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