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