1 /* $OpenBSD: root.c,v 1.49 2017/06/01 08:08:24 joris Exp $ */
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 <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
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
47 #define CVS_NBMETHODS (sizeof(cvs_methods)/sizeof(cvs_methods[0]))
48
49 /*
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:
55 * [:method:][[user[:pass]@]host[:port]:]path
56 * Returns a pointer to the allocated information on success, or NULL
57 * on failure.
58 */
59 static struct cvsroot *
cvsroot_parse(const char * str)60 cvsroot_parse(const char *str)
61 {
62 u_int i;
63 char *cp, *sp, *pp;
64 const char *errstr;
65 static struct cvsroot *root = NULL;
66
67 if (root != NULL)
68 return (root);
69
70 root = xcalloc(1, sizeof(*root));
71 root->cr_method = CVS_METHOD_NONE;
72 root->cr_str = xstrdup(str);
73 root->cr_buf = xstrdup(str);
74
75 sp = root->cr_buf;
76 cp = root->cr_buf;
77 if (*sp == ':') {
78 sp++;
79 if ((cp = strchr(sp, ':')) == NULL)
80 fatal("failed to parse CVSROOT: unterminated method");
81
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 }
89 }
90 if (i == CVS_NBMETHODS)
91 fatal("cvsroot_parse: unknown method `%s'", sp);
92 }
93
94 /* find the start of the actual path */
95 if ((sp = strchr(cp, '/')) == NULL)
96 fatal("no path specification in CVSROOT");
97
98 root->cr_dir = sp;
99 STRIP_SLASH(root->cr_dir);
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
107 if (*(sp - 1) != ':')
108 fatal("missing host/path delimiter in CVSROOT");
109
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;
128 } else
129 sp = cp;
130
131 pp = strchr(sp, ':');
132 if (pp != NULL) {
133 *(pp++) = '\0';
134 root->cr_port = strtonum(pp, 1, 65535, &errstr);
135 if (errstr != NULL)
136 fatal("port specification in CVSROOT is %s", errstr);
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);
151 }
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 */
163 struct cvsroot *
cvsroot_get(const char * dir)164 cvsroot_get(const char *dir)
165 {
166 char rootpath[PATH_MAX], *rootstr, line[128];
167 FILE *fp;
168
169 if (cvs_rootstr != NULL)
170 return cvsroot_parse(cvs_rootstr);
171
172 if (cvs_server_active == 1)
173 return cvsroot_parse(dir);
174
175 if (cvs_cmdop == CVS_OP_IMPORT) {
176 if ((rootstr = getenv("CVSROOT")) != NULL)
177 return (cvsroot_parse(rootstr));
178 return (NULL);
179 }
180
181 (void)xsnprintf(rootpath, PATH_MAX, "%s/%s", dir, CVS_PATH_ROOTSPEC);
182
183 if ((fp = fopen(rootpath, "r")) == NULL) {
184 if (errno == ENOENT) {
185 /* try env as a last resort */
186 if ((rootstr = getenv("CVSROOT")) != NULL)
187 return cvsroot_parse(rootstr);
188 else
189 return (NULL);
190 } else {
191 fatal("cvsroot_get: fopen: `%s': %s",
192 CVS_PATH_ROOTSPEC, strerror(errno));
193 }
194 }
195
196 if (fgets(line, (int)sizeof(line), fp) == NULL)
197 fatal("cvsroot_get: fgets: `%s'", CVS_PATH_ROOTSPEC);
198
199 (void)fclose(fp);
200
201 line[strcspn(line, "\n")] = '\0';
202 if (line[0] == '\0')
203 cvs_log(LP_ERR, "empty %s file", CVS_PATH_ROOTSPEC);
204
205 return cvsroot_parse(line);
206 }
207
208 int
cvsroot_is_local(void)209 cvsroot_is_local(void)
210 {
211 if (current_cvsroot == NULL)
212 fatal("cvsroot_is_local: no CVSROOT");
213
214 return (current_cvsroot->cr_method == CVS_METHOD_LOCAL);
215 }
216
217 int
cvsroot_is_remote(void)218 cvsroot_is_remote(void)
219 {
220 if (current_cvsroot == NULL)
221 fatal("cvsroot_is_remote: no CVSROOT");
222
223 return (current_cvsroot->cr_method != CVS_METHOD_LOCAL);
224 }
225