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