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