main.c revision 34467
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
6 *    as specified in the README file that comes with the CVS source distribution.
7 *
8 * This is the main C driver for the CVS system.
9 *
10 * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
11 * the shell-script CVS system that this is based on.
12 *
13 */
14
15#include "cvs.h"
16
17#ifdef HAVE_WINSOCK_H
18#include <winsock.h>
19#else
20extern int gethostname ();
21#endif
22
23char *program_name;
24char *program_path;
25char *command_name;
26
27/* I'd dynamically allocate this, but it seems like gethostname
28   requires a fixed size array.  If I'm remembering the RFCs right,
29   256 should be enough.  */
30#ifndef MAXHOSTNAMELEN
31#define MAXHOSTNAMELEN  256
32#endif
33
34char hostname[MAXHOSTNAMELEN];
35
36int use_editor = 1;
37int use_cvsrc = 1;
38int cvswrite = !CVSREAD_DFLT;
39int really_quiet = 0;
40int quiet = 0;
41int trace = 0;
42int noexec = 0;
43int readonlyfs = 0;
44int logoff = 0;
45mode_t cvsumask = UMASK_DFLT;
46
47char *CurDir;
48
49/*
50 * Defaults, for the environment variables that are not set
51 */
52char *Tmpdir = TMPDIR_DFLT;
53char *Editor = EDITOR_DFLT;
54
55static const struct cmd
56{
57    char *fullname;		/* Full name of the function (e.g. "commit") */
58
59    /* Synonyms for the command, nick1 and nick2.  We supply them
60       mostly for two reasons: (1) CVS has always supported them, and
61       we need to maintain compatibility, (2) if there is a need for a
62       version which is shorter than the fullname, for ease in typing.
63       Synonyms have the disadvantage that people will see "new" and
64       then have to think about it, or look it up, to realize that is
65       the operation they know as "add".  Also, this means that one
66       cannot create a command "cvs new" with a different meaning.  So
67       new synonyms are probably best used sparingly, and where used
68       should be abbreviations of the fullname (preferably consisting
69       of the first 2 or 3 or so letters).
70
71       One thing that some systems do is to recognize any unique
72       abbreviation, for example "annotat" "annota", etc., for
73       "annotate".  The problem with this is that scripts and user
74       habits will expect a certain abbreviation to be unique, and in
75       a future release of CVS it may not be.  So it is better to
76       accept only an explicit list of abbreviations and plan on
77       supporting them in the future as well as now.  */
78
79    char *nick1;
80    char *nick2;
81
82    int (*func) ();		/* Function takes (argc, argv) arguments. */
83} cmds[] =
84
85{
86    { "add",      "ad",       "new",       add },
87    { "admin",    "adm",      "rcs",       admin },
88    { "annotate", "ann",      NULL,        annotate },
89    { "checkout", "co",       "get",       checkout },
90    { "commit",   "ci",       "com",       commit },
91    { "diff",     "di",       "dif",       diff },
92    { "edit",     NULL,	      NULL,	   edit },
93    { "editors",  NULL,       NULL,	   editors },
94    { "export",   "exp",      "ex",        checkout },
95    { "history",  "hi",       "his",       history },
96    { "import",   "im",       "imp",       import },
97    { "init",     NULL,       NULL,        init },
98#ifdef SERVER_SUPPORT
99    { "kserver",  NULL,       NULL,        server }, /* placeholder */
100#endif
101    { "log",      "lo",       "rlog",      cvslog },
102#ifdef AUTH_CLIENT_SUPPORT
103    { "login",    "logon",    "lgn",       login },
104    { "logout",   NULL,       NULL,        logout },
105#ifdef SERVER_SUPPORT
106    { "pserver",  NULL,       NULL,        server }, /* placeholder */
107#endif
108#endif /* AUTH_CLIENT_SUPPORT */
109    { "rdiff",    "patch",    "pa",        patch },
110    { "release",  "re",       "rel",       release },
111    { "remove",   "rm",       "delete",    cvsremove },
112    { "status",   "st",       "stat",      status },
113    { "rtag",     "rt",       "rfreeze",   rtag },
114    { "tag",      "ta",       "freeze",    cvstag },
115    { "unedit",   NULL,	      NULL,	   unedit },
116    { "update",   "up",       "upd",       update },
117    { "watch",    NULL,	      NULL,	   watch },
118    { "watchers", NULL,	      NULL,	   watchers },
119#ifdef SERVER_SUPPORT
120    { "server",   NULL,       NULL,        server },
121#endif
122    { NULL, NULL, NULL, NULL },
123};
124
125static const char *const usg[] =
126{
127    /* CVS usage messages never have followed the GNU convention of
128       putting metavariables in uppercase.  I don't know whether that
129       is a good convention or not, but if it changes it would have to
130       change in all the usage messages.  For now, they consistently
131       use lowercase, as far as I know.  Puncutation is pretty funky,
132       though.  Sometimes they use none, as here.  Sometimes they use
133       single quotes (not the TeX-ish `' stuff), as in --help-options.
134       Sometimes they use double quotes, as in cvs -H add.
135
136       Most (not all) of the usage messages seem to have periods at
137       the end of each line.  I haven't tried to duplicate this style
138       in --help as it is a rather different format from the rest.  */
139
140    "Usage: %s [cvs-options] command [command-options-and-arguments]\n",
141    "  where cvs-options are -q, -n, etc.\n",
142    "    (specify --help-options for a list of options)\n",
143    "  where command is add, admin, etc.\n",
144    "    (specify --help-commands for a list of commands\n",
145    "     or --help-synonyms for a list of command synonyms)\n",
146    "  where command-options-and-arguments depend on the specific command\n",
147    "    (specify -H followed by a command name for command-specific help)\n",
148    "  Specify --help to receive this message\n",
149    "\n",
150
151    /* Some people think that a bug-reporting address should go here.  IMHO,
152       the web sites are better because anything else is very likely to go
153       obsolete in the years between a release and when someone might be
154       reading this help.  Besides, we could never adequately discuss
155       bug reporting in a concise enough way to put in a help message.  */
156
157    /* I was going to put this at the top, but usage() wants the %s to
158       be in the first line.  */
159    "The Concurrent Versions System (CVS) is a tool for version control.\n",
160    /* I really don't think I want to try to define "version control"
161       in one line.  I'm not sure one can get more concise than the
162       paragraph in ../cvs.spec without assuming the reader knows what
163       version control means.  */
164
165    "For CVS updates and additional information, see\n",
166    "    Cyclic Software at http://www.cyclic.com/ or\n",
167    "    Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
168    NULL,
169};
170
171static const char *const cmd_usage[] =
172{
173    "CVS commands are:\n",
174    "        add          Add a new file/directory to the repository\n",
175    "        admin        Administration front end for rcs\n",
176    "        annotate     Show last revision where each line was modified\n",
177    "        checkout     Checkout sources for editing\n",
178    "        commit       Check files into the repository\n",
179    "        diff         Show differences between revisions\n",
180    "        edit         Get ready to edit a watched file\n",
181    "        editors      See who is editing a watched file\n",
182    "        export       Export sources from CVS, similar to checkout\n",
183    "        history      Show repository access history\n",
184    "        import       Import sources into CVS, using vendor branches\n",
185    "        init         Create a CVS repository if it doesn't exist\n",
186    "        log          Print out history information for files\n",
187#ifdef AUTH_CLIENT_SUPPORT
188    "        login        Prompt for password for authenticating server.\n",
189    "        logout       Removes entry in .cvspass for remote repository.\n",
190#endif /* AUTH_CLIENT_SUPPORT */
191    "        rdiff        Create 'patch' format diffs between releases\n",
192    "        release      Indicate that a Module is no longer in use\n",
193    "        remove       Remove an entry from the repository\n",
194    "        rtag         Add a symbolic tag to a module\n",
195    "        status       Display status information on checked out files\n",
196    "        tag          Add a symbolic tag to checked out version of files\n",
197    "        unedit       Undo an edit command\n",
198    "        update       Bring work tree in sync with repository\n",
199    "        watch        Set watches\n",
200    "        watchers     See who is watching a file\n",
201    "(Specify the --help option for a list of other help options)\n",
202    NULL,
203};
204
205static const char *const opt_usage[] =
206{
207    "CVS global options (specified before the command name) are:\n",
208    "    -H           Displays usage information for command.\n",
209    "    -Q           Cause CVS to be really quiet.\n",
210    "    -q           Cause CVS to be somewhat quiet.\n",
211    "    -r           Make checked-out files read-only.\n",
212    "    -w           Make checked-out files read-write (default).\n",
213    "    -l           Turn history logging off.\n",
214    "    -n           Do not execute anything that will change the disk.\n",
215    "    -t           Show trace of program execution -- try with -n.\n",
216    "    -R           Assume repository is read-only, such as CDROM\n",
217    "    -v           CVS version and copyright.\n",
218    "    -b bindir    Find RCS programs in 'bindir'.\n",
219    "    -T tmpdir    Use 'tmpdir' for temporary files.\n",
220    "    -e editor    Use 'editor' for editing log information.\n",
221    "    -d CVS_root  Overrides $CVSROOT as the root of the CVS tree.\n",
222    "    -f           Do not use the ~/.cvsrc file.\n",
223#ifdef CLIENT_SUPPORT
224    "    -z #         Use compression level '#' for net traffic.\n",
225#ifdef ENCRYPTION
226    "    -x           Encrypt all net traffic.\n",
227#endif
228    "    -a           Authenticate all net traffic.\n",
229#endif
230    "    -s VAR=VAL   Set CVS user variable.\n",
231    "(Specify the --help option for a list of other help options)\n",
232    NULL
233};
234
235static const char * const*
236cmd_synonyms ()
237{
238    char ** synonyms;
239    char ** line;
240    const struct cmd *c = &cmds[0];
241    /* Three more for title, "specify --help" line, and NULL.  */
242    int numcmds = 3;
243
244    while (c->fullname != NULL)
245    {
246	numcmds++;
247	c++;
248    }
249
250    synonyms = (char **) xmalloc(numcmds * sizeof(char *));
251    line = synonyms;
252    *line++ = "CVS command synonyms are:\n";
253    for (c = &cmds[0]; c->fullname != NULL; c++)
254    {
255	if (c->nick1 || c->nick2)
256	{
257	    *line = xmalloc (strlen (c->fullname)
258			     + (c->nick1 != NULL ? strlen (c->nick1) : 0)
259			     + (c->nick2 != NULL ? strlen (c->nick2) : 0)
260			     + 40);
261	    sprintf(*line, "        %-12s %s %s\n", c->fullname,
262		    c->nick1 ? c->nick1 : "",
263		    c->nick2 ? c->nick2 : "");
264	    line++;
265	}
266    }
267    *line++ = "(Specify the --help option for a list of other help options)\n";
268    *line = NULL;
269
270    return (const char * const*) synonyms; /* will never be freed */
271}
272
273
274unsigned long int
275lookup_command_attribute (cmd_name)
276     char *cmd_name;
277{
278    unsigned long int ret = 0;
279
280    if (strcmp (cmd_name, "import") != 0)
281    {
282        ret |= CVS_CMD_IGNORE_ADMROOT;
283    }
284
285
286    if ((strcmp (cmd_name, "checkout") != 0) &&
287        (strcmp (cmd_name, "init") != 0) &&
288        (strcmp (cmd_name, "login") != 0) &&
289	(strcmp (cmd_name, "logout") != 0) &&
290        (strcmp (cmd_name, "rdiff") != 0) &&
291        (strcmp (cmd_name, "release") != 0) &&
292        (strcmp (cmd_name, "rtag") != 0))
293    {
294        ret |= CVS_CMD_USES_WORK_DIR;
295    }
296
297
298    /* The following commands do not modify the repository; we
299       conservatively assume that everything else does.  Feel free to
300       add to this list if you are _certain_ something is safe. */
301    if ((strcmp (cmd_name, "checkout") != 0) &&
302        (strcmp (cmd_name, "diff") != 0) &&
303        (strcmp (cmd_name, "update") != 0) &&
304        (strcmp (cmd_name, "history") != 0) &&
305        (strcmp (cmd_name, "editors") != 0) &&
306        (strcmp (cmd_name, "export") != 0) &&
307        (strcmp (cmd_name, "history") != 0) &&
308        (strcmp (cmd_name, "log") != 0) &&
309        (strcmp (cmd_name, "noop") != 0) &&
310        (strcmp (cmd_name, "watchers") != 0) &&
311        (strcmp (cmd_name, "status") != 0))
312    {
313        ret |= CVS_CMD_MODIFIES_REPOSITORY;
314    }
315
316    return ret;
317}
318
319
320static RETSIGTYPE
321main_cleanup (sig)
322    int sig;
323{
324#ifndef DONT_USE_SIGNALS
325    const char *name;
326    char temp[10];
327
328    switch (sig)
329    {
330#ifdef SIGHUP
331    case SIGHUP:
332	name = "hangup";
333	break;
334#endif
335#ifdef SIGINT
336    case SIGINT:
337	name = "interrupt";
338	break;
339#endif
340#ifdef SIGQUIT
341    case SIGQUIT:
342	name = "quit";
343	break;
344#endif
345#ifdef SIGPIPE
346    case SIGPIPE:
347	name = "broken pipe";
348	break;
349#endif
350#ifdef SIGTERM
351    case SIGTERM:
352	name = "termination";
353	break;
354#endif
355    default:
356	/* This case should never be reached, because we list above all
357	   the signals for which we actually establish a signal handler.  */
358	sprintf (temp, "%d", sig);
359	name = temp;
360	break;
361    }
362
363    error (1, 0, "received %s signal", name);
364#endif /* !DONT_USE_SIGNALS */
365}
366
367int
368main (argc, argv)
369    int argc;
370    char **argv;
371{
372    char *CVSroot = CVSROOT_DFLT;
373    extern char *version_string;
374    extern char *config_string;
375    char *cp, *end;
376    const struct cmd *cm;
377    int c, err = 0;
378    int tmpdir_update_env, cvs_update_env;
379    int free_CVSroot = 0;
380    int free_Editor = 0;
381    int free_Tmpdir = 0;
382
383    int help = 0;		/* Has the user asked for help?  This
384				   lets us support the `cvs -H cmd'
385				   convention to give help for cmd. */
386    static struct option long_options[] =
387    {
388        {"help", 0, NULL, 'H'},
389        {"version", 0, NULL, 'v'},
390	{"help-commands", 0, NULL, 1},
391	{"help-synonyms", 0, NULL, 2},
392	{"help-options", 0, NULL, 4},
393	{"allow-root", required_argument, NULL, 3},
394        {0, 0, 0, 0}
395    };
396    /* `getopt_long' stores the option index here, but right now we
397        don't use it. */
398    int option_index = 0;
399    int need_to_create_root = 0;
400
401#ifdef SYSTEM_INITIALIZE
402    /* Hook for OS-specific behavior, for example socket subsystems on
403       NT and OS2 or dealing with windows and arguments on Mac.  */
404    SYSTEM_INITIALIZE (&argc, &argv);
405#endif
406
407#ifdef HAVE_TZSET
408    /* On systems that have tzset (which is almost all the ones I know
409       of), it's a good idea to call it.  */
410    tzset ();
411#endif
412
413    /*
414     * Just save the last component of the path for error messages
415     */
416    program_path = xstrdup (argv[0]);
417#ifdef ARGV0_NOT_PROGRAM_NAME
418    /* On some systems, e.g. VMS, argv[0] is not the name of the command
419       which the user types to invoke the program.  */
420    program_name = "cvs";
421#else
422    program_name = last_component (argv[0]);
423#endif
424
425    /*
426     * Query the environment variables up-front, so that
427     * they can be overridden by command line arguments
428     */
429    cvs_update_env = 0;
430    tmpdir_update_env = *Tmpdir;	/* TMPDIR_DFLT must be set */
431    if ((cp = getenv (TMPDIR_ENV)) != NULL)
432    {
433	Tmpdir = cp;
434	tmpdir_update_env = 0;		/* it's already there */
435    }
436    if ((cp = getenv (EDITOR1_ENV)) != NULL)
437 	Editor = cp;
438    else if ((cp = getenv (EDITOR2_ENV)) != NULL)
439	Editor = cp;
440    else if ((cp = getenv (EDITOR3_ENV)) != NULL)
441	Editor = cp;
442    if ((cp = getenv (CVSROOT_ENV)) != NULL)
443    {
444	CVSroot = cp;
445	cvs_update_env = 0;		/* it's already there */
446    }
447    if (getenv (CVSREAD_ENV) != NULL)
448	cvswrite = 0;
449    if (getenv (CVSREADONLYFS_ENV) != NULL) {
450	readonlyfs = 1;
451	logoff = 1;
452    }
453
454    /* Set this to 0 to force getopt initialization.  getopt() sets
455       this to 1 internally.  */
456    optind = 0;
457
458    /* We have to parse the options twice because else there is no
459       chance to avoid reading the global options from ".cvsrc".  Set
460       opterr to 0 for avoiding error messages about invalid options.
461       */
462    opterr = 0;
463
464    while ((c = getopt_long
465            (argc, argv, "+f", NULL, NULL))
466           != EOF)
467    {
468	if (c == 'f')
469	    use_cvsrc = 0;
470    }
471
472    /*
473     * Scan cvsrc file for global options.
474     */
475    if (use_cvsrc)
476	read_cvsrc (&argc, &argv, "cvs");
477
478    optind = 0;
479    opterr = 1;
480
481    while ((c = getopt_long
482            (argc, argv, "+QqrwtnRlvb:T:e:d:Hfz:s:xa", long_options, &option_index))
483           != EOF)
484    {
485	switch (c)
486	{
487            case 1:
488	        /* --help-commands */
489                usage (cmd_usage);
490                break;
491            case 2:
492	        /* --help-synonyms */
493                usage (cmd_synonyms());
494                break;
495	    case 4:
496		/* --help-options */
497		usage (opt_usage);
498		break;
499	    case 3:
500		/* --allow-root */
501		root_allow_add (optarg);
502		break;
503	    case 'Q':
504		really_quiet = 1;
505		/* FALL THROUGH */
506	    case 'q':
507		quiet = 1;
508		break;
509	    case 'r':
510		cvswrite = 0;
511		break;
512	    case 'w':
513		cvswrite = 1;
514		break;
515	    case 't':
516		trace = 1;
517		break;
518	    case 'R':
519		readonlyfs = 1;
520		logoff = 1;
521		break;
522	    case 'n':
523		noexec = 1;
524	    case 'l':			/* Fall through */
525		logoff = 1;
526		break;
527	    case 'v':
528		/* Having the year here is a good idea, so people have
529		   some idea of how long ago their version of CVS was
530		   released.  */
531		(void) fputs (version_string, stdout);
532		(void) fputs (config_string, stdout);
533		(void) fputs ("\n", stdout);
534		(void) fputs ("\
535Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
536                        Jeff Polk, and other authors\n", stdout);
537		(void) fputs ("\n", stdout);
538		(void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
539		(void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
540		(void) fputs ("\n", stdout);
541
542		(void) fputs ("Specify the --help option for further information about CVS\n", stdout);
543
544		exit (0);
545		break;
546	    case 'b':
547		/* This option used to specify the directory for RCS
548		   executables.  But since we don't run them any more,
549		   this is a noop.  Silently ignore it so that .cvsrc
550		   and scripts and inetd.conf and such can work with
551		   either new or old CVS.  */
552		break;
553	    case 'T':
554		Tmpdir = xstrdup (optarg);
555		free_Tmpdir = 1;
556		tmpdir_update_env = 1;	/* need to update environment */
557		break;
558	    case 'e':
559		Editor = xstrdup (optarg);
560		free_Editor = 1;
561		break;
562	    case 'd':
563		CVSroot = xstrdup (optarg);
564		free_CVSroot = 1;
565		cvs_update_env = 1;	/* need to update environment */
566		break;
567	    case 'H':
568	        help = 1;
569		break;
570            case 'f':
571		use_cvsrc = 0; /* unnecessary, since we've done it above */
572		break;
573	    case 'z':
574#ifdef CLIENT_SUPPORT
575		gzip_level = atoi (optarg);
576		if (gzip_level <= 0 || gzip_level > 9)
577		  error (1, 0,
578			 "gzip compression level must be between 1 and 9");
579#endif
580		/* If no CLIENT_SUPPORT, we just silently ignore the gzip
581		   level, so that users can have it in their .cvsrc and not
582		   cause any trouble.  */
583		break;
584	    case 's':
585		variable_set (optarg);
586		break;
587	    case 'x':
588#ifdef CLIENT_SUPPORT
589	        cvsencrypt = 1;
590#endif /* CLIENT_SUPPORT */
591		/* If no CLIENT_SUPPORT, ignore -x, so that users can
592                   have it in their .cvsrc and not cause any trouble.
593                   If no ENCRYPTION, we still accept -x, but issue an
594                   error if we are being run as a client.  */
595		break;
596	    case 'a':
597#ifdef CLIENT_SUPPORT
598		cvsauthenticate = 1;
599#endif
600		/* If no CLIENT_SUPPORT, ignore -a, so that users can
601                   have it in their .cvsrc and not cause any trouble.
602                   We will issue an error later if stream
603                   authentication is not supported.  */
604		break;
605	    case '?':
606	    default:
607                usage (usg);
608	}
609    }
610
611    argc -= optind;
612    argv += optind;
613    if (argc < 1)
614	usage (usg);
615
616
617    /* Look up the command name. */
618
619    command_name = argv[0];
620    for (cm = cmds; cm->fullname; cm++)
621    {
622	if (cm->nick1 && !strcmp (command_name, cm->nick1))
623	    break;
624	if (cm->nick2 && !strcmp (command_name, cm->nick2))
625	    break;
626	if (!strcmp (command_name, cm->fullname))
627	    break;
628    }
629
630    if (!cm->fullname)
631	usage (cmd_usage);	        /* no match */
632    else
633	command_name = cm->fullname;	/* Global pointer for later use */
634
635    /* This should probably remain a warning, rather than an error,
636       for quite a while.  For one thing the version of VC distributed
637       with GNU emacs 19.34 invokes 'cvs rlog' instead of 'cvs log'.  */
638    if (strcmp (argv[0], "rlog") == 0)
639    {
640	error (0, 0, "warning: the rlog command is deprecated");
641	error (0, 0, "use the synonymous log command instead");
642    }
643
644    if (help)
645	argc = -1;		/* some functions only check for this */
646    else
647    {
648	/* The user didn't ask for help, so go ahead and authenticate,
649           set up CVSROOT, and the rest of it. */
650
651	/* The UMASK environment variable isn't handled with the
652	   others above, since we don't want to signal errors if the
653	   user has asked for help.  This won't work if somebody adds
654	   a command-line flag to set the umask, since we'll have to
655	   parse it before we get here. */
656
657	if ((cp = getenv (CVSUMASK_ENV)) != NULL)
658	{
659	    /* FIXME: Should be accepting symbolic as well as numeric mask.  */
660	    cvsumask = strtol (cp, &end, 8) & 0777;
661	    if (*end != '\0')
662		error (1, errno, "invalid umask value in %s (%s)",
663		       CVSUMASK_ENV, cp);
664	}
665
666#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
667	/* If we are invoked with a single argument "kserver", then we are
668	   running as Kerberos server as root.  Do the authentication as
669	   the very first thing, to minimize the amount of time we are
670	   running as root.  */
671	if (strcmp (command_name, "kserver") == 0)
672	{
673	    kserver_authenticate_connection ();
674
675	    /* Pretend we were invoked as a plain server.  */
676	    command_name = "server";
677	}
678#endif /* HAVE_KERBEROS */
679
680
681#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
682	if (strcmp (command_name, "pserver") == 0)
683	{
684	    /* The reason that --allow-root is not a command option
685	       is mainly the comment in server() about how argc,argv
686	       might be from .cvsrc.  I'm not sure about that, and
687	       I'm not sure it is only true of command options, but
688	       it seems easier to make it a global option.  */
689
690	    /* Gets username and password from client, authenticates, then
691	       switches to run as that user and sends an ACK back to the
692	       client. */
693	    pserver_authenticate_connection ();
694
695	    /* Pretend we were invoked as a plain server.  */
696	    command_name = "server";
697	}
698#endif /* (AUTH_SERVER_SUPPORT || HAVE_GSSAPI) && SERVER_SUPPORT */
699
700#ifdef SERVER_SUPPORT
701	server_active = strcmp (command_name, "server") == 0;
702
703	/* Fiddling with CVSROOT doesn't make sense if we're running
704           in server mode, since the client will send the repository
705           directory after the connection is made. */
706
707	if (!server_active)
708#endif
709	{
710	    char *CVSADM_Root;
711
712	    /* See if we are able to find a 'better' value for CVSroot
713	       in the CVSADM_ROOT directory. */
714
715	    CVSADM_Root = NULL;
716
717	    /* "cvs import" shouldn't check CVS/Root; in general it
718	       ignores CVS directories and CVS/Root is likely to
719	       specify a different repository than the one we are
720	       importing to.  */
721
722	    if (lookup_command_attribute (command_name)
723                & CVS_CMD_IGNORE_ADMROOT)
724            {
725		CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
726            }
727
728	    if (CVSADM_Root != NULL)
729	    {
730		if (CVSroot == NULL || !cvs_update_env)
731		{
732		    CVSroot = CVSADM_Root;
733		    cvs_update_env = 1;	/* need to update environment */
734		}
735		/* Let -d override CVS/Root file.  The user might want
736		   to change the access method, use a different server
737		   (if there are two server machines which share the
738		   repository using a networked file system), etc.  */
739		else if (
740#ifdef CLIENT_SUPPORT
741		         !getenv ("CVS_IGNORE_REMOTE_ROOT") &&
742#endif
743			 strcmp (CVSroot, CVSADM_Root) != 0)
744		{
745		    /* Once we have verified that this root is usable,
746		       we will want to write it into CVS/Root.
747
748		       Don't do it for the "login" command, however.
749		       Consider: if the user executes "cvs login" with
750		       the working directory inside an already checked
751		       out module, we'd incorrectly change the
752		       CVS/Root file to reflect the CVSROOT of the
753		       "cvs login" command.  Ahh, the things one
754		       discovers. */
755
756		    if (lookup_command_attribute (command_name)
757                        & CVS_CMD_USES_WORK_DIR)
758                    {
759			need_to_create_root = 1;
760                    }
761
762		}
763	    }
764
765	    /* Now we've reconciled CVSROOT from the command line, the
766               CVS/Root file, and the environment variable.  Do the
767               last sanity checks on the variable. */
768
769	    if (! CVSroot)
770	    {
771		error (0, 0,
772		       "No CVSROOT specified!  Please use the `-d' option");
773		error (1, 0,
774		       "or set the %s environment variable.", CVSROOT_ENV);
775	    }
776
777	    if (! *CVSroot)
778	    {
779		error (0, 0,
780		       "CVSROOT is set but empty!  Make sure that the");
781		error (0, 0,
782		       "specification of CVSROOT is legal, either via the");
783		error (0, 0,
784		       "`-d' option, the %s environment variable, or the",
785		       CVSROOT_ENV);
786		error (1, 0,
787		       "CVS/Root file (if any).");
788	    }
789
790	    /* Now we're 100% sure that we have a valid CVSROOT
791	       variable.  Parse it to see if we're supposed to do
792	       remote accesses or use a special access method. */
793
794	    if (parse_cvsroot (CVSroot))
795		error (1, 0, "Bad CVSROOT.");
796
797	    /*
798	     * Check to see if we can write into the history file.  If not,
799	     * we assume that we can't work in the repository.
800	     * BUT, only if the history file exists.
801	     */
802
803	    if (!client_active)
804	    {
805		char *path;
806		int save_errno;
807
808		path = xmalloc (strlen (CVSroot_directory)
809				+ sizeof (CVSROOTADM)
810				+ 20
811				+ sizeof (CVSROOTADM_HISTORY));
812		(void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
813		if (!isaccessible (path, R_OK | X_OK))
814		{
815		    save_errno = errno;
816		    /* If this is "cvs init", the root need not exist yet.  */
817		    if (strcmp (command_name, "init") != 0)
818		    {
819			error (1, save_errno, "%s", path);
820		    }
821		}
822		(void) strcat (path, "/");
823		(void) strcat (path, CVSROOTADM_HISTORY);
824		if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
825		{
826		    save_errno = errno;
827		    error (0, 0, "Sorry, you don't have read/write access to the history file");
828		    error (1, save_errno, "%s", path);
829		}
830		free (path);
831	    }
832
833#ifdef HAVE_PUTENV
834	    /* Update the CVSROOT environment variable if necessary. */
835
836	    if (cvs_update_env)
837	    {
838		char *env;
839		env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
840			       + 1 + 1);
841		(void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
842		(void) putenv (env);
843		/* do not free env, as putenv has control of it */
844	    }
845#endif
846	}
847
848	/* This is only used for writing into the history file.  For
849	   remote connections, it might be nice to have hostname
850	   and/or remote path, on the other hand I'm not sure whether
851	   it is worth the trouble.  */
852
853#ifdef SERVER_SUPPORT
854	if (server_active)
855	    CurDir = xstrdup ("<remote>");
856	else
857#endif
858	{
859	    CurDir = xgetwd ();
860            if (CurDir == NULL)
861		error (1, errno, "cannot get working directory");
862	}
863
864	if (Tmpdir == NULL || Tmpdir[0] == '\0')
865	    Tmpdir = "/tmp";
866
867#ifdef HAVE_PUTENV
868	if (tmpdir_update_env)
869	{
870	    char *env;
871	    env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1);
872	    (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir);
873	    (void) putenv (env);
874	    /* do not free env, as putenv has control of it */
875	}
876	{
877	    char *env;
878	    env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */
879	    (void) sprintf (env, "CVS_PID=%ld", (long) getpid ());
880	    (void) putenv (env);
881	}
882#endif
883
884#ifndef DONT_USE_SIGNALS
885	/* make sure we clean up on error */
886#ifdef SIGHUP
887	(void) SIG_register (SIGHUP, main_cleanup);
888	(void) SIG_register (SIGHUP, Lock_Cleanup);
889#endif
890#ifdef SIGINT
891	(void) SIG_register (SIGINT, main_cleanup);
892	(void) SIG_register (SIGINT, Lock_Cleanup);
893#endif
894#ifdef SIGQUIT
895	(void) SIG_register (SIGQUIT, main_cleanup);
896	(void) SIG_register (SIGQUIT, Lock_Cleanup);
897#endif
898#ifdef SIGPIPE
899	(void) SIG_register (SIGPIPE, main_cleanup);
900	(void) SIG_register (SIGPIPE, Lock_Cleanup);
901#endif
902#ifdef SIGTERM
903	(void) SIG_register (SIGTERM, main_cleanup);
904	(void) SIG_register (SIGTERM, Lock_Cleanup);
905#endif
906#endif /* !DONT_USE_SIGNALS */
907
908	gethostname(hostname, sizeof (hostname));
909
910#ifdef KLUDGE_FOR_WNT_TESTSUITE
911	/* Probably the need for this will go away at some point once
912	   we call fflush enough places (e.g. fflush (stdout) in
913	   cvs_outerr).  */
914	(void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
915	(void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
916#endif /* KLUDGE_FOR_WNT_TESTSUITE */
917
918	if (use_cvsrc)
919	    read_cvsrc (&argc, &argv, command_name);
920
921	/* Parse the CVSROOT/config file, but only for local.  For the
922	   server, we parse it after we know $CVSROOT.  For the
923	   client, it doesn't get parsed at all, obviously.  The
924	   presence of the parse_config call here is not mean to
925	   predetermine whether CVSROOT/config overrides things from
926	   read_cvsrc and other such places or vice versa.  That sort
927	   of thing probably needs more thought.  */
928	if (1
929#ifdef SERVER_SUPPORT
930	    && !server_active
931#endif
932#ifdef CLIENT_SUPPORT
933	    && !client_active
934#endif
935	    )
936	{
937	    /* If there was an error parsing the config file, parse_config
938	       already printed an error.  We keep going.  Why?  Because
939	       if we didn't, then there would be no way to check in a new
940	       CVSROOT/config file to fix the broken one!  */
941	    parse_config (CVSroot_directory);
942
943	    /* Now is a convenient time to read CVSROOT/options */
944	    parseopts(CVSroot_directory);
945	}
946    } /* end of stuff that gets done if the user DOESN'T ask for help */
947
948    err = (*(cm->func)) (argc, argv);
949
950    if (need_to_create_root)
951    {
952	/* Update the CVS/Root file.  We might want to do this in
953	   all directories that we recurse into, but currently we
954	   don't.  Note that if there is an error writing the file,
955	   we give an error/warning.  This is so if users try to rewrite
956	   CVS/Root with the -d option (a documented feature), they will
957	   either succeed, or be told why it didn't work.  */
958	Create_Root (NULL, CVSroot);
959    }
960
961    Lock_Cleanup ();
962
963    free (program_path);
964    if (free_CVSroot)
965	free (CVSroot);
966    if (free_Editor)
967	free (Editor);
968    if (free_Tmpdir)
969	free (Tmpdir);
970    root_allow_free ();
971
972#ifdef SYSTEM_CLEANUP
973    /* Hook for OS-specific behavior, for example socket subsystems on
974       NT and OS2 or dealing with windows and arguments on Mac.  */
975    SYSTEM_CLEANUP ();
976#endif
977
978    /* This is exit rather than return because apparently that keeps
979       some tools which check for memory leaks happier.  */
980    exit (err ? EXIT_FAILURE : 0);
981	/* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy.  */
982	return 0;
983}
984
985char *
986Make_Date (rawdate)
987    char *rawdate;
988{
989    struct tm *ftm;
990    time_t unixtime;
991    char date[MAXDATELEN];
992    char *ret;
993
994    unixtime = get_date (rawdate, (struct timeb *) NULL);
995    if (unixtime == (time_t) - 1)
996	error (1, 0, "Can't parse date/time: %s", rawdate);
997
998    ftm = gmtime (&unixtime);
999    if (ftm == NULL)
1000	/* This is a system, like VMS, where the system clock is in local
1001	   time.  Hopefully using localtime here matches the "zero timezone"
1002	   hack I added to get_date.  */
1003	ftm = localtime (&unixtime);
1004
1005    (void) sprintf (date, DATEFORM,
1006		    ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1007		    ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1008		    ftm->tm_min, ftm->tm_sec);
1009    ret = xstrdup (date);
1010    return (ret);
1011}
1012
1013void
1014usage (cpp)
1015    register const char *const *cpp;
1016{
1017    (void) fprintf (stderr, *cpp++, program_name, command_name);
1018    for (; *cpp; cpp++)
1019	(void) fprintf (stderr, *cpp);
1020    error_exit ();
1021}
1022
1023void
1024parseopts(root)
1025    const char *root;
1026{
1027    char path[PATH_MAX];
1028    int save_errno;
1029    char buf[1024];
1030    const char *p;
1031    char *q;
1032    FILE *fp;
1033
1034    if (root == NULL) {
1035	printf("no CVSROOT in parseopts\n");
1036	return;
1037    }
1038    p = strchr (root, ':');
1039    if (p)
1040	p++;
1041    else
1042	p = root;
1043    if (p == NULL) {
1044	printf("mangled CVSROOT in parseopts\n");
1045	return;
1046    }
1047    (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
1048    if ((fp = fopen(path, "r")) != NULL) {
1049	while (fgets(buf, sizeof buf, fp) != NULL) {
1050	    if (buf[0] == '#')
1051		continue;
1052	    q = strrchr(buf, '\n');
1053	    if (q)
1054		*q = '\0';
1055
1056	    if (!strncmp(buf, "tag=", 4)) {
1057		char *what;
1058		char *rcs_localid;
1059
1060		rcs_localid = buf + 4;
1061		RCS_setlocalid(rcs_localid);
1062	    }
1063	    if (!strncmp(buf, "tagexpand=", 10)) {
1064		char *what;
1065		char *rcs_incexc;
1066
1067		rcs_incexc = buf + 10;
1068		RCS_setincexc(rcs_incexc);
1069	    }
1070	    /*
1071	     * OpenBSD has a "umask=" and "dlimit=" command, we silently
1072	     * ignore them here since they are not much use to us.  cvsumask
1073	     * defaults to 002 already, and the dlimit (data size limit)
1074	     * should really be handled elsewhere (eg: login.conf).
1075	     */
1076	}
1077	fclose(fp);
1078    }
1079}
1080