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