Annotation of src/usr.bin/cvs/root.c, Revision 1.46
1.46 ! joris 1: /* $OpenBSD: root.c,v 1.45 2008/06/20 23:00:13 tobias Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.13 tedu 4: * All rights reserved.
1.1 jfb 5: *
1.13 tedu 6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
1.1 jfb 9: *
1.13 tedu 10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
1.1 jfb 12: * 2. The name of the author may not be used to endorse or promote products
1.13 tedu 13: * derived from this software without specific prior written permission.
1.1 jfb 14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
1.13 tedu 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 25: */
26:
1.36 otto 27: #include <errno.h>
28: #include <stdlib.h>
29: #include <string.h>
1.1 jfb 30:
31: #include "cvs.h"
32:
33: extern char *cvs_rootstr;
34:
35: /* keep these ordered with the defines */
36: const char *cvs_methods[] = {
37: "",
38: "local",
39: "ssh",
40: "pserver",
41: "kserver",
42: "gserver",
43: "ext",
44: "fork",
45: };
46:
1.20 xsa 47: #define CVS_NBMETHODS (sizeof(cvs_methods)/sizeof(cvs_methods[0]))
1.6 jfb 48:
49: /*
1.1 jfb 50: * cvsroot_parse()
51: *
52: * Parse a CVS root string (as found in CVS/Root files or the CVSROOT
53: * environment variable) and store the fields in a dynamically
54: * allocated cvs_root structure. The format of the string is as follows:
1.39 xsa 55: * [:method:][[user[:pass]@]host[:port]:]path
1.1 jfb 56: * Returns a pointer to the allocated information on success, or NULL
57: * on failure.
58: */
1.40 joris 59: static struct cvsroot *
1.1 jfb 60: cvsroot_parse(const char *str)
61: {
62: u_int i;
63: char *cp, *sp, *pp;
1.37 xsa 64: const char *errstr;
1.40 joris 65: static struct cvsroot *root = NULL;
1.1 jfb 66:
1.40 joris 67: if (root != NULL)
68: return (root);
1.6 jfb 69:
1.31 ray 70: root = xcalloc(1, sizeof(*root));
1.1 jfb 71: root->cr_method = CVS_METHOD_NONE;
1.26 joris 72: root->cr_str = xstrdup(str);
73: root->cr_buf = xstrdup(str);
1.1 jfb 74:
75: sp = root->cr_buf;
76: cp = root->cr_buf;
77: if (*sp == ':') {
78: sp++;
1.27 xsa 79: if ((cp = strchr(sp, ':')) == NULL)
80: fatal("failed to parse CVSROOT: unterminated method");
81:
1.1 jfb 82: *(cp++) = '\0';
83:
84: for (i = 0; i < CVS_NBMETHODS; i++) {
85: if (strcmp(sp, cvs_methods[i]) == 0) {
86: root->cr_method = i;
87: break;
88: }
1.14 jfb 89: }
1.27 xsa 90: if (i == CVS_NBMETHODS)
91: fatal("cvsroot_parse: unknown method `%s'", sp);
1.1 jfb 92: }
93:
94: /* find the start of the actual path */
1.27 xsa 95: if ((sp = strchr(cp, '/')) == NULL)
96: fatal("no path specification in CVSROOT");
1.1 jfb 97:
98: root->cr_dir = sp;
1.32 joris 99: STRIP_SLASH(root->cr_dir);
1.1 jfb 100: if (sp == cp) {
101: if (root->cr_method == CVS_METHOD_NONE)
102: root->cr_method = CVS_METHOD_LOCAL;
103: /* stop here, it's just a path */
104: return (root);
105: }
106:
1.27 xsa 107: if (*(sp - 1) != ':')
108: fatal("missing host/path delimiter in CVSROOT");
109:
1.1 jfb 110: *(sp - 1) = '\0';
111:
112: /*
113: * looks like we have more than just a directory path, so
114: * attempt to split it into user and host parts
115: */
116: sp = strchr(cp, '@');
117: if (sp != NULL) {
118: *(sp++) = '\0';
119:
120: /* password ? */
121: pp = strchr(cp, ':');
122: if (pp != NULL) {
123: *(pp++) = '\0';
124: root->cr_pass = pp;
125: }
126:
127: root->cr_user = cp;
1.12 deraadt 128: } else
1.11 jfb 129: sp = cp;
1.1 jfb 130:
131: pp = strchr(sp, ':');
132: if (pp != NULL) {
133: *(pp++) = '\0';
1.43 joris 134: root->cr_port = strtonum(pp, 1, 65535, &errstr);
1.37 xsa 135: if (errstr != NULL)
136: fatal("port specification in CVSROOT is %s", errstr);
1.1 jfb 137:
138: }
139:
140: root->cr_host = sp;
141:
142: if (root->cr_method == CVS_METHOD_NONE) {
143: /* no method found from start of CVSROOT, guess */
144: if (root->cr_host != NULL)
145: root->cr_method = CVS_METHOD_SERVER;
146: else
147: root->cr_method = CVS_METHOD_LOCAL;
148: }
149:
150: return (root);
1.25 joris 151: }
1.1 jfb 152:
153: /*
154: * cvsroot_get()
155: *
156: * Get the CVSROOT information for a specific directory <dir>. The
157: * value is taken from one of 3 possible sources (in order of precedence):
158: *
159: * 1) the `-d' command-line option
160: * 2) the CVS/Root file found in checked-out trees
161: * 3) the CVSROOT environment variable
162: */
1.21 xsa 163: struct cvsroot *
1.1 jfb 164: cvsroot_get(const char *dir)
165: {
1.5 jfb 166: char rootpath[MAXPATHLEN], *rootstr, line[128];
1.1 jfb 167: FILE *fp;
168:
169: if (cvs_rootstr != NULL)
170: return cvsroot_parse(cvs_rootstr);
1.41 tobias 171:
172: if (cvs_server_active == 1)
173: return cvsroot_parse(dir);
1.45 tobias 174:
175: if (cvs_cmdop == CVS_OP_IMPORT)
176: return NULL;
1.1 jfb 177:
1.35 xsa 178: (void)xsnprintf(rootpath, MAXPATHLEN, "%s/%s", dir, CVS_PATH_ROOTSPEC);
1.16 xsa 179:
1.27 xsa 180: if ((fp = fopen(rootpath, "r")) == NULL) {
1.1 jfb 181: if (errno == ENOENT) {
182: /* try env as a last resort */
183: if ((rootstr = getenv("CVSROOT")) != NULL)
184: return cvsroot_parse(rootstr);
185: else
1.32 joris 186: return (NULL);
1.12 deraadt 187: } else {
1.27 xsa 188: fatal("cvsroot_get: fopen: `%s': %s",
189: CVS_PATH_ROOTSPEC, strerror(errno));
1.1 jfb 190: }
191: }
192:
1.27 xsa 193: if (fgets(line, (int)sizeof(line), fp) == NULL)
194: fatal("cvsroot_get: fgets: `%s'", CVS_PATH_ROOTSPEC);
195:
1.5 jfb 196: (void)fclose(fp);
1.1 jfb 197:
1.44 gilles 198: line[strcspn(line, "\n")] = '\0';
199: if (line[0] == '\0')
1.32 joris 200: cvs_log(LP_ERR, "empty %s file", CVS_PATH_ROOTSPEC);
1.1 jfb 201:
1.5 jfb 202: return cvsroot_parse(line);
1.1 jfb 203: }