xref: /openbsd-src/gnu/usr.bin/cvs/src/root.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*
2  * Copyright (c) 1992, Mark D. Baushke
3  *
4  * You may distribute under the terms of the GNU General Public License as
5  * specified in the README file that comes with the CVS 1.4 kit.
6  *
7  * Name of Root
8  *
9  * Determine the path to the CVSROOT and set "Root" accordingly.
10  * If this looks like of modified clone of Name_Repository() in
11  * repos.c, it is...
12  */
13 
14 #include "cvs.h"
15 
16 /* Printable names for things in the CVSroot_method enum variable.
17    Watch out if the enum is changed in cvs.h! */
18 
19 char *method_names[] = {
20   "local", "server (rsh)", "pserver", "kserver", "ext"
21 };
22 
23 #ifndef DEBUG
24 
25 char *
26 Name_Root(dir, update_dir)
27      char *dir;
28      char *update_dir;
29 {
30     FILE *fpin;
31     char *ret, *xupdate_dir;
32     char root[PATH_MAX];
33     char tmp[PATH_MAX];
34     char cvsadm[PATH_MAX];
35     char *cp;
36 
37     if (update_dir && *update_dir)
38 	xupdate_dir = update_dir;
39     else
40 	xupdate_dir = ".";
41 
42     if (dir != NULL)
43     {
44 	(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
45 	(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
46     }
47     else
48     {
49 	(void) strcpy (cvsadm, CVSADM);
50 	(void) strcpy (tmp, CVSADM_ROOT);
51     }
52 
53     /*
54      * Do not bother looking for a readable file if there is no cvsadm
55      * directory present.
56      *
57      * It is possible that not all repositories will have a CVS/Root
58      * file. This is ok, but the user will need to specify -d
59      * /path/name or have the environment variable CVSROOT set in
60      * order to continue.  */
61     if ((!isdir (cvsadm)) || (!isreadable (tmp)))
62         return (NULL);
63 
64     /*
65      * The assumption here is that the CVS Root is always contained in the
66      * first line of the "Root" file.
67      */
68     fpin = open_file (tmp, "r");
69 
70     if (fgets (root, PATH_MAX, fpin) == NULL)
71     {
72 	error (0, 0, "in directory %s:", xupdate_dir);
73 	error (0, errno, "cannot read %s", CVSADM_ROOT);
74 	error (0, 0, "please correct this problem");
75 	return (NULL);
76     }
77     (void) fclose (fpin);
78     if ((cp = strrchr (root, '\n')) != NULL)
79 	*cp = '\0';			/* strip the newline */
80 
81     /*
82      * root now contains a candidate for CVSroot. It must be an
83      * absolute pathname
84      */
85 
86 #ifdef CLIENT_SUPPORT
87     /* It must specify a server via remote CVS or be an absolute pathname.  */
88     if ((strchr (root, ':') == NULL)
89     	&& ! isabsolute (root))
90 #else /* ! CLIENT_SUPPORT */
91     if (root[0] != '/')
92 #endif /* CLIENT_SUPPORT */
93     {
94 	error (0, 0, "in directory %s:", xupdate_dir);
95 	error (0, 0,
96 	       "ignoring %s because it does not contain an absolute pathname.",
97 	       CVSADM_ROOT);
98 	return (NULL);
99     }
100 
101 #ifdef CLIENT_SUPPORT
102     if ((strchr (root, ':') == NULL) && !isdir (root))
103 #else /* ! CLIENT_SUPPORT */
104     if (!isdir (root))
105 #endif /* CLIENT_SUPPORT */
106     {
107 	error (0, 0, "in directory %s:", xupdate_dir);
108 	error (0, 0,
109 	       "ignoring %s because it specifies a non-existent repository %s",
110 	       CVSADM_ROOT, root);
111 	return (NULL);
112     }
113 
114     /* allocate space to return and fill it in */
115     strip_path (root);
116     ret = xstrdup (root);
117     return (ret);
118 }
119 
120 /*
121  * Returns non-zero if the two directories have the same stat values
122  * which indicates that they are really the same directories.
123  */
124 int
125 same_directories (dir1, dir2)
126      char *dir1;
127      char *dir2;
128 {
129     struct stat sb1;
130     struct stat sb2;
131     int ret;
132 
133     if ( CVS_STAT (dir1, &sb1) < 0)
134         return (0);
135     if ( CVS_STAT (dir2, &sb2) < 0)
136         return (0);
137 
138     ret = 0;
139     if ( (memcmp( &sb1.st_dev, &sb2.st_dev, sizeof(dev_t) ) == 0) &&
140 	 (memcmp( &sb1.st_ino, &sb2.st_ino, sizeof(ino_t) ) == 0))
141         ret = 1;
142 
143     return (ret);
144 }
145 
146 
147 /*
148  * Write the CVS/Root file so that the environment variable CVSROOT
149  * and/or the -d option to cvs will be validated or not necessary for
150  * future work.
151  */
152 void
153 Create_Root (dir, rootdir)
154      char *dir;
155      char *rootdir;
156 {
157     FILE *fout;
158     char tmp[PATH_MAX];
159 
160     if (noexec)
161 	return;
162 
163     /* record the current cvs root */
164 
165     if (rootdir != NULL)
166     {
167         if (dir != NULL)
168 	    (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
169         else
170 	    (void) strcpy (tmp, CVSADM_ROOT);
171         fout = open_file (tmp, "w+");
172         if (fprintf (fout, "%s\n", rootdir) < 0)
173 	    error (1, errno, "write to %s failed", tmp);
174         if (fclose (fout) == EOF)
175 	    error (1, errno, "cannot close %s", tmp);
176     }
177 }
178 
179 #endif /* ! DEBUG */
180 
181 
182 /* Parse a CVSROOT variable into its constituent parts -- method,
183  * username, hostname, directory.  The prototypical CVSROOT variable
184  * looks like:
185  *
186  * :method:user@host:path
187  *
188  * Some methods may omit fields; local, for example, doesn't need user
189  * and host.
190  *
191  * Returns zero on success, non-zero on failure. */
192 
193 char *CVSroot_original = NULL;	/* the CVSroot that was passed in */
194 int client_active;		/* nonzero if we are doing remote access */
195 CVSmethod CVSroot_method;	/* one of the enum values defined in cvs.h */
196 char *CVSroot_username;		/* the username or NULL if method == local */
197 char *CVSroot_hostname;		/* the hostname or NULL if method == local */
198 char *CVSroot_directory;	/* the directory name */
199 
200 int
201 parse_cvsroot (CVSroot)
202     char *CVSroot;
203 {
204     static int cvsroot_parsed = 0;
205     char *cvsroot_copy, *p;
206 
207     /* Don't go through the trouble twice. */
208     if (cvsroot_parsed)
209     {
210 	error (0, 0, "WARNING (parse_cvsroot): someone called me twice!\n");
211 	return 0;
212     }
213 
214     CVSroot_original = xstrdup (CVSroot);
215     cvsroot_copy = xstrdup (CVSroot);
216 
217     if ((*cvsroot_copy == ':'))
218     {
219 	char *method = ++cvsroot_copy;
220 
221 	/* Access method specified, as in
222 	 * "cvs -d :pserver:user@host:/path",
223 	 * "cvs -d :local:e:\path", or
224 	 * "cvs -d :kserver:user@host:/path".
225 	 * We need to get past that part of CVSroot before parsing the
226 	 * rest of it.
227 	 */
228 
229 	if (! (p = strchr (method, ':')))
230 	{
231 	    error (0, 0, "bad CVSroot: %s", CVSroot);
232 	    return 1;
233 	}
234 	*p = '\0';
235 	cvsroot_copy = ++p;
236 
237 	/* Now we have an access method -- see if it's valid. */
238 
239 	if (strcmp (method, "local") == 0)
240 	    CVSroot_method = local_method;
241 	else if (strcmp (method, "pserver") == 0)
242 	    CVSroot_method = pserver_method;
243 	else if (strcmp (method, "kserver") == 0)
244 	    CVSroot_method = kserver_method;
245 	else if (strcmp (method, "server") == 0)
246 	    CVSroot_method = server_method;
247 	else if (strcmp (method, "ext") == 0)
248 	    CVSroot_method = ext_method;
249 	else
250 	{
251 	    error (0, 0, "unknown method in CVSroot: %s", CVSroot);
252 	    return 1;
253 	}
254     }
255     else
256     {
257 	/* If the method isn't specified, assume
258 	   SERVER_METHOD/EXT_METHOD if the string contains a colon or
259 	   LOCAL_METHOD otherwise.  */
260 
261 	CVSroot_method = ((strchr (cvsroot_copy, ':'))
262 #ifdef RSH_NOT_TRANSPARENT
263 			  ? server_method
264 #else
265 			  ? ext_method
266 #endif
267 			  : local_method);
268     }
269 
270     client_active = (CVSroot_method != local_method);
271 
272     /* Check for username/hostname if we're not LOCAL_METHOD. */
273 
274     CVSroot_username = NULL;
275     CVSroot_hostname = NULL;
276 
277     if (CVSroot_method != local_method)
278     {
279 	/* Check to see if there is a username in the string. */
280 
281 	if ((p = strchr (cvsroot_copy, '@')))
282 	{
283 	    CVSroot_username = cvsroot_copy;
284 	    *p = '\0';
285 	    cvsroot_copy = ++p;
286 	    if (*CVSroot_username == '\0')
287 		CVSroot_username = NULL;
288 	}
289 
290 	if ((p = strchr (cvsroot_copy, ':')))
291 	{
292 	    CVSroot_hostname = cvsroot_copy;
293 	    *p = '\0';
294 	    cvsroot_copy = ++p;
295 
296 	    if (*CVSroot_hostname == '\0')
297 		CVSroot_hostname = NULL;
298 	}
299     }
300 
301     CVSroot_directory = cvsroot_copy;
302 
303 #if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG)
304     if (CVSroot_method != local_method)
305     {
306 	error (0, 0, "Your CVSROOT is set for a remote access method");
307 	error (0, 0, "but your CVS executable doesn't support it");
308 	error (0, 0, "(%s)", CVSroot);
309 	return 1;
310     }
311 #endif
312 
313     /* Do various sanity checks. */
314 
315     if (CVSroot_username && ! CVSroot_hostname)
316     {
317 	error (0, 0, "missing hostname in CVSROOT: %s", CVSroot);
318 	return 1;
319     }
320 
321     switch (CVSroot_method)
322     {
323     case local_method:
324 	if (CVSroot_username || CVSroot_hostname)
325 	{
326 	    error (0, 0, "can't specify hostname and username in CVSROOT");
327 	    error (0, 0, "when using local access method");
328 	    error (0, 0, "(%s)", CVSroot);
329 	    return 1;
330 	}
331 	break;
332     case kserver_method:
333 #ifndef HAVE_KERBEROS
334 	error (0, 0, "Your CVSROOT is set for a kerberos access method");
335 	error (0, 0, "but your CVS executable doesn't support it");
336 	error (0, 0, "(%s)", CVSroot);
337 	return 1;
338 #endif
339     case server_method:
340     case ext_method:
341     case pserver_method:
342 	if (! CVSroot_hostname)
343 	{
344 	    error (0, 0, "didn't specify hostname in CVSROOT: %s", CVSroot);
345 	    return 1;
346 	}
347 	break;
348     }
349 
350     if (*CVSroot_directory == '\0')
351     {
352 	error (0, 0, "missing directory in CVSROOT: %s", CVSroot);
353 	return 1;
354     }
355 
356     /* Hooray!  We finally parsed it! */
357     return 0;
358 }
359 
360 
361 /* Set up the global CVSroot* variables as if we're using the local
362    repository DIR. */
363 
364 void
365 set_local_cvsroot (dir)
366     char *dir;
367 {
368     CVSroot_original = xstrdup (dir);
369     CVSroot_method = local_method;
370     CVSroot_directory = CVSroot_original;
371     CVSroot_username = NULL;
372     CVSroot_hostname = NULL;
373     client_active = 0;
374 }
375 
376 
377 #ifdef DEBUG
378 /* This is for testing the parsing function. */
379 
380 #include <stdio.h>
381 
382 char *CVSroot;
383 char *program_name = "testing";
384 char *command_name = "parse_cvsroot";		/* XXX is this used??? */
385 
386 void
387 main (argc, argv)
388     int argc;
389     char *argv[];
390 {
391     program_name = argv[0];
392 
393     if (argc != 2)
394     {
395 	fprintf (stderr, "Usage: %s <CVSROOT>\n", program_name);
396 	exit (2);
397     }
398 
399     if (parse_cvsroot (argv[1]))
400     {
401 	fprintf (stderr, "%s: Parsing failed.", program_name);
402 	exit (1);
403     }
404     printf ("CVSroot: %s\n", argv[1]);
405     printf ("CVSroot_method: %s\n", method_names[CVSroot_method]);
406     printf ("CVSroot_username: %s\n",
407 	    CVSroot_username ? CVSroot_username : "NULL");
408     printf ("CVSroot_hostname: %s\n",
409 	    CVSroot_hostname ? CVSroot_hostname : "NULL");
410     printf ("CVSroot_directory: %s\n", CVSroot_directory);
411 
412    exit (0);
413    /* NOTREACHED */
414 }
415 #endif
416