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