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