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