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