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