]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/main.c
This commit was generated by cvs2svn to compensate for changes in r162503,
[FreeBSD/FreeBSD.git] / contrib / cvs / src / main.c
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$
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
23 extern int gethostname ();
24 #endif
25
26 const char *program_name;
27 const char *program_path;
28 const char *cvs_cmd_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
37 char hostname[MAXHOSTNAMELEN];
38
39 int use_editor = 1;
40 int use_cvsrc = 1;
41 int cvswrite = !CVSREAD_DFLT;
42 int really_quiet = 0;
43 int quiet = 0;
44 int trace = 0;
45 int noexec = 0;
46 int readonlyfs = 0;
47 int require_real_user = 0;
48 int 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). */
53 int top_level_admin = 0;
54
55 mode_t cvsumask = UMASK_DFLT;
56
57 char *CurDir;
58
59 /*
60  * Defaults, for the environment variables that are not set
61  */
62 char *Tmpdir = TMPDIR_DFLT;
63 char *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.  */
68 List *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  */
76 static char *current_root = NULL;
77
78
79 static 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",      "blame",     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
153 static 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
199 static 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
245 static 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     "    -n           Do not execute anything that will change the disk.\n",
256     "    -t           Show trace of program execution -- try with -n.\n",
257     "    -R           Assume repository is read-only, such as CDROM\n",
258     "    -v           CVS version and copyright.\n",
259     "    -T tmpdir    Use 'tmpdir' for temporary files.\n",
260     "    -e editor    Use 'editor' for editing log information.\n",
261     "    -d CVS_root  Overrides $CVSROOT as the root of the CVS tree.\n",
262     "    -f           Do not use the ~/.cvsrc file.\n",
263 #ifdef CLIENT_SUPPORT
264     "    -z #         Use compression level '#' for net traffic.\n",
265 #ifdef ENCRYPTION
266     "    -x           Encrypt all net traffic.\n",
267 #endif
268     "    -a           Authenticate all net traffic.\n",
269 #endif
270     "    -s VAR=VAL   Set CVS user variable.\n",
271     "(Specify the --help option for a list of other help options)\n",
272     NULL
273 };
274
275
276 static int
277 set_root_directory (p, ignored)
278     Node *p;
279     void *ignored;
280 {
281     if (current_root == NULL && p->data == NULL)
282     {
283         current_root = p->key;
284         return 1;
285     }
286     return 0;
287 }
288
289
290 static const char * const*
291 cmd_synonyms ()
292 {
293     char ** synonyms;
294     char ** line;
295     const struct cmd *c = &cmds[0];
296     /* Three more for title, "specify --help" line, and NULL.  */
297     int numcmds = 3;
298
299     while (c->fullname != NULL)
300     {
301         numcmds++;
302         c++;
303     }
304     
305     synonyms = (char **) xmalloc(numcmds * sizeof(char *));
306     line = synonyms;
307     *line++ = "CVS command synonyms are:\n";
308     for (c = &cmds[0]; c->fullname != NULL; c++)
309     {
310         if (c->nick1 || c->nick2)
311         {
312             *line = xmalloc (strlen (c->fullname)
313                              + (c->nick1 != NULL ? strlen (c->nick1) : 0)
314                              + (c->nick2 != NULL ? strlen (c->nick2) : 0)
315                              + 40);
316             sprintf(*line, "        %-12s %s %s\n", c->fullname,
317                     c->nick1 ? c->nick1 : "",
318                     c->nick2 ? c->nick2 : "");
319             line++;
320         }
321     }
322     *line++ = "(Specify the --help option for a list of other help options)\n";
323     *line = NULL;
324     
325     return (const char * const*) synonyms; /* will never be freed */
326 }
327
328
329 unsigned long int
330 lookup_command_attribute (cmd_name)
331      char *cmd_name;
332 {
333     const struct cmd *cm;
334
335     for (cm = cmds; cm->fullname; cm++)
336     {
337         if (strcmp (cmd_name, cm->fullname) == 0)
338             break;
339     }
340     if (!cm->fullname)
341         error (1, 0, "unknown command: %s", cmd_name);
342     return cm->attr;
343 }
344
345
346 static RETSIGTYPE
347 main_cleanup (sig)
348     int sig;
349 {
350 #ifndef DONT_USE_SIGNALS
351     const char *name;
352     char temp[10];
353
354     switch (sig)
355     {
356 #ifdef SIGABRT
357     case SIGABRT:
358         name = "abort";
359         break;
360 #endif
361 #ifdef SIGHUP
362     case SIGHUP:
363         name = "hangup";
364         break;
365 #endif
366 #ifdef SIGINT
367     case SIGINT:
368         name = "interrupt";
369         break;
370 #endif
371 #ifdef SIGQUIT
372     case SIGQUIT:
373         name = "quit";
374         break;
375 #endif
376 #ifdef SIGPIPE
377     case SIGPIPE:
378         name = "broken pipe";
379         break;
380 #endif
381 #ifdef SIGTERM
382     case SIGTERM:
383         name = "termination";
384         break;
385 #endif
386     default:
387         /* This case should never be reached, because we list above all
388            the signals for which we actually establish a signal handler.  */
389         sprintf (temp, "%d", sig);
390         name = temp;
391         break;
392     }
393
394     error (1, 0, "received %s signal", name);
395 #endif /* !DONT_USE_SIGNALS */
396 }
397
398 int
399 main (argc, argv)
400     int argc;
401     char **argv;
402 {
403     char *CVSroot = CVSROOT_DFLT;
404     char *cp, *end;
405     const struct cmd *cm;
406     int c, err = 0;
407     int tmpdir_update_env, cvs_update_env;
408     int free_CVSroot = 0;
409     int free_Editor = 0;
410     int free_Tmpdir = 0;
411
412     int help = 0;               /* Has the user asked for help?  This
413                                    lets us support the `cvs -H cmd'
414                                    convention to give help for cmd. */
415     static const char short_options[] = "+QqgrwtnRvb:T:e:d:Hfz:s:xaU";
416     static struct option long_options[] =
417     {
418         {"help", 0, NULL, 'H'},
419         {"version", 0, NULL, 'v'},
420         {"help-commands", 0, NULL, 1},
421         {"help-synonyms", 0, NULL, 2},
422         {"help-options", 0, NULL, 4},
423         {"allow-root", required_argument, NULL, 3},
424         {0, 0, 0, 0}
425     };
426     /* `getopt_long' stores the option index here, but right now we
427         don't use it. */
428     int option_index = 0;
429
430 #ifdef SYSTEM_INITIALIZE
431     /* Hook for OS-specific behavior, for example socket subsystems on
432        NT and OS2 or dealing with windows and arguments on Mac.  */
433     SYSTEM_INITIALIZE (&argc, &argv);
434 #endif
435
436 #ifdef HAVE_TZSET
437     /* On systems that have tzset (which is almost all the ones I know
438        of), it's a good idea to call it.  */
439     tzset ();
440 #endif
441
442     /*
443      * Just save the last component of the path for error messages
444      */
445     program_path = xstrdup (argv[0]);
446 #ifdef ARGV0_NOT_PROGRAM_NAME
447     /* On some systems, e.g. VMS, argv[0] is not the name of the command
448        which the user types to invoke the program.  */
449     program_name = "cvs";
450 #else
451     program_name = last_component (argv[0]);
452 #endif
453
454     /*
455      * Query the environment variables up-front, so that
456      * they can be overridden by command line arguments
457      */
458     cvs_update_env = 0;
459     tmpdir_update_env = *Tmpdir;        /* TMPDIR_DFLT must be set */
460     if ((cp = getenv (TMPDIR_ENV)) != NULL)
461     {
462         Tmpdir = cp;
463         tmpdir_update_env = 0;          /* it's already there */
464     }
465     if ((cp = getenv (EDITOR1_ENV)) != NULL)
466         Editor = cp;
467     else if ((cp = getenv (EDITOR2_ENV)) != NULL)
468         Editor = cp;
469     else if ((cp = getenv (EDITOR3_ENV)) != NULL)
470         Editor = cp;
471     if ((cp = getenv (CVSROOT_ENV)) != NULL)
472     {
473         CVSroot = cp;
474         cvs_update_env = 0;             /* it's already there */
475     }
476     if (getenv (CVSREAD_ENV) != NULL)
477         cvswrite = 0;
478     if (getenv (CVSREADONLYFS_ENV) != NULL) {
479         readonlyfs = 1;
480         logoff = 1;
481     }
482
483     prepend_default_options (getenv ("CVS_OPTIONS"), &argc, &argv);
484
485     /* Set this to 0 to force getopt initialization.  getopt() sets
486        this to 1 internally.  */
487     optind = 0;
488
489     /* We have to parse the options twice because else there is no
490        chance to avoid reading the global options from ".cvsrc".  Set
491        opterr to 0 for avoiding error messages about invalid options.
492        */
493     opterr = 0;
494
495     while ((c = getopt_long
496             (argc, argv, short_options, long_options, &option_index))
497            != EOF)
498     {
499         if (c == 'f')
500             use_cvsrc = 0;
501     }
502
503     /*
504      * Scan cvsrc file for global options.
505      */
506     if (use_cvsrc)
507         read_cvsrc (&argc, &argv, "cvs");
508
509     optind = 0;
510     opterr = 1;
511
512     while ((c = getopt_long
513             (argc, argv, short_options, long_options, &option_index))
514            != EOF)
515     {
516         switch (c)
517         {
518             case 1:
519                 /* --help-commands */
520                 usage (cmd_usage);
521                 break;
522             case 2:
523                 /* --help-synonyms */
524                 usage (cmd_synonyms());
525                 break;
526             case 4:
527                 /* --help-options */
528                 usage (opt_usage);
529                 break;
530             case 3:
531                 /* --allow-root */
532                 root_allow_add (optarg);
533                 break;
534             case 'Q':
535                 really_quiet = 1;
536                 /* FALL THROUGH */
537             case 'q':
538                 quiet = 1;
539                 break;
540             case 'r':
541                 cvswrite = 0;
542                 break;
543             case 'w':
544                 cvswrite = 1;
545                 break;
546             case 'g':
547                 /*
548                  * force full group write perms (used for shared checked-out
549                  * source trees, see manual page)
550                  */
551                 umask(umask(077) & 007);
552                 break;
553             case 't':
554                 trace = 1;
555                 break;
556             case 'R':
557                 readonlyfs = 1;
558                 logoff = 1;
559                 break;
560             case 'n':
561                 noexec = 1;
562                 logoff = 1;
563                 break;
564             case 'v':
565                 (void) fputs ("\n", stdout);
566                 version (0, (char **) NULL);    
567                 (void) fputs ("\n", stdout);
568                 (void) fputs ("\
569 Copyright (c) 1989-2004 Brian Berliner, david d `zoo' zuhn, \n\
570                         Jeff Polk, and other authors\n", stdout);
571                 (void) fputs ("\n", stdout);
572                 (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
573                 (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
574                 (void) fputs ("\n", stdout);
575
576                 (void) fputs ("Specify the --help option for further information about CVS\n", stdout);
577
578                 exit (0);
579                 break;
580             case 'b':
581                 /* This option used to specify the directory for RCS
582                    executables.  But since we don't run them any more,
583                    this is a noop.  Silently ignore it so that .cvsrc
584                    and scripts and inetd.conf and such can work with
585                    either new or old CVS.  */
586                 break;
587             case 'T':
588                 Tmpdir = xstrdup (optarg);
589                 free_Tmpdir = 1;
590                 tmpdir_update_env = 1;  /* need to update environment */
591                 break;
592             case 'e':
593                 Editor = xstrdup (optarg);
594                 free_Editor = 1;
595                 break;
596             case 'd':
597                 if (CVSroot_cmdline != NULL)
598                     free (CVSroot_cmdline);
599                 CVSroot_cmdline = xstrdup (optarg);
600                 if (free_CVSroot)
601                     free (CVSroot);
602                 CVSroot = xstrdup (optarg);
603                 free_CVSroot = 1;
604                 cvs_update_env = 1;     /* need to update environment */
605                 break;
606             case 'H':
607                 help = 1;
608                 break;
609             case 'f':
610                 use_cvsrc = 0; /* unnecessary, since we've done it above */
611                 break;
612             case 'z':
613 #ifdef CLIENT_SUPPORT
614                 gzip_level = strtol (optarg, &end, 10);
615                 if (*end != '\0' || gzip_level < 0 || gzip_level > 9)
616                   error (1, 0,
617                          "gzip compression level must be between 0 and 9");
618 #endif /* CLIENT_SUPPORT */
619                 /* If no CLIENT_SUPPORT, we just silently ignore the gzip
620                  * level, so that users can have it in their .cvsrc and not
621                  * cause any trouble.
622                  *
623                  * We still parse the argument to -z for correctness since
624                  * one user complained of being bitten by a run of
625                  * `cvs -z -n up' which read -n as the argument to -z without
626                  * complaining.  */
627                 break;
628             case 's':
629                 variable_set (optarg);
630                 break;
631             case 'x':
632 #ifdef CLIENT_SUPPORT
633                 cvsencrypt = 1;
634 #endif /* CLIENT_SUPPORT */
635                 /* If no CLIENT_SUPPORT, ignore -x, so that users can
636                    have it in their .cvsrc and not cause any trouble.
637                    If no ENCRYPTION, we still accept -x, but issue an
638                    error if we are being run as a client.  */
639                 break;
640             case 'a':
641 #ifdef CLIENT_SUPPORT
642                 cvsauthenticate = 1;
643 #endif
644                 /* If no CLIENT_SUPPORT, ignore -a, so that users can
645                    have it in their .cvsrc and not cause any trouble.
646                    We will issue an error later if stream
647                    authentication is not supported.  */
648                 break;
649             case 'U':
650 #ifdef SERVER_SUPPORT
651                 require_real_user = 1;
652 #endif
653                 break;
654             case '?':
655             default:
656                 usage (usg);
657         }
658     }
659
660     argc -= optind;
661     argv += optind;
662     if (argc < 1)
663         usage (usg);
664
665
666     /* Look up the command name. */
667
668     cvs_cmd_name = argv[0];
669     for (cm = cmds; cm->fullname; cm++)
670     {
671         if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1))
672             break;
673         if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2))
674             break;
675         if (!strcmp (cvs_cmd_name, cm->fullname))
676             break;
677     }
678
679     if (!cm->fullname)
680     {
681         fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name);
682         usage (cmd_usage);
683     }
684     else
685         cvs_cmd_name = cm->fullname;    /* Global pointer for later use */
686
687     if (help)
688     {
689         argc = -1;              /* some functions only check for this */
690         err = (*(cm->func)) (argc, argv);
691     }
692     else
693     {
694         /* The user didn't ask for help, so go ahead and authenticate,
695            set up CVSROOT, and the rest of it. */
696
697         /* The UMASK environment variable isn't handled with the
698            others above, since we don't want to signal errors if the
699            user has asked for help.  This won't work if somebody adds
700            a command-line flag to set the umask, since we'll have to
701            parse it before we get here. */
702
703         if ((cp = getenv (CVSUMASK_ENV)) != NULL)
704         {
705             /* FIXME: Should be accepting symbolic as well as numeric mask.  */
706             cvsumask = strtol (cp, &end, 8) & 0777;
707             if (*end != '\0')
708                 error (1, errno, "invalid umask value in %s (%s)",
709                        CVSUMASK_ENV, cp);
710         }
711
712 #ifdef SERVER_SUPPORT
713
714 # ifdef HAVE_KERBEROS
715         /* If we are invoked with a single argument "kserver", then we are
716            running as Kerberos server as root.  Do the authentication as
717            the very first thing, to minimize the amount of time we are
718            running as root.  */
719         if (strcmp (cvs_cmd_name, "kserver") == 0)
720         {
721             kserver_authenticate_connection ();
722
723             /* Pretend we were invoked as a plain server.  */
724             cvs_cmd_name = "server";
725         }
726 # endif /* HAVE_KERBEROS */
727
728
729 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
730         if (strcmp (cvs_cmd_name, "pserver") == 0)
731         {
732             /* The reason that --allow-root is not a command option
733                is mainly the comment in server() about how argc,argv
734                might be from .cvsrc.  I'm not sure about that, and
735                I'm not sure it is only true of command options, but
736                it seems easier to make it a global option.  */
737
738             /* Gets username and password from client, authenticates, then
739                switches to run as that user and sends an ACK back to the
740                client. */
741             pserver_authenticate_connection ();
742       
743             /* Pretend we were invoked as a plain server.  */
744             cvs_cmd_name = "server";
745         }
746 # endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
747
748         server_active = strcmp (cvs_cmd_name, "server") == 0;
749
750 #endif /* SERVER_SUPPORT */
751
752         /* This is only used for writing into the history file.  For
753            remote connections, it might be nice to have hostname
754            and/or remote path, on the other hand I'm not sure whether
755            it is worth the trouble.  */
756
757 #ifdef SERVER_SUPPORT
758         if (server_active)
759             CurDir = xstrdup ("<remote>");
760         else
761 #endif
762         {
763             CurDir = xgetwd ();
764             if (CurDir == NULL)
765                 error (1, errno, "cannot get working directory");
766         }
767
768         if (Tmpdir == NULL || Tmpdir[0] == '\0')
769             Tmpdir = "/tmp";
770
771 #ifdef HAVE_PUTENV
772         if (tmpdir_update_env)
773         {
774             char *env;
775             env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1);
776             (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir);
777             (void) putenv (env);
778             /* do not free env, as putenv has control of it */
779         }
780         {
781             char *env;
782             env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */
783             (void) sprintf (env, "CVS_PID=%ld", (long) getpid ());
784             (void) putenv (env);
785         }
786 #endif
787
788 #ifndef DONT_USE_SIGNALS
789         /* make sure we clean up on error */
790 #ifdef SIGABRT
791         (void) SIG_register (SIGABRT, main_cleanup);
792 #endif
793 #ifdef SIGHUP
794         (void) SIG_register (SIGHUP, main_cleanup);
795 #endif
796 #ifdef SIGINT
797         (void) SIG_register (SIGINT, main_cleanup);
798 #endif
799 #ifdef SIGQUIT
800         (void) SIG_register (SIGQUIT, main_cleanup);
801 #endif
802 #ifdef SIGPIPE
803         (void) SIG_register (SIGPIPE, main_cleanup);
804 #endif
805 #ifdef SIGTERM
806         (void) SIG_register (SIGTERM, main_cleanup);
807 #endif
808 #endif /* !DONT_USE_SIGNALS */
809
810         gethostname(hostname, sizeof (hostname));
811
812 #ifdef KLUDGE_FOR_WNT_TESTSUITE
813         /* Probably the need for this will go away at some point once
814            we call fflush enough places (e.g. fflush (stdout) in
815            cvs_outerr).  */
816         (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
817         (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
818 #endif /* KLUDGE_FOR_WNT_TESTSUITE */
819
820         if (use_cvsrc)
821             read_cvsrc (&argc, &argv, cvs_cmd_name);
822
823 #ifdef SERVER_SUPPORT
824         /* Fiddling with CVSROOT doesn't make sense if we're running
825                in server mode, since the client will send the repository
826                directory after the connection is made. */
827
828         if (!server_active)
829 #endif
830         {
831             char *CVSADM_Root;
832             
833             /* See if we are able to find a 'better' value for CVSroot
834                in the CVSADM_ROOT directory. */
835
836             CVSADM_Root = NULL;
837
838             /* "cvs import" shouldn't check CVS/Root; in general it
839                ignores CVS directories and CVS/Root is likely to
840                specify a different repository than the one we are
841                importing to.  */
842
843             if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT)
844
845                 /* -d overrides CVS/Root, so don't give an error if the
846                    latter points to a nonexistent repository.  */
847                 && CVSroot_cmdline == NULL)
848             {
849                 CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
850             }
851
852             if (CVSADM_Root != NULL)
853             {
854                 if (CVSroot == NULL || !cvs_update_env)
855                 {
856                     CVSroot = CVSADM_Root;
857                     cvs_update_env = 1; /* need to update environment */
858                 }
859             }
860
861             /* Now we've reconciled CVSROOT from the command line, the
862                CVS/Root file, and the environment variable.  Do the
863                last sanity checks on the variable. */
864
865             if (! CVSroot)
866             {
867                 error (0, 0,
868                        "No CVSROOT specified!  Please use the `-d' option");
869                 error (1, 0,
870                        "or set the %s environment variable.", CVSROOT_ENV);
871             }
872             
873             if (! *CVSroot)
874             {
875                 error (0, 0,
876                        "CVSROOT is set but empty!  Make sure that the");
877                 error (0, 0,
878                        "specification of CVSROOT is valid, either via the");
879                 error (0, 0,
880                        "`-d' option, the %s environment variable, or the",
881                        CVSROOT_ENV);
882                 error (1, 0,
883                        "CVS/Root file (if any).");
884             }
885         }
886
887         /* Here begins the big loop over unique cvsroot values.  We
888            need to call do_recursion once for each unique value found
889            in CVS/Root.  Prime the list with the current value. */
890
891         /* Create the list. */
892         assert (root_directories == NULL);
893         root_directories = getlist ();
894
895         /* Prime it. */
896         if (CVSroot != NULL)
897         {
898             Node *n;
899             n = getnode ();
900             n->type = NT_UNKNOWN;
901             n->key = xstrdup (CVSroot);
902             n->data = NULL;
903
904             if (addnode (root_directories, n))
905                 error (1, 0, "cannot add initial CVSROOT %s", n->key);
906         }
907
908         assert (current_root == NULL);
909
910         /* If we're running the server, we want to execute this main
911            loop once and only once (we won't be serving multiple roots
912            from this connection, so there's no need to do it more than
913            once).  To get out of the loop, we perform a "break" at the
914            end of things.  */
915
916         while (
917 #ifdef SERVER_SUPPORT
918                server_active ||
919 #endif
920                walklist (root_directories, set_root_directory, NULL)
921                )
922         {
923 #ifdef SERVER_SUPPORT
924             /* Fiddling with CVSROOT doesn't make sense if we're running
925                in server mode, since the client will send the repository
926                directory after the connection is made. */
927
928             if (!server_active)
929 #endif
930             {
931                 /* Now we're 100% sure that we have a valid CVSROOT
932                    variable.  Parse it to see if we're supposed to do
933                    remote accesses or use a special access method. */
934
935                 if (current_parsed_root != NULL)
936                     free_cvsroot_t (current_parsed_root);
937                 if ((current_parsed_root = parse_cvsroot (current_root)) == NULL)
938                     error (1, 0, "Bad CVSROOT: `%s'.", current_root);
939
940                 if (trace)
941                     fprintf (stderr, "%s-> main loop with CVSROOT=%s\n",
942                            CLIENT_SERVER_STR, current_root);
943
944                 /*
945                  * Check to see if the repository exists.
946                  */
947 #ifdef CLIENT_SUPPORT
948                 if (!current_parsed_root->isremote)
949 #endif  /* CLIENT_SUPPORT */
950                 {
951                     char *path;
952                     int save_errno;
953
954                     path = xmalloc (strlen (current_parsed_root->directory)
955                                     + sizeof (CVSROOTADM)
956                                     + 2);
957                     (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
958                     if (!isaccessible (path, R_OK | X_OK))
959                     {
960                         save_errno = errno;
961                         /* If this is "cvs init", the root need not exist yet.  */
962                         if (strcmp (cvs_cmd_name, "init") != 0)
963                         {
964                             error (1, save_errno, "%s", path);
965                         }
966                     }
967                     free (path);
968                 }
969
970 #ifdef HAVE_PUTENV
971                 /* Update the CVSROOT environment variable if necessary. */
972                 /* FIXME (njc): should we always set this with the CVSROOT from the command line? */
973                 if (cvs_update_env)
974                 {
975                     static char *prev;
976                     char *env;
977                     env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
978                                    + 1 + 1);
979                     (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
980                     (void) putenv (env);
981                     /* do not free env yet, as putenv has control of it */
982                     /* but do free the previous value, if any */
983                     if (prev != NULL)
984                         free (prev);
985                     prev = env;
986                 }
987 #endif
988             }
989         
990             /* Parse the CVSROOT/config file, but only for local.  For the
991                server, we parse it after we know $CVSROOT.  For the
992                client, it doesn't get parsed at all, obviously.  The
993                presence of the parse_config call here is not mean to
994                predetermine whether CVSROOT/config overrides things from
995                read_cvsrc and other such places or vice versa.  That sort
996                of thing probably needs more thought.  */
997             if (1
998 #ifdef SERVER_SUPPORT
999                 && !server_active
1000 #endif
1001 #ifdef CLIENT_SUPPORT
1002                 && !current_parsed_root->isremote
1003 #endif
1004                 )
1005             {
1006                 /* If there was an error parsing the config file, parse_config
1007                    already printed an error.  We keep going.  Why?  Because
1008                    if we didn't, then there would be no way to check in a new
1009                    CVSROOT/config file to fix the broken one!  */
1010                 parse_config (current_parsed_root->directory);
1011
1012                 /* Now is a convenient time to read CVSROOT/options */
1013                 parseopts(current_parsed_root->directory);
1014             }
1015
1016 #ifdef CLIENT_SUPPORT
1017             /* Need to check for current_parsed_root != NULL here since
1018              * we could still be in server mode before the server function
1019              * gets called below and sets the root
1020              */
1021             if (current_parsed_root != NULL && current_parsed_root->isremote)
1022             {
1023                 /* Create a new list for directory names that we've
1024                    sent to the server. */
1025                 if (dirs_sent_to_server != NULL)
1026                     dellist (&dirs_sent_to_server);
1027                 dirs_sent_to_server = getlist ();
1028             }
1029 #endif
1030
1031             err = (*(cm->func)) (argc, argv);
1032         
1033             /* Mark this root directory as done.  When the server is
1034                active, current_root will be NULL -- don't try and
1035                remove it from the list. */
1036
1037             if (current_root != NULL)
1038             {
1039                 Node *n = findnode (root_directories, current_root);
1040                 assert (n != NULL);
1041                 n->data = (void *) 1;
1042                 current_root = NULL;
1043             }
1044         
1045 #if 0
1046             /* This will not work yet, since it tries to free (void *) 1. */
1047             dellist (&root_directories);
1048 #endif
1049
1050 #ifdef SERVER_SUPPORT
1051             if (server_active)
1052             {
1053                 server_active = 0;
1054                 break;
1055             }
1056 #endif
1057         } /* end of loop for cvsroot values */
1058
1059     } /* end of stuff that gets done if the user DOESN'T ask for help */
1060
1061     Lock_Cleanup ();
1062
1063     /* It's okay to cast out the const below since we know we allocated this in
1064      * this function.  The const was to keep other functions from messing with
1065      * this.
1066      */
1067     free ((char *)program_path);
1068     if (CVSroot_cmdline != NULL)
1069         free (CVSroot_cmdline);
1070     if (free_CVSroot)
1071         free (CVSroot);
1072     if (free_Editor)
1073         free (Editor);
1074     if (free_Tmpdir)
1075         free (Tmpdir);
1076     root_allow_free ();
1077
1078 #ifdef SYSTEM_CLEANUP
1079     /* Hook for OS-specific behavior, for example socket subsystems on
1080        NT and OS2 or dealing with windows and arguments on Mac.  */
1081     SYSTEM_CLEANUP ();
1082 #endif
1083
1084     /* This is exit rather than return because apparently that keeps
1085        some tools which check for memory leaks happier.  */
1086     exit (err ? EXIT_FAILURE : 0);
1087         /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy.  */
1088         return 0;
1089 }
1090
1091 char *
1092 Make_Date (rawdate)
1093     char *rawdate;
1094 {
1095     time_t unixtime;
1096
1097     unixtime = get_date (rawdate, (struct timeb *) NULL);
1098     if (unixtime == (time_t) - 1)
1099         error (1, 0, "Can't parse date/time: %s", rawdate);
1100     return date_from_time_t (unixtime);
1101 }
1102
1103 /* Convert a time_t to an RCS format date.  This is mainly for the
1104    use of "cvs history", because the CVSROOT/history file contains
1105    time_t format dates; most parts of CVS will want to avoid using
1106    time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
1107    Assuming that the time_t is in GMT (as it generally should be),
1108    then the result will be in GMT too.
1109
1110    Returns a newly malloc'd string.  */
1111
1112 char *
1113 date_from_time_t (unixtime)
1114     time_t unixtime;
1115 {
1116     struct tm *ftm;
1117     char date[MAXDATELEN];
1118     char *ret;
1119
1120     ftm = gmtime (&unixtime);
1121     if (ftm == NULL)
1122         /* This is a system, like VMS, where the system clock is in local
1123            time.  Hopefully using localtime here matches the "zero timezone"
1124            hack I added to get_date (get_date of course being the relevant
1125            issue for Make_Date, and for history.c too I think).  */
1126         ftm = localtime (&unixtime);
1127
1128     (void) sprintf (date, DATEFORM,
1129                     ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1130                     ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1131                     ftm->tm_min, ftm->tm_sec);
1132     ret = xstrdup (date);
1133     return (ret);
1134 }
1135
1136 /* Convert a date to RFC822/1123 format.  This is used in contexts like
1137    dates to send in the protocol; it should not vary based on locale or
1138    other such conventions for users.  We should have another routine which
1139    does that kind of thing.
1140
1141    The SOURCE date is in our internal RCS format.  DEST should point to
1142    storage managed by the caller, at least MAXDATELEN characters.  */
1143 void
1144 date_to_internet (dest, source)
1145     char *dest;
1146     const char *source;
1147 {
1148     struct tm date;
1149
1150     date_to_tm (&date, source);
1151     tm_to_internet (dest, &date);
1152 }
1153
1154 void
1155 date_to_tm (dest, source)
1156     struct tm *dest;
1157     const char *source;
1158 {
1159     if (sscanf (source, SDATEFORM,
1160                 &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
1161                 &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
1162             != 6)
1163         /* Is there a better way to handle errors here?  I made this
1164            non-fatal in case we are called from the code which can't
1165            deal with fatal errors.  */
1166         error (0, 0, "internal error: bad date %s", source);
1167
1168     if (dest->tm_year > 100)
1169         dest->tm_year -= 1900;
1170
1171     dest->tm_mon -= 1;
1172 }
1173
1174 /* Convert a date to RFC822/1123 format.  This is used in contexts like
1175    dates to send in the protocol; it should not vary based on locale or
1176    other such conventions for users.  We should have another routine which
1177    does that kind of thing.
1178
1179    The SOURCE date is a pointer to a struct tm.  DEST should point to
1180    storage managed by the caller, at least MAXDATELEN characters.  */
1181 void
1182 tm_to_internet (dest, source)
1183     char *dest;
1184     const struct tm *source;
1185 {
1186     /* Just to reiterate, these strings are from RFC822 and do not vary
1187        according to locale.  */
1188     static const char *const month_names[] =
1189       {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1190          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1191     
1192     sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday,
1193              source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon],
1194              source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec);
1195 }
1196
1197 void
1198 usage (cpp)
1199     register const char *const *cpp;
1200 {
1201     (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
1202     for (; *cpp; cpp++)
1203         (void) fprintf (stderr, *cpp);
1204     error_exit ();
1205 }
1206
1207 void
1208 parseopts(root)
1209     const char *root;
1210 {
1211     char path[PATH_MAX];
1212     int save_errno;
1213     char buf[1024];
1214     const char *p;
1215     char *q;
1216     FILE *fp;
1217
1218     if (root == NULL) {
1219         printf("no CVSROOT in parseopts\n");
1220         return;
1221     }
1222     p = strchr (root, ':');
1223     if (p)
1224         p++;
1225     else
1226         p = root;
1227     if (p == NULL) {
1228         printf("mangled CVSROOT in parseopts\n");
1229         return;
1230     }
1231     (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
1232     if ((fp = fopen(path, "r")) != NULL) {
1233         while (fgets(buf, sizeof buf, fp) != NULL) {
1234             if (buf[0] == '#')
1235                 continue;
1236             q = strrchr(buf, '\n');
1237             if (q)
1238                 *q = '\0';
1239
1240             if (!strcmp(buf, "iso8601")) {
1241                 datesep = '-';
1242             }
1243             if (!strncmp(buf, "tag=", 4)) {
1244                 char *what;
1245                 char *rcs_localid;
1246
1247                 rcs_localid = buf + 4;
1248                 RCS_setlocalid(rcs_localid);
1249             }
1250             if (!strncmp(buf, "tagexpand=", 10)) {
1251                 char *what;
1252                 char *rcs_incexc;
1253
1254                 rcs_incexc = buf + 10;
1255                 RCS_setincexc(rcs_incexc);
1256             }
1257             /*
1258              * OpenBSD has a "umask=" and "dlimit=" command, we silently
1259              * ignore them here since they are not much use to us.  cvsumask
1260              * defaults to 002 already, and the dlimit (data size limit)
1261              * should really be handled elsewhere (eg: login.conf).
1262              */
1263         }
1264         fclose(fp);
1265     }
1266 }