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