xref: /openbsd-src/gnu/usr.bin/cvs/src/checkout.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  *
5  * You may distribute under the terms of the GNU General Public License as
6  * specified in the README file that comes with the CVS source distribution.
7  *
8  * Create Version
9  *
10  * "checkout" creates a "version" of an RCS repository.  This version is owned
11  * totally by the user and is actually an independent copy, to be dealt with
12  * as seen fit.  Once "checkout" has been called in a given directory, it
13  * never needs to be called again.  The user can keep up-to-date by calling
14  * "update" when he feels like it; this will supply him with a merge of his
15  * own modifications and the changes made in the RCS original.  See "update"
16  * for details.
17  *
18  * "checkout" can be given a list of directories or files to be updated and in
19  * the case of a directory, will recursivley create any sub-directories that
20  * exist in the repository.
21  *
22  * When the user is satisfied with his own modifications, the present version
23  * can be committed by "commit"; this keeps the present version in tact,
24  * usually.
25  *
26  * The call is cvs checkout [options] <module-name>...
27  *
28  * "checkout" creates a directory ./CVS, in which it keeps its administration,
29  * in two files, Repository and Entries. The first contains the name of the
30  * repository.  The second contains one line for each registered file,
31  * consisting of the version number it derives from, its time stamp at
32  * derivation time and its name.  Both files are normal files and can be
33  * edited by the user, if necessary (when the repository is moved, e.g.)
34  */
35 
36 #include <assert.h>
37 #include "cvs.h"
38 
39 static char *findslash PROTO((char *start, char *p));
40 static int checkout_proc PROTO((int argc, char **argv, char *where,
41 		          char *mwhere, char *mfile, int shorten,
42 		          int local_specified, char *omodule,
43 		          char *msg));
44 
45 static const char *const checkout_usage[] =
46 {
47     "Usage:\n  %s %s [-ANPRcflnps] [-r rev | -D date] [-d dir]\n",
48     "    [-j rev1] [-j rev2] [-k kopt] modules...\n",
49     "\t-A\tReset any sticky tags/date/kopts.\n",
50     "\t-N\tDon't shorten module paths if -d specified.\n",
51     "\t-P\tPrune empty directories.\n",
52     "\t-R\tProcess directories recursively.\n",
53     "\t-c\t\"cat\" the module database.\n",
54     "\t-f\tForce a head revision match if tag/date not found.\n",
55     "\t-l\tLocal directory only, not recursive\n",
56     "\t-n\tDo not run module program (if any).\n",
57     "\t-p\tCheck out files to standard output (avoids stickiness).\n",
58     "\t-s\tLike -c, but include module status.\n",
59     "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n",
60     "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n",
61     "\t-d dir\tCheck out into dir instead of module name.\n",
62     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
63     "\t-j rev\tMerge in changes made between current revision and rev.\n",
64     "(Specify the --help global option for a list of other help options)\n",
65     NULL
66 };
67 
68 static const char *const export_usage[] =
69 {
70     "Usage: %s %s [-NRfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n",
71     "\t-N\tDon't shorten module paths if -d specified.\n",
72     "\t-f\tForce a head revision match if tag/date not found.\n",
73     "\t-l\tLocal directory only, not recursive\n",
74     "\t-R\tProcess directories recursively (default).\n",
75     "\t-n\tDo not run module program (if any).\n",
76     "\t-r rev\tExport revision or tag.\n",
77     "\t-D date\tExport revisions as of date.\n",
78     "\t-d dir\tExport into dir instead of module name.\n",
79     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
80     "(Specify the --help global option for a list of other help options)\n",
81     NULL
82 };
83 
84 static int checkout_prune_dirs;
85 static int force_tag_match = 1;
86 static int pipeout;
87 static int aflag;
88 static char *options = NULL;
89 static char *tag = NULL;
90 static int tag_validated = 0;
91 static char *date = NULL;
92 static char *join_rev1 = NULL;
93 static char *join_rev2 = NULL;
94 static int join_tags_validated = 0;
95 static char *preload_update_dir = NULL;
96 static char *history_name = NULL;
97 static enum mtype m_type;
98 
99 int
100 checkout (argc, argv)
101     int argc;
102     char **argv;
103 {
104     int i;
105     int c;
106     DBM *db;
107     int cat = 0, err = 0, status = 0;
108     int run_module_prog = 1;
109     int local = 0;
110     int shorten = -1;
111     char *where = NULL;
112     char *valid_options;
113     const char *const *valid_usage;
114 
115     /*
116      * A smaller subset of options are allowed for the export command, which
117      * is essentially like checkout, except that it hard-codes certain
118      * options to be default (like -kv) and takes care to remove the CVS
119      * directory when it has done its duty
120      */
121     if (strcmp (command_name, "export") == 0)
122     {
123         m_type = EXPORT;
124 	valid_options = "+Nnk:d:flRQqr:D:";
125 	valid_usage = export_usage;
126     }
127     else
128     {
129         m_type = CHECKOUT;
130 	valid_options = "+ANnk:d:flRpQqcsr:D:j:P";
131 	valid_usage = checkout_usage;
132     }
133 
134     if (argc == -1)
135 	usage (valid_usage);
136 
137     ign_setup ();
138     wrap_setup ();
139 
140     optind = 0;
141     while ((c = getopt (argc, argv, valid_options)) != -1)
142     {
143 	switch (c)
144 	{
145 	    case 'A':
146 		aflag = 1;
147 		break;
148 	    case 'N':
149 		shorten = 0;
150 		break;
151 	    case 'k':
152 		if (options)
153 		    free (options);
154 		options = RCS_check_kflag (optarg);
155 		break;
156 	    case 'n':
157 		run_module_prog = 0;
158 		break;
159 	    case 'Q':
160 	    case 'q':
161 #ifdef SERVER_SUPPORT
162 		/* The CVS 1.5 client sends these options (in addition to
163 		   Global_option requests), so we must ignore them.  */
164 		if (!server_active)
165 #endif
166 		    error (1, 0,
167 			   "-q or -Q must be specified before \"%s\"",
168 			   command_name);
169 		break;
170 	    case 'l':
171 		local = 1;
172 		break;
173 	    case 'R':
174 		local = 0;
175 		break;
176 	    case 'P':
177 		checkout_prune_dirs = 1;
178 		break;
179 	    case 'p':
180 		pipeout = 1;
181 		run_module_prog = 0;	/* don't run module prog when piping */
182 		noexec = 1;		/* so no locks will be created */
183 		break;
184 	    case 'c':
185 		cat = 1;
186 		break;
187 	    case 'd':
188 		where = optarg;
189 		if (shorten == -1)
190 		    shorten = 1;
191 		break;
192 	    case 's':
193 		status = 1;
194 		break;
195 	    case 'f':
196 		force_tag_match = 0;
197 		break;
198 	    case 'r':
199 		tag = optarg;
200 		checkout_prune_dirs = 1;
201 		break;
202 	    case 'D':
203 		date = Make_Date (optarg);
204 		checkout_prune_dirs = 1;
205 		break;
206 	    case 'j':
207 		if (join_rev2)
208 		    error (1, 0, "only two -j options can be specified");
209 		if (join_rev1)
210 		    join_rev2 = optarg;
211 		else
212 		    join_rev1 = optarg;
213 		break;
214 	    case '?':
215 	    default:
216 		usage (valid_usage);
217 		break;
218 	}
219     }
220     argc -= optind;
221     argv += optind;
222 
223     if (shorten == -1)
224 	shorten = 0;
225 
226     if ((cat || status) && argc != 0)
227 	error (1, 0, "-c and -s must not get any arguments");
228 
229     if (!(cat || status) && argc == 0)
230 	error (1, 0, "must specify at least one module or directory");
231 
232     if (where && pipeout)
233 	error (1, 0, "-d and -p are mutually exclusive");
234 
235     if (m_type == EXPORT)
236     {
237 	if (!tag && !date)
238 	    error (1, 0, "must specify a tag or date");
239 
240 	if (tag && isdigit ((unsigned char) tag[0]))
241 	    error (1, 0, "tag `%s' must be a symbolic tag", tag);
242     }
243 
244 #ifdef SERVER_SUPPORT
245     if (server_active && where != NULL)
246     {
247 	server_pathname_check (where);
248     }
249 #endif
250 
251     if (!safe_location()) {
252         error(1, 0, "Cannot check out files into the repository itself");
253     }
254 
255 #ifdef CLIENT_SUPPORT
256     if (client_active)
257     {
258 	int expand_modules;
259 
260 	start_server ();
261 
262 	ign_setup ();
263 
264 	/* We have to expand names here because the "expand-modules"
265            directive to the server has the side-effect of having the
266            server send the check-in and update programs for the
267            various modules/dirs requested.  If we turn this off and
268            simply request the names of the modules and directories (as
269            below in !expand_modules), those files (CVS/Checkin.prog
270            or CVS/Update.prog) don't get created.  Grrr.  */
271 
272 	expand_modules = (!cat && !status && !pipeout
273 			  && supported_request ("expand-modules"));
274 
275 	if (expand_modules)
276 	{
277 	    /* This is done here because we need to read responses
278                from the server before we send the command checkout or
279                export files. */
280 
281 	    client_expand_modules (argc, argv, local);
282 	}
283 
284 	if (!run_module_prog)
285 	    send_arg ("-n");
286 	if (local)
287 	    send_arg ("-l");
288 	if (pipeout)
289 	    send_arg ("-p");
290 	if (!force_tag_match)
291 	    send_arg ("-f");
292 	if (aflag)
293 	    send_arg("-A");
294 	if (!shorten)
295 	    send_arg("-N");
296 	if (checkout_prune_dirs && m_type == CHECKOUT)
297 	    send_arg("-P");
298 	client_prune_dirs = checkout_prune_dirs;
299 	if (cat)
300 	    send_arg("-c");
301 	if (where != NULL)
302 	    option_with_arg ("-d", where);
303 	if (status)
304 	    send_arg("-s");
305 	if (options != NULL && options[0] != '\0')
306 	    send_arg (options);
307 	option_with_arg ("-r", tag);
308 	if (date)
309 	    client_senddate (date);
310 	if (join_rev1 != NULL)
311 	    option_with_arg ("-j", join_rev1);
312 	if (join_rev2 != NULL)
313 	    option_with_arg ("-j", join_rev2);
314 
315 	if (expand_modules)
316 	{
317 	    client_send_expansions (local, where, 1);
318 	}
319 	else
320 	{
321 	    int i;
322 	    for (i = 0; i < argc; ++i)
323 		send_arg (argv[i]);
324 	    client_nonexpanded_setup ();
325 	}
326 
327 	send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0);
328 	return get_responses_and_close ();
329     }
330 #endif /* CLIENT_SUPPORT */
331 
332     if (cat || status)
333     {
334 	cat_module (status);
335 	if (options)
336 	    free (options);
337 	return (0);
338     }
339     db = open_module ();
340 
341 
342     /* If we've specified something like "cvs co foo/bar baz/quux"
343        don't try to shorten names.  There are a few cases in which we
344        could shorten (e.g. "cvs co foo/bar foo/baz"), but we don't
345        handle those yet.  Better to have an extra directory created
346        than the thing checked out under the wrong directory name. */
347 
348     if (argc > 1)
349 	shorten = 0;
350 
351 
352     /* If we will be calling history_write, work out the name to pass
353        it.  */
354     if (m_type == CHECKOUT && !pipeout)
355     {
356 	if (tag && date)
357 	{
358 	    history_name = xmalloc (strlen (tag) + strlen (date) + 2);
359 	    sprintf (history_name, "%s:%s", tag, date);
360 	}
361 	else if (tag)
362 	    history_name = tag;
363 	else
364 	    history_name = date;
365     }
366 
367 
368     for (i = 0; i < argc; i++)
369 	err += do_module (db, argv[i], m_type, "Updating", checkout_proc,
370 			  where, shorten, local, run_module_prog,
371 			  (char *) NULL);
372     close_module (db);
373     if (options)
374 	free (options);
375     return (err);
376 }
377 
378 /* FIXME: This is and emptydir_name are in checkout.c for historical
379    reasons, probably want to move them.  */
380 
381 int
382 safe_location ()
383 {
384     char *current;
385     char hardpath[PATH_MAX+5];
386     size_t hardpath_len;
387     int  x;
388     int retval;
389 
390 #ifdef HAVE_READLINK
391     /* FIXME-arbitrary limit: should be retrying this like xgetwd.
392        But how does readlink let us know that the buffer was too small?
393        (by returning sizeof hardpath - 1?).  */
394     x = readlink(CVSroot_directory, hardpath, sizeof hardpath - 1);
395 #else
396     x = -1;
397 #endif
398     if (x == -1)
399     {
400         strcpy(hardpath, CVSroot_directory);
401     }
402     else
403     {
404         hardpath[x] = '\0';
405     }
406     current = xgetwd ();
407     if (current == NULL)
408 	error (1, errno, "could not get working directory");
409     hardpath_len = strlen (hardpath);
410     if (strlen (current) >= hardpath_len
411 	&& strncmp (current, hardpath, hardpath_len) == 0)
412     {
413 	if (/* Current is a subdirectory of hardpath.  */
414 	    current[hardpath_len] == '/'
415 
416 	    /* Current is hardpath itself.  */
417 	    || current[hardpath_len] == '\0')
418 	    retval = 0;
419 	else
420 	    /* It isn't a problem.  For example, current is
421 	       "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot".  */
422 	    retval = 1;
423     }
424     else
425 	retval = 1;
426     free (current);
427     return retval;
428 }
429 
430 struct dir_to_build
431 {
432     /* What to put in CVS/Repository.  */
433     char *repository;
434     /* The path to the directory.  */
435     char *dirpath;
436 
437     /* If set, don't build the directory, just change to it.
438        The caller will also want to set REPOSITORY to NULL.  */
439     int just_chdir;
440 
441     struct dir_to_build *next;
442 };
443 
444 static int build_dirs_and_chdir PROTO ((struct dir_to_build *list,
445 					int sticky));
446 
447 static void build_one_dir PROTO ((char *, char *, int));
448 
449 static void
450 build_one_dir (repository, dirpath, sticky)
451     char *repository;
452     char *dirpath;
453     int sticky;
454 {
455     FILE *fp;
456 
457     if (isfile (CVSADM))
458     {
459 	if (m_type == EXPORT)
460 	    error (1, 0, "cannot export into a working directory");
461     }
462     else if (m_type == CHECKOUT)
463     {
464 	/* I suspect that this check could be omitted.  */
465 	if (!isdir (repository))
466 	    error (1, 0, "there is no repository %s", repository);
467 
468 	if (Create_Admin (".", dirpath, repository,
469 			  sticky ? (char *) NULL : tag,
470 			  sticky ? (char *) NULL : date,
471 
472 			  /* FIXME?  This is a guess.  If it is important
473 			     for nonbranch to be set correctly here I
474 			     think we need to write it one way now and
475 			     then rewrite it later via WriteTag, once
476 			     we've had a chance to call RCS_nodeisbranch
477 			     on each file.  */
478 			  0, 1, 1))
479 	    return;
480 
481 	if (!noexec)
482 	{
483 	    fp = open_file (CVSADM_ENTSTAT, "w+");
484 	    if (fclose (fp) == EOF)
485 		error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
486 #ifdef SERVER_SUPPORT
487 	    if (server_active)
488 		server_set_entstat (dirpath, repository);
489 #endif
490 	}
491     }
492 }
493 
494 /*
495  * process_module calls us back here so we do the actual checkout stuff
496  */
497 /* ARGSUSED */
498 static int
499 checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten,
500 	       local_specified, omodule, msg)
501     int argc;
502     char **argv;
503     char *where_orig;
504     char *mwhere;
505     char *mfile;
506     int shorten;
507     int local_specified;
508     char *omodule;
509     char *msg;
510 {
511     char *myargv[2];
512     int err = 0;
513     int which;
514     char *cp;
515     char *repository;
516     char *oldupdate = NULL;
517     char *where;
518 
519     /*
520      * OK, so we're doing the checkout! Our args are as follows:
521      *  argc,argv contain either dir or dir followed by a list of files
522      *  where contains where to put it (if supplied by checkout)
523      *  mwhere contains the module name or -d from module file
524      *  mfile says do only that part of the module
525      *  shorten = 1 says shorten as much as possible
526      *  omodule is the original arg to do_module()
527      */
528 
529     /* Set up the repository (maybe) for the bottom directory.
530        Allocate more space than we need so we don't need to keep
531        reallocating this string. */
532     repository = xmalloc (strlen (CVSroot_directory)
533 			  + strlen (argv[0])
534 			  + (mfile == NULL ? 0 : strlen (mfile))
535 			  + 10);
536     (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
537     Sanitize_Repository_Name (repository);
538 
539 
540     /* save the original value of preload_update_dir */
541     if (preload_update_dir != NULL)
542 	oldupdate = xstrdup (preload_update_dir);
543 
544 
545     /* Allocate space and set up the where variable.  We allocate more
546        space than necessary here so that we don't have to keep
547        reallocaing it later on. */
548 
549     where = xmalloc (strlen (argv[0])
550 		     + (mfile == NULL ? 0 : strlen (mfile))
551 		     + (mwhere == NULL ? 0 : strlen (mwhere))
552 		     + (where_orig == NULL ? 0 : strlen (where_orig))
553 		     + 10);
554 
555     /* Yes, this could be written in a less verbose way, but in this
556        form it is quite easy to read.
557 
558        FIXME?  The following code that sets should probably be moved
559        to do_module in modules.c, since there is similar code in
560        patch.c and rtag.c. */
561 
562     if (shorten)
563     {
564 	if (where_orig != NULL)
565 	{
566 	    /* If the user has specified a directory with `-d' on the
567 	       command line, use it preferentially, even over the `-d'
568 	       flag in the modules file. */
569 
570 	    (void) strcpy (where, where_orig);
571 	}
572 	else if (mwhere != NULL)
573 	{
574 	    /* Second preference is the value of mwhere, which is from
575 	       the `-d' flag in the modules file. */
576 
577 	    (void) strcpy (where, mwhere);
578 	}
579 	else
580 	{
581 	    /* Third preference is the directory specified in argv[0]
582 	       which is this module'e directory in the repository. */
583 
584 	    (void) strcpy (where, argv[0]);
585 	}
586     }
587     else
588     {
589 	/* Use the same preferences here, bug don't shorten -- that
590            is, tack on where_orig if it exists. */
591 
592 	*where = '\0';
593 
594 	if (where_orig != NULL)
595 	{
596 	    (void) strcat (where, where_orig);
597 	    (void) strcat (where, "/");
598 	}
599 
600 	/* If the -d flag in the modules file specified an absolute
601            directory, let the user override it with the command-line
602            -d option. */
603 
604 	if ((mwhere != NULL) && (! isabsolute (mwhere)))
605 	    (void) strcat (where, mwhere);
606 	else
607 	    (void) strcat (where, argv[0]);
608     }
609     strip_trailing_slashes (where); /* necessary? */
610 
611 
612     /* At this point, the user may have asked for a single file or
613        directory from within a module.  In that case, we should modify
614        where, repository, and argv as appropriate. */
615 
616     if (mfile != NULL)
617     {
618 	/* The mfile variable can have one or more path elements.  If
619 	   it has multiple elements, we want to tack those onto both
620 	   repository and where.  The last element may refer to either
621 	   a file or directory.  Here's what to do:
622 
623 	   it refers to a directory
624 	     -> simply tack it on to where and repository
625 	   it refers to a file
626 	     -> munge argv to contain `basename mfile` */
627 
628 	char *cp;
629 	char *path;
630 
631 
632 	/* Paranoia check. */
633 
634 	if (mfile[strlen (mfile) - 1] == '/')
635 	{
636 	    error (0, 0, "checkout_proc: trailing slash on mfile (%s)!",
637 		   mfile);
638 	}
639 
640 
641 	/* Does mfile have multiple path elements? */
642 
643 	cp = strrchr (mfile, '/');
644 	if (cp != NULL)
645 	{
646 	    *cp = '\0';
647 	    (void) strcat (repository, "/");
648 	    (void) strcat (repository, mfile);
649 	    (void) strcat (where, "/");
650 	    (void) strcat (where, mfile);
651 	    mfile = cp + 1;
652 	}
653 
654 
655 	/* Now mfile is a single path element. */
656 
657 	path = xmalloc (strlen (repository) + strlen (mfile) + 5);
658 	(void) sprintf (path, "%s/%s", repository, mfile);
659 	if (isdir (path))
660 	{
661 	    /* It's a directory, so tack it on to repository and
662                where, as we did above. */
663 
664 	    (void) strcat (repository, "/");
665 	    (void) strcat (repository, mfile);
666 	    (void) strcat (where, "/");
667 	    (void) strcat (where, mfile);
668 	}
669 	else
670 	{
671 	    /* It's a file, which means we have to screw around with
672                argv. */
673 	    myargv[0] = argv[0];
674 	    myargv[1] = mfile;
675 	    argc = 2;
676 	    argv = myargv;
677 	}
678 	free (path);
679     }
680 
681     if (preload_update_dir != NULL)
682     {
683 	preload_update_dir =
684 	    xrealloc (preload_update_dir,
685 		      strlen (preload_update_dir) + strlen (where) + 5);
686 	strcat (preload_update_dir, "/");
687 	strcat (preload_update_dir, where);
688     }
689     else
690 	preload_update_dir = xstrdup (where);
691 
692     /*
693      * At this point, where is the directory we want to build, repository is
694      * the repository for the lowest level of the path.
695      *
696      * We need to tell build_dirs not only the path we want it to
697      * build, but also the repositories we want it to populate the
698      * path with.  To accomplish this, we walk the path backwards, one
699      * pathname component at a time, constucting a linked list of
700      * struct dir_to_build.
701      */
702 
703     /*
704      * If we are sending everything to stdout, we can skip a whole bunch of
705      * work from here
706      */
707     if (!pipeout)
708     {
709 	struct dir_to_build *head;
710 	char *reposcopy;
711 
712 	if (strncmp (repository, CVSroot_directory,
713 		     strlen (CVSroot_directory)) != 0)
714 	    error (1, 0, "\
715 internal error: %s doesn't start with %s in checkout_proc",
716 		   repository, CVSroot_directory);
717 
718 	/* We always create at least one directory, which corresponds to
719 	   the entire strings for WHERE and REPOSITORY.  */
720 	head = (struct dir_to_build *) xmalloc (sizeof (struct dir_to_build));
721 	/* Special marker to indicate that we don't want build_dirs_and_chdir
722 	   to create the CVSADM directory for us.  */
723 	head->repository = NULL;
724 	head->dirpath = xstrdup (where);
725 	head->next = NULL;
726 	head->just_chdir = 0;
727 
728 
729 	/* Make a copy of the repository name to play with. */
730 	reposcopy = xstrdup (repository);
731 
732 	/* FIXME: this should be written in terms of last_component
733 	   instead of hardcoding '/'.  This presumably affects OS/2,
734 	   NT, &c, if the user specifies '\'.  Likewise for the call
735 	   to findslash.  */
736 	cp = where + strlen (where);
737 	while (cp > where)
738 	{
739 	    struct dir_to_build *new;
740 
741 	    cp = findslash (where, cp - 1);
742 	    if (cp == NULL)
743 		break;		/* we're done */
744 
745 	    new = (struct dir_to_build *)
746 		xmalloc (sizeof (struct dir_to_build));
747 	    new->dirpath = xmalloc (strlen (where));
748 
749 	    /* If the user specified an absolute path for where, the
750                last path element we create should be the top-level
751                directory. */
752 
753 	    if (cp > where)
754 	    {
755 		strncpy (new->dirpath, where, cp - where);
756 		new->dirpath[cp - where] = '\0';
757 	    }
758 	    else
759 	    {
760 		/* where should always be at least one character long. */
761 		assert (where[0] != '\0');
762 		strcpy (new->dirpath, "/");
763 	    }
764 	    new->next = head;
765 	    head = new;
766 
767 	    /* If where consists of multiple pathname components,
768 	       then we want to just cd into it, without creating
769 	       directories or modifying CVS directories as we go.
770 	       In CVS 1.9 and earlier, the code actually does a
771 	       CVS_CHDIR up-front; I'm not going to try to go back
772 	       to that exact code but this is somewhat similar
773 	       in spirit.  */
774 	    if (where_orig != NULL
775 		&& cp - where < strlen (where_orig))
776 	    {
777 		new->repository = NULL;
778 		new->just_chdir = 1;
779 		continue;
780 	    }
781 
782 	    new->just_chdir = 0;
783 
784 	    /* Now figure out what repository directory to generate.
785                The most complete case would be something like this:
786 
787 	       The modules file contains
788 	         foo -d bar/baz quux
789 
790 	       The command issued was:
791 	         cvs co -d what/ever -N foo
792 
793 	       The results in the CVS/Repository files should be:
794 	         .     -> (don't touch CVS/Repository)
795 			  (I think this case might be buggy currently)
796 		 what  -> (don't touch CVS/Repository)
797 		 ever  -> .          (same as "cd what/ever; cvs co -N foo")
798 		 bar   -> Emptydir   (generated dir -- not in repos)
799 		 baz   -> quux       (finally!) */
800 
801 	    if (strcmp (reposcopy, CVSroot_directory) == 0)
802 	    {
803 		/* We can't walk up past CVSROOT.  Instead, the
804                    repository should be Emptydir. */
805 		new->repository = emptydir_name ();
806 	    }
807 	    else
808 	    {
809 		if ((where_orig != NULL)
810 		    && (strcmp (new->dirpath, where_orig) == 0))
811 		{
812 		    /* It's the case that the user specified a
813 		     * destination directory with the "-d" flag.  The
814 		     * repository in this directory should be "."
815 		     * since the user's command is equivalent to:
816 		     *
817 		     *   cd <dir>; cvs co blah   */
818 
819 		    strcpy (reposcopy, CVSroot_directory);
820 		    goto allocate_repos;
821 		}
822 		else if (mwhere != NULL)
823 		{
824 		    /* This is a generated directory, so point to
825                        CVSNULLREPOS. */
826 
827 		    new->repository = emptydir_name ();
828 		}
829 		else
830 		{
831 		    /* It's a directory in the repository! */
832 
833 		    char *rp;
834 
835 		    /* We'll always be below CVSROOT, but check for
836 		       paranoia's sake. */
837 		    rp = strrchr (reposcopy, '/');
838 		    if (rp == NULL)
839 			error (1, 0,
840 			       "internal error: %s doesn't contain a slash",
841 			       reposcopy);
842 
843 		    *rp = '\0';
844 
845 		allocate_repos:
846 		    new->repository = xmalloc (strlen (reposcopy) + 5);
847 		    (void) strcpy (new->repository, reposcopy);
848 
849 		    if (strcmp (reposcopy, CVSroot_directory) == 0)
850 		    {
851 			/* Special case -- the repository name needs
852 			   to be "/path/to/repos/." (the trailing dot
853 			   is important).  We might be able to get rid
854 			   of this after the we check out the other
855 			   code that handles repository names. */
856 			(void) strcat (new->repository, "/.");
857 		    }
858 		}
859 	    }
860 	}
861 
862 	/* clean up */
863 	free (reposcopy);
864 
865 	{
866 	    int where_is_absolute = isabsolute (where);
867 
868 	    /* The top-level CVSADM directory should always be
869 	       CVSroot_directory.  Create it, but only if WHERE is
870 	       relative.  If WHERE is absolute, our current directory
871 	       may not have a thing to do with where the sources are
872 	       being checked out.  If it does, build_dirs_and_chdir
873 	       will take care of creating adm files here. */
874 	    /* FIXME: checking where_is_absolute is a horrid kludge;
875 	       I suspect we probably can just skip the call to
876 	       build_one_dir whenever the -d command option was specified
877 	       to checkout.  */
878 
879 	    if (! where_is_absolute && top_level_admin)
880 	    {
881 		/* It may be argued that we shouldn't set any sticky
882 		   bits for the top-level repository.  FIXME?  */
883 		build_one_dir (CVSroot_directory, ".", argc <= 1);
884 
885 #ifdef SERVER_SUPPORT
886 		/* We _always_ want to have a top-level admin
887 		   directory.  If we're running in client/server mode,
888 		   send a "Clear-static-directory" command to make
889 		   sure it is created on the client side.  (See 5.10
890 		   in cvsclient.dvi to convince yourself that this is
891 		   OK.)  If this is a duplicate command being sent, it
892 		   will be ignored on the client side.  */
893 
894 		if (server_active)
895 		    server_clear_entstat (".", CVSroot_directory);
896 #endif
897 	    }
898 
899 
900 	    /* Build dirs on the path if necessary and leave us in the
901 	       bottom directory (where if where was specified) doesn't
902 	       contain a CVS subdir yet, but all the others contain
903 	       CVS and Entries.Static files */
904 
905 	    if (build_dirs_and_chdir (head, argc <= 1) != 0)
906 	    {
907 		error (0, 0, "ignoring module %s", omodule);
908 		err = 1;
909 		goto out;
910 	    }
911 	}
912 
913 	/* set up the repository (or make sure the old one matches) */
914 	if (!isfile (CVSADM))
915 	{
916 	    FILE *fp;
917 
918 	    if (!noexec && argc > 1)
919 	    {
920 		/* I'm not sure whether this check is redundant.  */
921 		if (!isdir (repository))
922 		    error (1, 0, "there is no repository %s", repository);
923 
924 		Create_Admin (".", preload_update_dir, repository,
925 			      (char *) NULL, (char *) NULL, 0, 0,
926 			      m_type == CHECKOUT);
927 		fp = open_file (CVSADM_ENTSTAT, "w+");
928 		if (fclose(fp) == EOF)
929 		    error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
930 #ifdef SERVER_SUPPORT
931 		if (server_active)
932 		    server_set_entstat (where, repository);
933 #endif
934 	    }
935 	    else
936 	    {
937 		/* I'm not sure whether this check is redundant.  */
938 		if (!isdir (repository))
939 		    error (1, 0, "there is no repository %s", repository);
940 
941 		Create_Admin (".", preload_update_dir, repository, tag, date,
942 
943 			      /* FIXME?  This is a guess.  If it is important
944 				 for nonbranch to be set correctly here I
945 				 think we need to write it one way now and
946 				 then rewrite it later via WriteTag, once
947 				 we've had a chance to call RCS_nodeisbranch
948 				 on each file.  */
949 			      0, 0, m_type == CHECKOUT);
950 	    }
951 	}
952 	else
953 	{
954 	    char *repos;
955 
956 	    if (m_type == EXPORT)
957 		error (1, 0, "cannot export into working directory");
958 
959 	    /* get the contents of the previously existing repository */
960 	    repos = Name_Repository ((char *) NULL, preload_update_dir);
961 	    if (fncmp (repository, repos) != 0)
962 	    {
963 		error (0, 0, "existing repository %s does not match %s",
964 		       repos, repository);
965 		error (0, 0, "ignoring module %s", omodule);
966 		free (repos);
967 		err = 1;
968 		goto out;
969 	    }
970 	    free (repos);
971 	}
972     }
973 
974     /*
975      * If we are going to be updating to stdout, we need to cd to the
976      * repository directory so the recursion processor can use the current
977      * directory as the place to find repository information
978      */
979     if (pipeout)
980     {
981 	if ( CVS_CHDIR (repository) < 0)
982 	{
983 	    error (0, errno, "cannot chdir to %s", repository);
984 	    err = 1;
985 	    goto out;
986 	}
987 	which = W_REPOS;
988 	if (tag != NULL && !tag_validated)
989 	{
990 	    tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, NULL);
991 	    tag_validated = 1;
992 	}
993     }
994     else
995     {
996 	which = W_LOCAL | W_REPOS;
997 	if (tag != NULL && !tag_validated)
998 	{
999 	    tag_check_valid (tag, argc - 1, argv + 1, 0, aflag,
1000 			     repository);
1001 	    tag_validated = 1;
1002 	}
1003     }
1004 
1005     if (tag != NULL || date != NULL || join_rev1 != NULL)
1006 	which |= W_ATTIC;
1007 
1008     if (! join_tags_validated)
1009     {
1010         if (join_rev1 != NULL)
1011 	    tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag,
1012 				  repository);
1013 	if (join_rev2 != NULL)
1014 	    tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag,
1015 				  repository);
1016 	join_tags_validated = 1;
1017     }
1018 
1019     /*
1020      * if we are going to be recursive (building dirs), go ahead and call the
1021      * update recursion processor.  We will be recursive unless either local
1022      * only was specified, or we were passed arguments
1023      */
1024     if (!(local_specified || argc > 1))
1025     {
1026 	if (m_type == CHECKOUT && !pipeout)
1027 	    history_write ('O', preload_update_dir, history_name, where,
1028 			   repository);
1029 	else if (m_type == EXPORT && !pipeout)
1030 	    history_write ('E', preload_update_dir, tag ? tag : date, where,
1031 			   repository);
1032 	err += do_update (0, (char **) NULL, options, tag, date,
1033 			  force_tag_match, 0 /* !local */ ,
1034 			  1 /* update -d */ , aflag, checkout_prune_dirs,
1035 			  pipeout, which, join_rev1, join_rev2,
1036 			  preload_update_dir);
1037 	goto out;
1038     }
1039 
1040     if (!pipeout)
1041     {
1042 	int i;
1043 	List *entries;
1044 
1045 	/* we are only doing files, so register them */
1046 	entries = Entries_Open (0, NULL);
1047 	for (i = 1; i < argc; i++)
1048 	{
1049 	    char *line;
1050 	    Vers_TS *vers;
1051 	    struct file_info finfo;
1052 
1053 	    memset (&finfo, 0, sizeof finfo);
1054 	    finfo.file = argv[i];
1055 	    /* Shouldn't be used, so set to arbitrary value.  */
1056 	    finfo.update_dir = NULL;
1057 	    finfo.fullname = argv[i];
1058 	    finfo.repository = repository;
1059 	    finfo.entries = entries;
1060 	    /* The rcs slot is needed to get the options from the RCS
1061                file */
1062 	    finfo.rcs = RCS_parse (finfo.file, repository);
1063 
1064 	    vers = Version_TS (&finfo, options, tag, date,
1065 			       force_tag_match, 0);
1066 	    if (vers->ts_user == NULL)
1067 	    {
1068 		line = xmalloc (strlen (finfo.file) + 15);
1069 		(void) sprintf (line, "Initial %s", finfo.file);
1070 		Register (entries, finfo.file,
1071 			  vers->vn_rcs ? vers->vn_rcs : "0",
1072 			  line, vers->options, vers->tag,
1073 			  vers->date, (char *) 0);
1074 		free (line);
1075 	    }
1076 	    freevers_ts (&vers);
1077 	    freercsnode (&finfo.rcs);
1078 	}
1079 
1080 	Entries_Close (entries);
1081     }
1082 
1083     /* Don't log "export", just regular "checkouts" */
1084     if (m_type == CHECKOUT && !pipeout)
1085 	history_write ('O', preload_update_dir, history_name, where,
1086 		       repository);
1087 
1088     /* go ahead and call update now that everything is set */
1089     err += do_update (argc - 1, argv + 1, options, tag, date,
1090 		      force_tag_match, local_specified, 1 /* update -d */,
1091 		      aflag, checkout_prune_dirs, pipeout, which, join_rev1,
1092 		      join_rev2, preload_update_dir);
1093 out:
1094     free (preload_update_dir);
1095     preload_update_dir = oldupdate;
1096     free (where);
1097     free (repository);
1098     return (err);
1099 }
1100 
1101 static char *
1102 findslash (start, p)
1103     char *start;
1104     char *p;
1105 {
1106     for (;;)
1107     {
1108 	if (*p == '/') return p;
1109 	if (p == start) break;
1110 	--p;
1111     }
1112     return NULL;
1113 }
1114 
1115 /* Return a newly malloc'd string containing a pathname for CVSNULLREPOS,
1116    and make sure that it exists.  If there is an error creating the
1117    directory, give a fatal error.  Otherwise, the directory is guaranteed
1118    to exist when we return.  */
1119 char *
1120 emptydir_name ()
1121 {
1122     char *repository;
1123 
1124     repository = xmalloc (strlen (CVSroot_directory)
1125 			  + sizeof (CVSROOTADM)
1126 			  + sizeof (CVSNULLREPOS)
1127 			  + 10);
1128     (void) sprintf (repository, "%s/%s/%s", CVSroot_directory,
1129 		    CVSROOTADM, CVSNULLREPOS);
1130     if (!isfile (repository))
1131     {
1132 	mode_t omask;
1133 	omask = umask (cvsumask);
1134 	if (CVS_MKDIR (repository, 0777) < 0)
1135 	    error (1, errno, "cannot create %s", repository);
1136 	(void) umask (omask);
1137     }
1138     return repository;
1139 }
1140 
1141 /* Build all the dirs along the path to DIRS with CVS subdirs with appropriate
1142    repositories.  If ->repository is NULL, do not create a CVSADM directory
1143    for that subdirectory; just CVS_CHDIR into it.  */
1144 static int
1145 build_dirs_and_chdir (dirs, sticky)
1146     struct dir_to_build *dirs;
1147     int sticky;
1148 {
1149     int retval = 0;
1150     struct dir_to_build *nextdir;
1151 
1152     while (dirs != NULL)
1153     {
1154 	char *dir = last_component (dirs->dirpath);
1155 
1156 	if (!dirs->just_chdir)
1157 	{
1158 	    mkdir_if_needed (dir);
1159 	    Subdir_Register (NULL, NULL, dir);
1160 	}
1161 
1162 	if (CVS_CHDIR (dir) < 0)
1163 	{
1164 	    error (0, errno, "cannot chdir to %s", dir);
1165 	    retval = 1;
1166 	    goto out;
1167 	}
1168 	if (dirs->repository != NULL)
1169 	{
1170 	    build_one_dir (dirs->repository, dirs->dirpath, sticky);
1171 	    free (dirs->repository);
1172 	}
1173 	nextdir = dirs->next;
1174 	free (dirs->dirpath);
1175 	free (dirs);
1176 	dirs = nextdir;
1177     }
1178 
1179  out:
1180     while (dirs != NULL)
1181     {
1182 	if (dirs->repository != NULL)
1183 	    free (dirs->repository);
1184 	nextdir = dirs->next;
1185 	free (dirs->dirpath);
1186 	free (dirs);
1187 	dirs = nextdir;
1188     }
1189     return retval;
1190 }
1191