checkout.c revision 17721
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 1.4 kit.
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 build_dirs_and_chdir PROTO((char *dir, char *prepath, char *realdir,
40				 int sticky));
41static int checkout_proc PROTO((int *pargc, char **argv, char *where,
42		          char *mwhere, char *mfile, int shorten,
43		          int local_specified, char *omodule,
44		          char *msg));
45static int safe_location PROTO((void));
46
47static const char *const checkout_usage[] =
48{
49    "Usage:\n  %s %s [-ANPcflnps] [-r rev | -D date] [-d dir] [-k kopt] modules...\n",
50    "\t-A\tReset any sticky tags/date/kopts.\n",
51    "\t-N\tDon't shorten module paths if -d specified.\n",
52    "\t-P\tPrune empty directories.\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.\n",
58    "\t-s\tLike -c, but include module status.\n",
59    "\t-r rev\tCheck out revision or tag. (implies -P)\n",
60    "\t-D date\tCheck out revisions as of date. (implies -P)\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    NULL
65};
66
67static const char *const export_usage[] =
68{
69    "Usage: %s %s [-NPfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n",
70    "\t-N\tDon't shorten module paths if -d specified.\n",
71    "\t-f\tForce a head revision match if tag/date not found.\n",
72    "\t-l\tLocal directory only, not recursive\n",
73    "\t-n\tDo not run module program (if any).\n",
74    "\t-r rev\tCheck out revision or tag.\n",
75    "\t-D date\tCheck out revisions as of date.\n",
76    "\t-d dir\tCheck out into dir instead of module name.\n",
77    "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
78    NULL
79};
80
81static int checkout_prune_dirs;
82static int force_tag_match = 1;
83static int pipeout;
84static int aflag;
85static char *options = NULL;
86static char *tag = NULL;
87static int tag_validated = 0;
88static char *date = NULL;
89static char *join_rev1 = NULL;
90static char *join_rev2 = NULL;
91static char *preload_update_dir = NULL;
92
93int
94checkout (argc, argv)
95    int argc;
96    char **argv;
97{
98    int i;
99    int c;
100    DBM *db;
101    int cat = 0, err = 0, status = 0;
102    int run_module_prog = 1;
103    int local = 0;
104    int shorten = -1;
105    char *where = NULL;
106    char *valid_options;
107    const char *const *valid_usage;
108    enum mtype m_type;
109
110    /*
111     * A smaller subset of options are allowed for the export command, which
112     * is essentially like checkout, except that it hard-codes certain
113     * options to be default (like -kv) and takes care to remove the CVS
114     * directory when it has done its duty
115     */
116    if (strcmp (command_name, "export") == 0)
117    {
118        m_type = EXPORT;
119	valid_options = "Nnk:d:flRQqr:D:";
120	valid_usage = export_usage;
121    }
122    else
123    {
124        m_type = CHECKOUT;
125	valid_options = "ANnk:d:flRpQqcsr:D:j:P";
126	valid_usage = checkout_usage;
127    }
128
129    if (argc == -1)
130	usage (valid_usage);
131
132    ign_setup ();
133    wrap_setup ();
134
135    optind = 1;
136    while ((c = getopt (argc, argv, valid_options)) != -1)
137    {
138	switch (c)
139	{
140	    case 'A':
141		aflag = 1;
142		break;
143	    case 'N':
144		shorten = 0;
145		break;
146	    case 'k':
147		if (options)
148		    free (options);
149		options = RCS_check_kflag (optarg);
150		break;
151	    case 'n':
152		run_module_prog = 0;
153		break;
154	    case 'Q':
155	    case 'q':
156#ifdef SERVER_SUPPORT
157		/* The CVS 1.5 client sends these options (in addition to
158		   Global_option requests), so we must ignore them.  */
159		if (!server_active)
160#endif
161		    error (1, 0,
162			   "-q or -Q must be specified before \"%s\"",
163			   command_name);
164		break;
165	    case 'l':
166		local = 1;
167		break;
168	    case 'R':
169		local = 0;
170		break;
171	    case 'P':
172		checkout_prune_dirs = 1;
173		break;
174	    case 'p':
175		pipeout = 1;
176		run_module_prog = 0;	/* don't run module prog when piping */
177		noexec = 1;		/* so no locks will be created */
178		break;
179	    case 'c':
180		cat = 1;
181		break;
182	    case 'd':
183		where = optarg;
184		if (shorten == -1)
185		    shorten = 1;
186		break;
187	    case 's':
188		status = 1;
189		break;
190	    case 'f':
191		force_tag_match = 0;
192		break;
193	    case 'r':
194		tag = optarg;
195		checkout_prune_dirs = 1;
196		break;
197	    case 'D':
198		date = Make_Date (optarg);
199		checkout_prune_dirs = 1;
200		break;
201	    case 'j':
202		if (join_rev2)
203		    error (1, 0, "only two -j options can be specified");
204		if (join_rev1)
205		    join_rev2 = optarg;
206		else
207		    join_rev1 = optarg;
208		break;
209	    case '?':
210	    default:
211		usage (valid_usage);
212		break;
213	}
214    }
215    argc -= optind;
216    argv += optind;
217
218    if (shorten == -1)
219	shorten = 0;
220
221    if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0)
222	|| (tag && date))
223	usage (valid_usage);
224
225    if (where && pipeout)
226	error (1, 0, "-d and -p are mutually exclusive");
227
228    if (strcmp (command_name, "export") == 0)
229    {
230	if (!tag && !date)
231	{
232	    error (0, 0, "must specify a tag or date");
233	    usage (valid_usage);
234	}
235	if (tag && isdigit (tag[0]))
236	    error (1, 0, "tag `%s' must be a symbolic tag", tag);
237/*
238 * mhy 950615: -kv doesn't work for binaries with RCS keywords.
239 * Instead use the default provided in the RCS file (-ko for binaries).
240 */
241#if 0
242	if (!options)
243	  options = RCS_check_kflag ("v");/* -kv is default */
244#endif
245    }
246
247    if (!safe_location()) {
248        error(1, 0, "Cannot check out files into the repository itself");
249    }
250
251#ifdef CLIENT_SUPPORT
252    if (client_active)
253    {
254	int expand_modules;
255
256	start_server ();
257
258	ign_setup ();
259
260	/* We have to expand names here because the "expand-modules"
261           directive to the server has the side-effect of having the
262           server send the check-in and update programs for the
263           various modules/dirs requested.  If we turn this off and
264           simply request the names of the modules and directories (as
265           below in !expand_modules), those files (CVS/Checking.prog
266           or CVS/Update.prog) don't get created.  Grrr.  */
267
268	expand_modules = (!cat && !status && !pipeout
269			  && supported_request ("expand-modules"));
270
271	if (expand_modules)
272	  {
273	    /* This is done here because we need to read responses
274               from the server before we send the command checkout or
275               export files. */
276
277	    client_expand_modules (argc, argv, local);
278	  }
279
280	if (!run_module_prog) send_arg ("-n");
281	if (local) send_arg ("-l");
282	if (pipeout) send_arg ("-p");
283	if (!force_tag_match) send_arg ("-f");
284	if (aflag)
285	    send_arg("-A");
286	if (!shorten)
287	    send_arg("-N");
288	if (checkout_prune_dirs && strcmp (command_name, "export") != 0)
289	    send_arg("-P");
290	client_prune_dirs = checkout_prune_dirs;
291	if (cat)
292	    send_arg("-c");
293	if (where != NULL)
294	{
295	    option_with_arg ("-d", where);
296	}
297	if (status)
298	    send_arg("-s");
299	if (strcmp (command_name, "export") != 0
300	    && options != NULL
301	    && options[0] != '\0')
302	    send_arg (options);
303	option_with_arg ("-r", tag);
304	if (date)
305	    client_senddate (date);
306	if (join_rev1 != NULL)
307	    option_with_arg ("-j", join_rev1);
308	if (join_rev2 != NULL)
309	    option_with_arg ("-j", join_rev2);
310
311	if (expand_modules)
312	  {
313	    client_send_expansions (local);
314	  }
315	else
316	  {
317	    int i;
318	    for (i = 0; i < argc; ++i)
319	      send_arg (argv[i]);
320	    client_nonexpanded_setup ();
321	  }
322
323	send_to_server (strcmp (command_name, "export") == 0 ?
324                        "export\012" : "co\012",
325                        0);
326
327	return get_responses_and_close ();
328    }
329#endif /* CLIENT_SUPPORT */
330
331    if (cat || status)
332    {
333	cat_module (status);
334	return (0);
335    }
336    db = open_module ();
337
338    /*
339     * if we have more than one argument and where was specified, we make the
340     * where, cd into it, and try to shorten names as much as possible.
341     * Otherwise, we pass the where as a single argument to do_module.
342     */
343    if (argc > 1 && where != NULL)
344    {
345	char repository[PATH_MAX];
346
347	(void) CVS_MKDIR (where, 0777);
348	if (chdir (where) < 0)
349	    error (1, errno, "cannot chdir to %s", where);
350	preload_update_dir = xstrdup (where);
351	where = (char *) NULL;
352	if (!isfile (CVSADM))
353	{
354	    (void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM,
355			    CVSNULLREPOS);
356	    if (!isfile (repository))
357	    {
358		mode_t omask;
359		omask = umask (cvsumask);
360		(void) CVS_MKDIR (repository, 0777);
361		(void) umask (omask);
362	    }
363
364	    /* I'm not sure whether this check is redundant.  */
365	    if (!isdir (repository))
366		error (1, 0, "there is no repository %s", repository);
367
368	    Create_Admin (".", where, repository,
369			  (char *) NULL, (char *) NULL);
370	    if (!noexec)
371	    {
372		FILE *fp;
373
374		fp = open_file (CVSADM_ENTSTAT, "w+");
375		if (fclose(fp) == EOF)
376		    error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
377#ifdef SERVER_SUPPORT
378		if (server_active)
379		    server_set_entstat (preload_update_dir, repository);
380#endif
381	    }
382	}
383    }
384
385    /*
386     * if where was specified (-d) and we have not taken care of it already
387     * with the multiple arg stuff, and it was not a simple directory name
388     * but rather a path, we strip off everything but the last component and
389     * attempt to cd to the indicated place.  where then becomes simply the
390     * last component
391     */
392    if (where != NULL && strchr (where, '/') != NULL)
393    {
394	char *slash;
395
396	slash = strrchr (where, '/');
397	*slash = '\0';
398
399	if (chdir (where) < 0)
400	    error (1, errno, "cannot chdir to %s", where);
401
402	preload_update_dir = xstrdup (where);
403
404	where = slash + 1;
405	if (*where == '\0')
406	    where = NULL;
407    }
408
409    for (i = 0; i < argc; i++)
410	err += do_module (db, argv[i], m_type, "Updating", checkout_proc,
411			  where, shorten, local, run_module_prog,
412			  (char *) NULL);
413    close_module (db);
414    return (err);
415}
416
417static int
418safe_location ()
419{
420    char current[PATH_MAX];
421    char hardpath[PATH_MAX+5];
422    int  x;
423
424    x = readlink(CVSroot, hardpath, sizeof hardpath - 1);
425    if (x == -1)
426    {
427        strcpy(hardpath, CVSroot);
428    }
429    else
430    {
431        hardpath[x] = '\0';
432    }
433    getwd (current);
434    if (strncmp(current, hardpath, strlen(hardpath)) == 0)
435    {
436        return (0);
437    }
438    return (1);
439}
440
441/*
442 * process_module calls us back here so we do the actual checkout stuff
443 */
444/* ARGSUSED */
445static int
446checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
447	       local_specified, omodule, msg)
448    int *pargc;
449    char **argv;
450    char *where;
451    char *mwhere;
452    char *mfile;
453    int shorten;
454    int local_specified;
455    char *omodule;
456    char *msg;
457{
458    int err = 0;
459    int which;
460    char *cp;
461    char *cp2;
462    char repository[PATH_MAX];
463    char xwhere[PATH_MAX];
464    char *oldupdate = NULL;
465    char *prepath;
466    char *realdirs;
467
468    /*
469     * OK, so we're doing the checkout! Our args are as follows:
470     *  argc,argv contain either dir or dir followed by a list of files
471     *  where contains where to put it (if supplied by checkout)
472     *  mwhere contains the module name or -d from module file
473     *  mfile says do only that part of the module
474     *  shorten = TRUE says shorten as much as possible
475     *  omodule is the original arg to do_module()
476     */
477
478    /* set up the repository (maybe) for the bottom directory */
479    (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
480
481    /* save the original value of preload_update_dir */
482    if (preload_update_dir != NULL)
483	oldupdate = xstrdup (preload_update_dir);
484
485    /* fix up argv[] for the case of partial modules */
486    if (mfile != NULL)
487    {
488	char file[PATH_MAX];
489
490	/* if mfile is really a path, straighten it out first */
491	if ((cp = strrchr (mfile, '/')) != NULL)
492	{
493	    *cp = 0;
494	    (void) strcat (repository, "/");
495	    (void) strcat (repository, mfile);
496
497	    /*
498	     * Now we need to fill in the where correctly. if !shorten, tack
499	     * the rest of the path onto where if where is filled in
500	     * otherwise tack the rest of the path onto mwhere and make that
501	     * the where
502	     *
503	     * If shorten is enabled, we might use mwhere to set where if
504	     * nobody set it yet, so we'll need to setup mwhere as the last
505	     * component of the path we are tacking onto repository
506	     */
507	    if (!shorten)
508	    {
509		if (where != NULL)
510		    (void) sprintf (xwhere, "%s/%s", where, mfile);
511		else
512		    (void) sprintf (xwhere, "%s/%s", mwhere, mfile);
513		where = xwhere;
514	    }
515	    else
516	    {
517		char *slash;
518
519		if ((slash = strrchr (mfile, '/')) != NULL)
520		    mwhere = slash + 1;
521		else
522		    mwhere = mfile;
523	    }
524	    mfile = cp + 1;
525	}
526
527	(void) sprintf (file, "%s/%s", repository, mfile);
528	if (isdir (file))
529	{
530
531	    /*
532	     * The portion of a module was a directory, so kludge up where to
533	     * be the subdir, and fix up repository
534	     */
535	    (void) strcpy (repository, file);
536
537	    /*
538	     * At this point, if shorten is not enabled, we make where either
539	     * where with mfile concatenated, or if where hadn't been set we
540	     * set it to mwhere with mfile concatenated.
541	     *
542	     * If shorten is enabled and where hasn't been set yet, then where
543	     * becomes mfile
544	     */
545	    if (!shorten)
546	    {
547		if (where != NULL)
548		    (void) sprintf (xwhere, "%s/%s", where, mfile);
549		else
550		    (void) sprintf (xwhere, "%s/%s", mwhere, mfile);
551		where = xwhere;
552	    }
553	    else if (where == NULL)
554		where = mfile;
555	}
556	else
557	{
558	    int i;
559
560	    /*
561	     * The portion of a module was a file, so kludge up argv to be
562	     * correct
563	     */
564	    for (i = 1; i < *pargc; i++)/* free the old ones */
565		free (argv[i]);
566	    argv[1] = xstrdup (mfile);	/* set up the new one */
567	    *pargc = 2;
568
569	    /* where gets mwhere if where isn't set */
570	    if (where == NULL)
571		where = mwhere;
572	}
573    }
574
575    /*
576     * if shorten is enabled and where isn't specified yet, we pluck the last
577     * directory component of argv[0] and make it the where
578     */
579    if (shorten && where == NULL)
580    {
581	if ((cp = strrchr (argv[0], '/')) != NULL)
582	{
583	    (void) strcpy (xwhere, cp + 1);
584	    where = xwhere;
585	}
586    }
587
588    /* if where is still NULL, use mwhere if set or the argv[0] dir */
589    if (where == NULL)
590    {
591	if (mwhere)
592	    where = mwhere;
593	else
594	{
595	    (void) strcpy (xwhere, argv[0]);
596	    where = xwhere;
597	}
598    }
599
600    if (preload_update_dir != NULL)
601    {
602	char tmp[PATH_MAX];
603
604	(void) sprintf (tmp, "%s/%s", preload_update_dir, where);
605	free (preload_update_dir);
606	preload_update_dir = xstrdup (tmp);
607    }
608    else
609	preload_update_dir = xstrdup (where);
610
611    /*
612     * At this point, where is the directory we want to build, repository is
613     * the repository for the lowest level of the path.
614     */
615
616    /*
617     * If we are sending everything to stdout, we can skip a whole bunch of
618     * work from here
619     */
620    if (!pipeout)
621    {
622
623	/*
624	 * We need to tell build_dirs not only the path we want it to build,
625	 * but also the repositories we want it to populate the path with. To
626	 * accomplish this, we pass build_dirs a ``real path'' with valid
627	 * repositories and a string to pre-pend based on how many path
628	 * elements exist in where. Big Black Magic
629	 */
630	prepath = xstrdup (repository);
631	cp = strrchr (where, '/');
632	cp2 = strrchr (prepath, '/');
633	while (cp != NULL)
634	{
635	    cp = findslash (where, cp - 1);
636	    cp2 = findslash (prepath, cp2 - 1);
637	}
638	*cp2 = '\0';
639	realdirs = cp2 + 1;
640
641	/*
642	 * build dirs on the path if necessary and leave us in the bottom
643	 * directory (where if where was specified) doesn't contain a CVS
644	 * subdir yet, but all the others contain CVS and Entries.Static
645	 * files
646	 */
647	if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0)
648	{
649	    error (0, 0, "ignoring module %s", omodule);
650	    free (prepath);
651	    free (preload_update_dir);
652	    preload_update_dir = oldupdate;
653	    return (1);
654	}
655
656	/* clean up */
657	free (prepath);
658
659	/* set up the repository (or make sure the old one matches) */
660	if (!isfile (CVSADM))
661	{
662	    FILE *fp;
663
664	    if (!noexec && *pargc > 1)
665	    {
666		/* I'm not sure whether this check is redundant.  */
667		if (!isdir (repository))
668		    error (1, 0, "there is no repository %s", repository);
669
670		Create_Admin (".", where, repository,
671			      (char *) NULL, (char *) NULL);
672		fp = open_file (CVSADM_ENTSTAT, "w+");
673		if (fclose(fp) == EOF)
674		    error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
675#ifdef SERVER_SUPPORT
676		if (server_active)
677		    server_set_entstat (where, repository);
678#endif
679	    }
680	    else
681	    {
682		/* I'm not sure whether this check is redundant.  */
683		if (!isdir (repository))
684		    error (1, 0, "there is no repository %s", repository);
685
686		Create_Admin (".", where, repository, tag, date);
687	    }
688	}
689	else
690	{
691	    char *repos;
692
693	    /* get the contents of the previously existing repository */
694	    repos = Name_Repository ((char *) NULL, preload_update_dir);
695	    if (fncmp (repository, repos) != 0)
696	    {
697		error (0, 0, "existing repository %s does not match %s",
698		       repos, repository);
699		error (0, 0, "ignoring module %s", omodule);
700		free (repos);
701		free (preload_update_dir);
702		preload_update_dir = oldupdate;
703		return (1);
704	    }
705	    free (repos);
706	}
707    }
708
709    /*
710     * If we are going to be updating to stdout, we need to cd to the
711     * repository directory so the recursion processor can use the current
712     * directory as the place to find repository information
713     */
714    if (pipeout)
715    {
716	if (chdir (repository) < 0)
717	{
718	    error (0, errno, "cannot chdir to %s", repository);
719	    free (preload_update_dir);
720	    preload_update_dir = oldupdate;
721	    return (1);
722	}
723	which = W_REPOS;
724	if (tag != NULL && !tag_validated)
725	{
726	    tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL);
727	    tag_validated = 1;
728	}
729    }
730    else
731    {
732	which = W_LOCAL | W_REPOS;
733	if (tag != NULL && !tag_validated)
734	{
735	    tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag,
736			     repository);
737	    tag_validated = 1;
738	}
739    }
740
741    if (tag != NULL || date != NULL)
742	which |= W_ATTIC;
743
744    /* FIXME: We don't call tag_check_valid on join_rev1 and join_rev2
745       yet (make sure to handle ':' correctly if we do, though).  */
746
747    /*
748     * if we are going to be recursive (building dirs), go ahead and call the
749     * update recursion processor.  We will be recursive unless either local
750     * only was specified, or we were passed arguments
751     */
752    if (!(local_specified || *pargc > 1))
753    {
754	if (strcmp (command_name, "export") != 0 && !pipeout)
755	    history_write ('O', preload_update_dir, tag ? tag : date, where,
756			   repository);
757	err += do_update (0, (char **) NULL, options, tag, date,
758			  force_tag_match, 0 /* !local */ ,
759			  1 /* update -d */ , aflag, checkout_prune_dirs,
760			  pipeout, which, join_rev1, join_rev2,
761			  preload_update_dir);
762	free (preload_update_dir);
763	preload_update_dir = oldupdate;
764	return (err);
765    }
766
767    if (!pipeout)
768    {
769	int i;
770	List *entries;
771
772	/* we are only doing files, so register them */
773	entries = Entries_Open (0);
774	for (i = 1; i < *pargc; i++)
775	{
776	    char *line;
777	    char *user;
778	    Vers_TS *vers;
779
780	    user = argv[i];
781	    vers = Version_TS (repository, options, tag, date, user,
782			       force_tag_match, 0, entries, (RCSNode *) NULL);
783	    if (vers->ts_user == NULL)
784	    {
785		line = xmalloc (strlen (user) + 15);
786		(void) sprintf (line, "Initial %s", user);
787		Register (entries, user, vers->vn_rcs ? vers->vn_rcs : "0",
788			  line, vers->options, vers->tag,
789			  vers->date, (char *) 0);
790		free (line);
791	    }
792	    freevers_ts (&vers);
793	}
794
795	Entries_Close (entries);
796    }
797
798    /* Don't log "export", just regular "checkouts" */
799    if (strcmp (command_name, "export") != 0 && !pipeout)
800	history_write ('O', preload_update_dir, (tag ? tag : date), where,
801		       repository);
802
803    /* go ahead and call update now that everything is set */
804    err += do_update (*pargc - 1, argv + 1, options, tag, date,
805		      force_tag_match, local_specified, 1 /* update -d */,
806		      aflag, checkout_prune_dirs, pipeout, which, join_rev1,
807		      join_rev2, preload_update_dir);
808    free (preload_update_dir);
809    preload_update_dir = oldupdate;
810    return (err);
811}
812
813static char *
814findslash (start, p)
815    char *start;
816    char *p;
817{
818    while (p >= start && *p != '/')
819	p--;
820    if (p < start)
821	return (NULL);
822    else
823	return (p);
824}
825
826/*
827 * build all the dirs along the path to dir with CVS subdirs with appropriate
828 * repositories and Entries.Static files
829 */
830static int
831build_dirs_and_chdir (dir, prepath, realdir, sticky)
832    char *dir;
833    char *prepath;
834    char *realdir;
835    int sticky;
836{
837    FILE *fp;
838    char repository[PATH_MAX];
839    char path[PATH_MAX];
840    char path2[PATH_MAX];
841    char *slash;
842    char *slash2;
843    char *cp;
844    char *cp2;
845
846    (void) strcpy (path, dir);
847    (void) strcpy (path2, realdir);
848    for (cp = path, cp2 = path2;
849    (slash = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL;
850	 cp = slash + 1, cp2 = slash2 + 1)
851    {
852	*slash = '\0';
853	*slash2 = '\0';
854	(void) CVS_MKDIR (cp, 0777);
855	if (chdir (cp) < 0)
856	{
857	    error (0, errno, "cannot chdir to %s", cp);
858	    return (1);
859	}
860	if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
861	{
862	    (void) sprintf (repository, "%s/%s", prepath, path2);
863	    /* I'm not sure whether this check is redundant.  */
864	    if (!isdir (repository))
865		error (1, 0, "there is no repository %s", repository);
866	    Create_Admin (".", path, repository, sticky ? (char *) NULL : tag,
867			  sticky ? (char *) NULL : date);
868	    if (!noexec)
869	    {
870		fp = open_file (CVSADM_ENTSTAT, "w+");
871		if (fclose(fp) == EOF)
872		    error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
873#ifdef SERVER_SUPPORT
874		if (server_active)
875		    server_set_entstat (path, repository);
876#endif
877	    }
878	}
879	*slash = '/';
880	*slash2 = '/';
881    }
882    (void) CVS_MKDIR (cp, 0777);
883    if (chdir (cp) < 0)
884    {
885	error (0, errno, "cannot chdir to %s", cp);
886	return (1);
887    }
888    return (0);
889}
890