Annotation of src/usr.bin/cvs/root.c, Revision 1.2
1.1 jfb 1: /* $OpenBSD$ */
2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
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
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/types.h>
28:
29: #include <stdlib.h>
30: #include <stdio.h>
31: #include <unistd.h>
32: #include <err.h>
33: #include <errno.h>
34: #include <string.h>
35: #include <paths.h>
36:
37: #include "cvs.h"
38: #include "log.h"
39:
40:
41: extern char *cvs_rootstr;
42:
43:
44: /* keep these ordered with the defines */
45: const char *cvs_methods[] = {
46: "",
47: "local",
48: "ssh",
49: "pserver",
50: "kserver",
51: "gserver",
52: "ext",
53: "fork",
54: };
55:
56: #define CVS_NBMETHODS (sizeof(cvs_methods)/sizeof(cvs_methods[0]))
57:
58:
59:
60: /*
61: * cvsroot_parse()
62: *
63: * Parse a CVS root string (as found in CVS/Root files or the CVSROOT
64: * environment variable) and store the fields in a dynamically
65: * allocated cvs_root structure. The format of the string is as follows:
66: * :method:path
67: * Returns a pointer to the allocated information on success, or NULL
68: * on failure.
69: */
70:
71: struct cvsroot*
72: cvsroot_parse(const char *str)
73: {
74: u_int i;
75: char *cp, *sp, *pp;
76: struct cvsroot *root;
77:
78: root = (struct cvsroot *)malloc(sizeof(*root));
79: if (root == NULL) {
80: cvs_log(LP_ERRNO, "failed to allocate CVS root data");
81: return (NULL);
82: }
83:
84: root->cr_method = CVS_METHOD_NONE;
85:
86: root->cr_buf = strdup(str);
87: if (root->cr_buf == NULL) {
88: cvs_log(LP_ERRNO, "failed to copy CVS root");
89: free(root);
90: return (NULL);
91: }
92:
93: sp = root->cr_buf;
94: cp = root->cr_buf;
95:
96: if (*sp == ':') {
97: sp++;
98: cp = strchr(sp, ':');
99: if (cp == NULL) {
100: cvs_log(LP_ERR, "failed to parse CVSROOT: "
101: "unterminated method");
102: free(root->cr_buf);
103: free(root);
104: return (NULL);
105: }
106: *(cp++) = '\0';
107:
108: for (i = 0; i < CVS_NBMETHODS; i++) {
109: if (strcmp(sp, cvs_methods[i]) == 0) {
110: root->cr_method = i;
111: break;
112: }
113: }
114: }
115:
116: /* find the start of the actual path */
117: sp = strchr(cp, '/');
118: if (sp == NULL) {
119: cvs_log(LP_ERR, "no path specification in CVSROOT");
120: free(root->cr_buf);
121: free(root);
122: return (NULL);
123: }
124:
125: root->cr_dir = sp;
126: if (sp == cp) {
127: if (root->cr_method == CVS_METHOD_NONE)
128: root->cr_method = CVS_METHOD_LOCAL;
129: /* stop here, it's just a path */
130: return (root);
131: }
132:
133: if (*(sp - 1) != ':') {
134: cvs_log(LP_ERR, "missing host/path delimiter in CVS root");
135: free(root);
136: return (NULL);
137: }
138: *(sp - 1) = '\0';
139:
140: /*
141: * looks like we have more than just a directory path, so
142: * attempt to split it into user and host parts
143: */
144: sp = strchr(cp, '@');
145: if (sp != NULL) {
146: *(sp++) = '\0';
147:
148: /* password ? */
149: pp = strchr(cp, ':');
150: if (pp != NULL) {
151: *(pp++) = '\0';
152: root->cr_pass = pp;
153: }
154:
155: root->cr_user = cp;
156: }
157:
158: pp = strchr(sp, ':');
159: if (pp != NULL) {
160: *(pp++) = '\0';
161: root->cr_port = (u_int)strtol(pp, &cp, 10);
162: if (*cp != '\0' || root->cr_port > 65535) {
163: cvs_log(LP_ERR,
164: "invalid port specification in CVSROOT");
165: free(root);
166: return (NULL);
167: }
168:
169: }
170:
171: root->cr_host = sp;
172:
173: if (root->cr_method == CVS_METHOD_NONE) {
174: /* no method found from start of CVSROOT, guess */
175: if (root->cr_host != NULL)
176: root->cr_method = CVS_METHOD_SERVER;
177: else
178: root->cr_method = CVS_METHOD_LOCAL;
179: }
180:
181: return (root);
182: }
183:
184:
185: /*
186: * cvsroot_free()
187: *
188: * Free a CVSROOT structure previously allocated and returned by
189: * cvsroot_parse().
190: */
191:
192: void
193: cvsroot_free(struct cvsroot *root)
194: {
195: free(root->cr_buf);
196: free(root);
197: }
198:
199:
200: /*
201: * cvsroot_get()
202: *
203: * Get the CVSROOT information for a specific directory <dir>. The
204: * value is taken from one of 3 possible sources (in order of precedence):
205: *
206: * 1) the `-d' command-line option
207: * 2) the CVS/Root file found in checked-out trees
208: * 3) the CVSROOT environment variable
209: */
210:
211: struct cvsroot*
212: cvsroot_get(const char *dir)
213: {
214: size_t len;
215: char rootpath[MAXPATHLEN], *rootstr, *line;
216: FILE *fp;
217: struct cvsroot *rp;
218:
219: if (cvs_rootstr != NULL)
220: return cvsroot_parse(cvs_rootstr);
221:
222: snprintf(rootpath, sizeof(rootpath), "%s/" CVS_PATH_ROOTSPEC, dir);
223: fp = fopen(rootpath, "r");
224: if (fp == NULL) {
225: if (errno == ENOENT) {
226: /* try env as a last resort */
227: if ((rootstr = getenv("CVSROOT")) != NULL)
228: return cvsroot_parse(rootstr);
229: else
230: return (NULL);
231: }
232: else {
233: cvs_log(LP_ERRNO, "failed to open CVS/Root");
234: return (NULL);
235: }
236: }
237:
238: line = fgetln(fp, &len);
239: if (line == NULL) {
240: cvs_log(LP_ERR, "failed to read CVSROOT line from CVS/Root");
241: (void)fclose(fp);
242: }
243:
244: /* line is not NUL-terminated, but we don't need to allocate an
245: * extra byte because we don't want the trailing newline. It will
246: * get replaced by a \0.
247: */
248: rootstr = (char *)malloc(len);
249: if (rootstr == NULL) {
250: cvs_log(LP_ERRNO, "failed to allocate CVSROOT string");
251: (void)fclose(fp);
252: return (NULL);
253: }
1.2 ! vincent 254: memcpy(rootstr, line, len);
! 255: rootstr[len] = '\0';
1.1 jfb 256: rp = cvsroot_parse(rootstr);
257:
258: (void)fclose(fp);
259: free(rootstr);
260:
261: return (rp);
262: }