2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
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.
13 * This is the main C driver for the CVS system.
15 * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
16 * the shell-script CVS system that this is based on.
25 #include "xgethostname.h"
27 const char *program_name;
28 const char *program_path;
29 const char *cvs_cmd_name;
31 const char *global_session_id; /* Random session ID */
34 /* FIXME: Perhaps this should be renamed original_hostname or the like? */
35 char *server_hostname;
39 int cvswrite = !CVSREAD_DFLT;
51 *** CVSROOT/config options
54 struct config *config;
58 mode_t cvsumask = UMASK_DFLT;
63 * Defaults, for the environment variables that are not set
65 char *Editor = EDITOR_DFLT;
71 /* Temp dir, if set by the user. */
72 static char *tmpdir_cmdline;
76 /* Returns in order of precedence:
78 * 1. Temp dir as set via the command line.
79 * 2. Temp dir as set in CVSROOT/config.
80 * 3. Temp dir as set in $TMPDIR env var.
81 * 4. Contents of TMPDIR_DFLT preprocessor macro.
84 * It is a fatal error if this function would otherwise return NULL or an
88 get_cvs_tmp_dir (void)
91 if (tmpdir_cmdline) retval = tmpdir_cmdline;
92 else if (config && config->TmpDir) retval = config->TmpDir;
93 else retval = get_system_temp_dir ();
94 if (!retval) retval = TMPDIR_DFLT;
96 if (!retval || !*retval) error (1, 0, "No temp dir specified.");
103 /* When our working directory contains subdirectories with different
104 values in CVS/Root files, we maintain a list of them. */
105 List *root_directories = NULL;
107 static const struct cmd
109 const char *fullname; /* Full name of the function (e.g. "commit") */
111 /* Synonyms for the command, nick1 and nick2. We supply them
112 mostly for two reasons: (1) CVS has always supported them, and
113 we need to maintain compatibility, (2) if there is a need for a
114 version which is shorter than the fullname, for ease in typing.
115 Synonyms have the disadvantage that people will see "new" and
116 then have to think about it, or look it up, to realize that is
117 the operation they know as "add". Also, this means that one
118 cannot create a command "cvs new" with a different meaning. So
119 new synonyms are probably best used sparingly, and where used
120 should be abbreviations of the fullname (preferably consisting
121 of the first 2 or 3 or so letters).
123 One thing that some systems do is to recognize any unique
124 abbreviation, for example "annotat" "annota", etc., for
125 "annotate". The problem with this is that scripts and user
126 habits will expect a certain abbreviation to be unique, and in
127 a future release of CVS it may not be. So it is better to
128 accept only an explicit list of abbreviations and plan on
129 supporting them in the future as well as now. */
134 int (*func) (int, char **); /* Function takes (argc, argv) arguments. */
135 unsigned long attr; /* Attributes. */
139 { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
140 { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
141 { "annotate", "ann", NULL, annotate, CVS_CMD_USES_WORK_DIR },
142 { "checkout", "co", "get", checkout, 0 },
143 { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
144 { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR },
145 { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
146 { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR },
147 { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR },
148 { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR },
149 { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT},
150 { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY },
151 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
152 { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
154 { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR },
155 #ifdef AUTH_CLIENT_SUPPORT
156 { "login", "logon", "lgn", login, 0 },
157 { "logout", NULL, NULL, logout, 0 },
158 #endif /* AUTH_CLIENT_SUPPORT */
159 { "ls", "dir", "list", ls, 0 },
160 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
161 { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
163 { "rannotate","rann", "ra", annotate, 0 },
164 { "rdiff", "patch", "pa", patch, 0 },
165 { "release", "re", "rel", release, CVS_CMD_MODIFIES_REPOSITORY },
166 { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
167 { "rlog", "rl", NULL, cvslog, 0 },
168 { "rls", "rdir", "rlist", ls, 0 },
169 { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY },
170 #ifdef SERVER_SUPPORT
171 { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
173 { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR },
174 { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
175 { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
176 { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR },
177 { "version", "ve", "ver", version, 0 },
178 { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
179 { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR },
180 { NULL, NULL, NULL, NULL, 0 },
183 static const char *const usg[] =
185 /* CVS usage messages never have followed the GNU convention of
186 putting metavariables in uppercase. I don't know whether that
187 is a good convention or not, but if it changes it would have to
188 change in all the usage messages. For now, they consistently
189 use lowercase, as far as I know. Punctuation is pretty funky,
190 though. Sometimes they use none, as here. Sometimes they use
191 single quotes (not the TeX-ish `' stuff), as in --help-options.
192 Sometimes they use double quotes, as in cvs -H add.
194 Most (not all) of the usage messages seem to have periods at
195 the end of each line. I haven't tried to duplicate this style
196 in --help as it is a rather different format from the rest. */
198 "Usage: %s [cvs-options] command [command-options-and-arguments]\n",
199 " where cvs-options are -q, -n, etc.\n",
200 " (specify --help-options for a list of options)\n",
201 " where command is add, admin, etc.\n",
202 " (specify --help-commands for a list of commands\n",
203 " or --help-synonyms for a list of command synonyms)\n",
204 " where command-options-and-arguments depend on the specific command\n",
205 " (specify -H followed by a command name for command-specific help)\n",
206 " Specify --help to receive this message\n",
209 /* Some people think that a bug-reporting address should go here. IMHO,
210 the web sites are better because anything else is very likely to go
211 obsolete in the years between a release and when someone might be
212 reading this help. Besides, we could never adequately discuss
213 bug reporting in a concise enough way to put in a help message. */
215 /* I was going to put this at the top, but usage() wants the %s to
216 be in the first line. */
217 "The Concurrent Versions System (CVS) is a tool for version control.\n",
218 /* I really don't think I want to try to define "version control"
219 in one line. I'm not sure one can get more concise than the
220 paragraph in ../cvs.spec without assuming the reader knows what
221 version control means. */
223 "For CVS updates and additional information, see\n",
224 " the CVS home page at http://www.nongnu.org/cvs/ or\n",
225 " the CVSNT home page at http://www.cvsnt.org/\n",
229 static const char *const cmd_usage[] =
231 "CVS commands are:\n",
232 " add Add a new file/directory to the repository\n",
233 " admin Administration front end for rcs\n",
234 " annotate Show last revision where each line was modified\n",
235 " checkout Checkout sources for editing\n",
236 " commit Check files into the repository\n",
237 " diff Show differences between revisions\n",
238 " edit Get ready to edit a watched file\n",
239 " editors See who is editing a watched file\n",
240 " export Export sources from CVS, similar to checkout\n",
241 " history Show repository access history\n",
242 " import Import sources into CVS, using vendor branches\n",
243 " init Create a CVS repository if it doesn't exist\n",
244 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
245 " kserver Kerberos server mode\n",
247 " log Print out history information for files\n",
248 #ifdef AUTH_CLIENT_SUPPORT
249 " login Prompt for password for authenticating server\n",
250 " logout Removes entry in .cvspass for remote repository\n",
251 #endif /* AUTH_CLIENT_SUPPORT */
252 " ls List files available from CVS\n",
253 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
254 " pserver Password server mode\n",
256 " rannotate Show last revision where each line of module was modified\n",
257 " rdiff Create 'patch' format diffs between releases\n",
258 " release Indicate that a Module is no longer in use\n",
259 " remove Remove an entry from the repository\n",
260 " rlog Print out history information for a module\n",
261 " rls List files in a module\n",
262 " rtag Add a symbolic tag to a module\n",
263 #ifdef SERVER_SUPPORT
264 " server Server mode\n",
266 " status Display status information on checked out files\n",
267 " tag Add a symbolic tag to checked out version of files\n",
268 " unedit Undo an edit command\n",
269 " update Bring work tree in sync with repository\n",
270 " version Show current CVS version(s)\n",
271 " watch Set watches\n",
272 " watchers See who is watching a file\n",
273 "(Specify the --help option for a list of other help options)\n",
277 static const char *const opt_usage[] =
279 /* Omit -b because it is just for compatibility. */
280 "CVS global options (specified before the command name) are:\n",
281 " -H Displays usage information for command.\n",
282 " -Q Cause CVS to be really quiet.\n",
283 " -q Cause CVS to be somewhat quiet.\n",
284 " -r Make checked-out files read-only.\n",
285 " -w Make checked-out files read-write (default).\n",
286 " -n Do not execute anything that will change the disk.\n",
287 " -t Show trace of program execution (repeat for more\n",
288 " verbosity) -- try with -n.\n",
289 " -R Assume repository is read-only, such as CDROM\n",
290 " -v CVS version and copyright.\n",
291 " -T tmpdir Use 'tmpdir' for temporary files.\n",
292 " -e editor Use 'editor' for editing log information.\n",
293 " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
294 " -f Do not use the ~/.cvsrc file.\n",
295 #ifdef CLIENT_SUPPORT
296 " -z # Request compression level '#' for net traffic.\n",
298 " -x Encrypt all net traffic.\n",
300 " -a Authenticate all net traffic.\n",
302 " -s VAR=VAL Set CVS user variable.\n",
303 "(Specify the --help option for a list of other help options)\n",
309 set_root_directory (Node *p, void *ignored)
311 if (current_parsed_root == NULL && p->data != NULL)
313 current_parsed_root = p->data;
314 original_parsed_root = current_parsed_root;
321 static const char * const*
326 const struct cmd *c = &cmds[0];
327 /* Three more for title, "specify --help" line, and NULL. */
330 while (c->fullname != NULL)
336 synonyms = xnmalloc (numcmds, sizeof(char *));
338 *line++ = "CVS command synonyms are:\n";
339 for (c = &cmds[0]; c->fullname != NULL; c++)
341 if (c->nick1 || c->nick2)
343 *line = Xasprintf (" %-12s %s %s\n", c->fullname,
344 c->nick1 ? c->nick1 : "",
345 c->nick2 ? c->nick2 : "");
349 *line++ = "(Specify the --help option for a list of other help options)\n";
352 return (const char * const*) synonyms; /* will never be freed */
358 lookup_command_attribute (const char *cmd_name)
360 const struct cmd *cm;
362 for (cm = cmds; cm->fullname; cm++)
364 if (strcmp (cmd_name, cm->fullname) == 0)
368 error (1, 0, "unknown command: %s", cmd_name);
375 * Exit with an error code and an informative message about the signal
376 * received. This function, by virtue of causing an actual call to exit(),
377 * causes all the atexit() handlers to be called.
380 * sig The signal recieved.
383 * The cleanup routines registered via atexit() and the error function
384 * itself can potentially change the exit status. They shouldn't do this
385 * unless they encounter problems doing their own jobs.
388 * Nothing. This function will always exit. It should exit with an exit
389 * status of 1, but might not, as noted in the ERRORS section above.
391 #ifndef DONT_USE_SIGNALS
392 static RETSIGTYPE main_cleanup (int) __attribute__ ((__noreturn__));
393 #endif /* DONT_USE_SIGNALS */
395 main_cleanup (int sig)
397 #ifndef DONT_USE_SIGNALS
425 name = "broken pipe";
430 name = "termination";
434 /* This case should never be reached, because we list above all
435 the signals for which we actually establish a signal handler. */
436 sprintf (temp, "%d", sig);
441 /* This always exits, which will cause our exit handlers to be called. */
442 error (1, 0, "received %s signal", name);
443 /* but make the exit explicit to silence warnings when gcc processes the
444 * noreturn attribute.
447 #endif /* !DONT_USE_SIGNALS */
454 * When !defined ALLOW_CONFIG_OVERRIDE, this will never have any value but
457 extern char *gConfigPath;
462 enum {RANDOM_BYTES = 8};
463 enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
465 static char const alphabet[62] =
466 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
468 /* Divide BUF by D, returning the remainder. Replace BUF by the
469 quotient. BUF[0] is the most significant part of BUF.
470 D must not exceed UINT_MAX >> CHAR_BIT. */
472 divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
474 unsigned int carry = 0;
476 for (i = 0; i < COMMITID_RAW_SIZE; i++)
478 unsigned int byte = buf[i];
479 unsigned int dividend = (carry << CHAR_BIT) + byte;
480 buf[i] = dividend / d;
481 carry = dividend % d;
487 convert (char const input[COMMITID_RAW_SIZE], char *output)
489 static char const zero[COMMITID_RAW_SIZE] = { 0, };
490 unsigned char buf[COMMITID_RAW_SIZE];
492 memcpy (buf, input, COMMITID_RAW_SIZE);
493 while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
494 output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
502 main (int argc, char **argv)
504 cvsroot_t *CVSroot_parsed = NULL;
505 bool cvsroot_update_env = true;
507 const struct cmd *cm;
511 int help = 0; /* Has the user asked for help? This
512 lets us support the `cvs -H cmd'
513 convention to give help for cmd. */
514 static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
515 static struct option long_options[] =
517 {"help", 0, NULL, 'H'},
518 {"version", 0, NULL, 'v'},
519 {"help-commands", 0, NULL, 1},
520 {"help-synonyms", 0, NULL, 2},
521 {"help-options", 0, NULL, 4},
522 #ifdef SERVER_SUPPORT
523 {"allow-root", required_argument, NULL, 3},
524 #endif /* SERVER_SUPPORT */
527 /* `getopt_long' stores the option index here, but right now we
529 int option_index = 0;
531 #ifdef SYSTEM_INITIALIZE
532 /* Hook for OS-specific behavior, for example socket subsystems on
533 NT and OS2 or dealing with windows and arguments on Mac. */
534 SYSTEM_INITIALIZE (&argc, &argv);
537 #ifdef SYSTEM_CLEANUP
538 /* Hook for OS-specific behavior, for example socket subsystems on
539 NT and OS2 or dealing with windows and arguments on Mac. */
540 cleanup_register (SYSTEM_CLEANUP);
544 /* On systems that have tzset (which is almost all the ones I know
545 of), it's a good idea to call it. */
550 * Just save the last component of the path for error messages
552 program_path = xstrdup (argv[0]);
553 #ifdef ARGV0_NOT_PROGRAM_NAME
554 /* On some systems, e.g. VMS, argv[0] is not the name of the command
555 which the user types to invoke the program. */
556 program_name = "cvs";
558 program_name = last_component (argv[0]);
562 * Query the environment variables up-front, so that
563 * they can be overridden by command line arguments
565 if ((cp = getenv (EDITOR1_ENV)) != NULL)
567 else if ((cp = getenv (EDITOR2_ENV)) != NULL)
569 else if ((cp = getenv (EDITOR3_ENV)) != NULL)
571 if (getenv (CVSREAD_ENV) != NULL)
573 if (getenv (CVSREADONLYFS_ENV) != NULL) {
578 /* Set this to 0 to force getopt initialization. getopt() sets
579 this to 1 internally. */
582 /* We have to parse the options twice because else there is no
583 chance to avoid reading the global options from ".cvsrc". Set
584 opterr to 0 for avoiding error messages about invalid options.
588 while ((c = getopt_long
589 (argc, argv, short_options, long_options, &option_index))
596 #ifdef SERVER_SUPPORT
597 /* Don't try and read a .cvsrc file if we are a server. */
600 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
601 || !strcmp (argv[optind], "pserver")
603 # ifdef HAVE_KERBEROS
604 || !strcmp (argv[optind], "kserver")
605 # endif /* HAVE_KERBEROS */
606 || !strcmp (argv[optind], "server")))
608 /* Avoid any .cvsrc file. */
610 /* Pre-parse the server options to get the config path. */
611 cvs_cmd_name = argv[optind];
612 parseServerOptions (argc - optind, argv + optind);
614 #endif /* SERVER_SUPPORT */
617 * Scan cvsrc file for global options.
620 read_cvsrc (&argc, &argv, "cvs");
625 while ((c = getopt_long
626 (argc, argv, short_options, long_options, &option_index))
632 /* --help-commands */
636 /* --help-synonyms */
637 usage (cmd_synonyms());
643 #ifdef SERVER_SUPPORT
646 root_allow_add (optarg, gConfigPath);
648 #endif /* SERVER_SUPPORT */
673 (void) fputs ("\n", stdout);
675 (void) fputs ("\n", stdout);
677 Copyright (C) 2005 Free Software Foundation, Inc.\n\
679 Senior active maintainers include Larry Jones, Derek R. Price,\n\
680 and Mark D. Baushke. Please see the AUTHORS and README files from the CVS\n\
681 distribution kit for a complete list of contributors and copyrights.\n",
683 (void) fputs ("\n", stdout);
684 (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
685 (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
686 (void) fputs ("\n", stdout);
688 (void) fputs ("Specify the --help option for further information about CVS\n", stdout);
693 /* This option used to specify the directory for RCS
694 executables. But since we don't run them any more,
695 this is a noop. Silently ignore it so that .cvsrc
696 and scripts and inetd.conf and such can work with
697 either new or old CVS. */
700 if (tmpdir_cmdline) free (tmpdir_cmdline);
701 tmpdir_cmdline = xstrdup (optarg);
704 if (free_Editor) free (Editor);
705 Editor = xstrdup (optarg);
709 if (CVSroot_cmdline != NULL)
710 free (CVSroot_cmdline);
711 CVSroot_cmdline = xstrdup (optarg);
717 use_cvsrc = 0; /* unnecessary, since we've done it above */
720 #ifdef CLIENT_SUPPORT
721 gzip_level = strtol (optarg, &end, 10);
722 if (*end != '\0' || gzip_level < 0 || gzip_level > 9)
724 "gzip compression level must be between 0 and 9");
725 #endif /* CLIENT_SUPPORT */
726 /* If no CLIENT_SUPPORT, we just silently ignore the gzip
727 * level, so that users can have it in their .cvsrc and not
730 * We still parse the argument to -z for correctness since
731 * one user complained of being bitten by a run of
732 * `cvs -z -n up' which read -n as the argument to -z without
736 variable_set (optarg);
739 #ifdef CLIENT_SUPPORT
741 #endif /* CLIENT_SUPPORT */
742 /* If no CLIENT_SUPPORT, ignore -x, so that users can
743 have it in their .cvsrc and not cause any trouble.
744 If no ENCRYPTION, we still accept -x, but issue an
745 error if we are being run as a client. */
748 #ifdef CLIENT_SUPPORT
751 /* If no CLIENT_SUPPORT, ignore -a, so that users can
752 have it in their .cvsrc and not cause any trouble.
753 We will issue an error later if stream
754 authentication is not supported. */
767 if (readonlyfs && !really_quiet) {
769 "WARNING: Read-only repository access mode selected via `cvs -R'.\n\
770 Using this option to access a repository which some users write to may\n\
771 cause intermittent sandbox corruption.");
774 /* Calculate the cvs global session ID */
777 char buf[COMMITID_RAW_SIZE] = { 0, };
778 char out[COMMITID_RAW_SIZE * 2];
780 time_t rightnow = time (NULL);
781 char *startrand = buf + sizeof (time_t);
782 unsigned char *p = (unsigned char *) startrand;
783 size_t randbytes = RANDOM_BYTES;
784 int flags = O_RDONLY;
789 if (rightnow != (time_t)-1)
790 while (rightnow > 0) {
791 *--p = rightnow % (UCHAR_MAX + 1);
792 rightnow /= UCHAR_MAX + 1;
795 /* try to use more random data */
796 randbytes = COMMITID_RAW_SIZE;
799 fd = open ("/dev/urandom", flags);
801 len = read (fd, startrand, randbytes);
805 /* no random data was available so use pid */
806 long int pid = (long int)getpid ();
807 p = (unsigned char *) (startrand + sizeof (pid));
809 *--p = pid % (UCHAR_MAX + 1);
810 pid /= UCHAR_MAX + 1;
814 global_session_id = strdup (out);
818 TRACE (TRACE_FUNCTION, "main: Session ID is %s", global_session_id);
820 /* Look up the command name. */
822 cvs_cmd_name = argv[0];
823 for (cm = cmds; cm->fullname; cm++)
825 if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1))
827 if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2))
829 if (!strcmp (cvs_cmd_name, cm->fullname))
835 fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name);
839 cvs_cmd_name = cm->fullname; /* Global pointer for later use */
843 argc = -1; /* some functions only check for this */
844 err = (*(cm->func)) (argc, argv);
848 /* The user didn't ask for help, so go ahead and authenticate,
849 set up CVSROOT, and the rest of it. */
851 short int lock_cleanup_setup = 0;
853 /* The UMASK environment variable isn't handled with the
854 others above, since we don't want to signal errors if the
855 user has asked for help. This won't work if somebody adds
856 a command-line flag to set the umask, since we'll have to
857 parse it before we get here. */
859 if ((cp = getenv (CVSUMASK_ENV)) != NULL)
861 /* FIXME: Should be accepting symbolic as well as numeric mask. */
862 cvsumask = strtol (cp, &end, 8) & 0777;
864 error (1, errno, "invalid umask value in %s (%s)",
868 /* HOSTNAME & SERVER_HOSTNAME need to be set before they are
869 * potentially used in gserver_authenticate_connection() (called from
870 * pserver_authenticate_connection, below).
872 hostname = xgethostname ();
876 "xgethostname () returned NULL, using \"localhost\"");
877 hostname = xstrdup ("localhost");
880 /* Keep track of this separately since the client can change
881 * HOSTNAME on the server.
883 server_hostname = xstrdup (hostname);
885 #ifdef SERVER_SUPPORT
887 # ifdef HAVE_KERBEROS
888 /* If we are invoked with a single argument "kserver", then we are
889 running as Kerberos server as root. Do the authentication as
890 the very first thing, to minimize the amount of time we are
892 if (strcmp (cvs_cmd_name, "kserver") == 0)
894 kserver_authenticate_connection ();
896 /* Pretend we were invoked as a plain server. */
897 cvs_cmd_name = "server";
899 # endif /* HAVE_KERBEROS */
901 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
902 if (strcmp (cvs_cmd_name, "pserver") == 0)
904 /* The reason that --allow-root is not a command option
905 is mainly that it seems easier to make it a global option. */
907 /* Gets username and password from client, authenticates, then
908 switches to run as that user and sends an ACK back to the
910 pserver_authenticate_connection ();
912 /* Pretend we were invoked as a plain server. */
913 cvs_cmd_name = "server";
915 # endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
916 #endif /* SERVER_SUPPORT */
918 server_active = strcmp (cvs_cmd_name, "server") == 0;
920 #ifdef SERVER_SUPPORT
923 /* This is only used for writing into the history file. For
924 remote connections, it might be nice to have hostname
925 and/or remote path, on the other hand I'm not sure whether
926 it is worth the trouble. */
927 CurDir = xstrdup ("<remote>");
928 cleanup_register (server_cleanup);
933 cleanup_register (close_stdout);
936 error (1, errno, "cannot get working directory");
941 /* XXX pid < 10^32 */
942 val = Xasprintf ("%ld", (long) getpid ());
943 setenv (CVS_PID_ENV, val, 1);
947 /* make sure we clean up on error */
948 signals_register (main_cleanup);
950 #ifdef KLUDGE_FOR_WNT_TESTSUITE
951 /* Probably the need for this will go away at some point once
952 we call fflush enough places (e.g. fflush (stdout) in
954 (void) setvbuf (stdout, NULL, _IONBF, 0);
955 (void) setvbuf (stderr, NULL, _IONBF, 0);
956 #endif /* KLUDGE_FOR_WNT_TESTSUITE */
959 read_cvsrc (&argc, &argv, cvs_cmd_name);
961 /* Fiddling with CVSROOT doesn't make sense if we're running
962 * in server mode, since the client will send the repository
963 * directory after the connection is made.
967 /* First check if a root was set via the command line. */
970 if (!(CVSroot_parsed = parse_cvsroot (CVSroot_cmdline)))
971 error (1, 0, "Bad CVSROOT: `%s'.", CVSroot_cmdline);
974 /* See if we are able to find a 'better' value for CVSroot
975 * in the CVSADM_ROOT directory.
977 * "cvs import" shouldn't check CVS/Root; in general it
978 * ignores CVS directories and CVS/Root is likely to
979 * specify a different repository than the one we are
980 * importing to, but if this is not import and no root was
981 * specified on the command line, set the root from the
985 && !(cm->attr & CVS_CMD_IGNORE_ADMROOT)
987 CVSroot_parsed = Name_Root (NULL, NULL);
989 /* Now, if there is no root on the command line and we didn't find
990 * one in a file, set it via the $CVSROOT env var.
994 char *tmp = getenv (CVSROOT_ENV);
997 if (!(CVSroot_parsed = parse_cvsroot (tmp)))
998 error (1, 0, "Bad CVSROOT: `%s'.", tmp);
999 cvsroot_update_env = false;
1004 if (!CVSroot_parsed)
1006 if (!(CVSroot_parsed = parse_cvsroot (CVSROOT_DFLT)))
1007 error (1, 0, "Bad CVSROOT: `%s'.", CVSROOT_DFLT);
1009 #endif /* CVSROOT_DFLT */
1011 /* Now we've reconciled CVSROOT from the command line, the
1012 CVS/Root file, and the environment variable. Do the
1013 last sanity checks on the variable. */
1014 if (!CVSroot_parsed)
1017 "No CVSROOT specified! Please use the `-d' option");
1019 "or set the %s environment variable.", CVSROOT_ENV);
1023 /* Here begins the big loop over unique cvsroot values. We
1024 need to call do_recursion once for each unique value found
1025 in CVS/Root. Prime the list with the current value. */
1027 /* Create the list. */
1028 assert (root_directories == NULL);
1029 root_directories = getlist ();
1036 n->type = NT_UNKNOWN;
1037 n->key = xstrdup (CVSroot_parsed->original);
1038 n->data = CVSroot_parsed;
1040 if (addnode (root_directories, n))
1041 error (1, 0, "cannot add initial CVSROOT %s", n->key);
1044 assert (current_parsed_root == NULL);
1046 /* If we're running the server, we want to execute this main
1047 loop once and only once (we won't be serving multiple roots
1048 from this connection, so there's no need to do it more than
1049 once). To get out of the loop, we perform a "break" at the
1052 while (server_active ||
1053 walklist (root_directories, set_root_directory, NULL))
1055 /* Fiddling with CVSROOT doesn't make sense if we're running
1056 in server mode, since the client will send the repository
1057 directory after the connection is made. */
1061 /* Now we're 100% sure that we have a valid CVSROOT
1062 variable. Parse it to see if we're supposed to do
1063 remote accesses or use a special access method. */
1065 TRACE (TRACE_FUNCTION,
1066 "main loop with CVSROOT=%s",
1067 current_parsed_root ? current_parsed_root->directory
1071 * Check to see if the repository exists.
1073 if (!current_parsed_root->isremote)
1078 path = Xasprintf ("%s/%s", current_parsed_root->directory,
1080 if (!isaccessible (path, R_OK | X_OK))
1083 /* If this is "cvs init", the root need not exist yet.
1085 if (strcmp (cvs_cmd_name, "init"))
1086 error (1, save_errno, "%s", path);
1091 /* Update the CVSROOT environment variable. */
1092 if (cvsroot_update_env)
1093 setenv (CVSROOT_ENV, current_parsed_root->original, 1);
1096 /* Parse the CVSROOT/config file, but only for local. For the
1097 server, we parse it after we know $CVSROOT. For the
1098 client, it doesn't get parsed at all, obviously. The
1099 presence of the parse_config call here is not meant to
1100 predetermine whether CVSROOT/config overrides things from
1101 read_cvsrc and other such places or vice versa. That sort
1102 of thing probably needs more thought. */
1103 if (!server_active && !current_parsed_root->isremote)
1105 /* If there was an error parsing the config file, parse_config
1106 already printed an error. We keep going. Why? Because
1107 if we didn't, then there would be no way to check in a new
1108 CVSROOT/config file to fix the broken one! */
1109 if (config) free_config (config);
1110 config = parse_config (current_parsed_root->directory, NULL);
1112 /* Can set TMPDIR in the environment if necessary now, since
1113 * if it was set in config, we now know it.
1115 push_env_temp_dir ();
1118 #ifdef CLIENT_SUPPORT
1119 /* Need to check for current_parsed_root != NULL here since
1120 * we could still be in server mode before the server function
1121 * gets called below and sets the root
1123 if (current_parsed_root != NULL && current_parsed_root->isremote)
1125 /* Create a new list for directory names that we've
1126 sent to the server. */
1127 if (dirs_sent_to_server != NULL)
1128 dellist (&dirs_sent_to_server);
1129 dirs_sent_to_server = getlist ();
1134 #ifdef SERVER_SUPPORT
1135 /* Don't worry about lock_cleanup_setup when the server is
1136 * active since we can only go through this loop once in that
1142 #ifdef CLIENT_SUPPORT
1143 !current_parsed_root->isremote &&
1145 !lock_cleanup_setup))
1147 /* Set up to clean up any locks we might create on exit. */
1148 cleanup_register (Lock_Cleanup);
1149 lock_cleanup_setup = 1;
1152 /* Call our worker function. */
1153 err = (*(cm->func)) (argc, argv);
1155 /* Mark this root directory as done. When the server is
1156 active, our list will be empty -- don't try and
1157 remove it from the list. */
1161 Node *n = findnode (root_directories,
1162 original_parsed_root->original);
1164 assert (n->data != NULL);
1166 current_parsed_root = NULL;
1171 } /* end of loop for cvsroot values */
1173 dellist (&root_directories);
1174 } /* end of stuff that gets done if the user DOESN'T ask for help */
1178 /* This is exit rather than return because apparently that keeps
1179 some tools which check for memory leaks happier. */
1180 exit (err ? EXIT_FAILURE : 0);
1181 /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */
1188 Make_Date (const char *rawdate)
1192 if (!get_date (&t, rawdate, NULL))
1193 error (1, 0, "Can't parse date/time: `%s'", rawdate);
1195 /* Truncate nanoseconds. */
1196 return date_from_time_t (t.tv_sec);
1201 /* Parse a string of the form TAG[:DATE], where TAG could be the empty string.
1204 * input The string to be parsed.
1207 * tag The tag found, if any. If TAG is the empty string, then leave
1208 * this value unchanged.
1209 * date The date found, if any. If DATE is the empty string or is
1210 * missing, leave this value unchanged.
1213 * If either TAG or DATE is replaced for output, the previous value is freed.
1216 * If either TAG or DATE cannot be parsed, then this function will exit with
1217 * a fatal error message.
1223 parse_tagdate (char **tag, char **date, const char *input)
1227 TRACE (TRACE_FUNCTION, "parse_tagdate (%s, %s, %s)",
1228 *tag ? *tag : "(null)", *date ? *date : "(null)",
1231 if ((p = strchr (input, ':')))
1233 /* Parse the tag. */
1236 /* The tag has > 0 length. */
1237 if (*tag) free (*tag);
1238 *tag = xmalloc (p - input + 1);
1239 strncpy (*tag, input, p - input);
1240 (*tag)[p - input] = '\0';
1243 /* Parse the date. */
1246 if (*date) free (*date);
1247 *date = Make_Date (p);
1250 else if (strlen (input))
1252 /* The tag has > 0 length. */
1253 if (*tag) free (*tag);
1254 *tag = xstrdup (input);
1257 TRACE (TRACE_DATA, "parse_tagdate: got tag = `%s', date = `%s'",
1258 *tag ? *tag : "(null)", *date ? *date : "(null)");
1263 /* Convert a time_t to an RCS format date. This is mainly for the
1264 use of "cvs history", because the CVSROOT/history file contains
1265 time_t format dates; most parts of CVS will want to avoid using
1266 time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
1267 Assuming that the time_t is in GMT (as it generally should be),
1268 then the result will be in GMT too.
1270 Returns a newly malloc'd string. */
1273 date_from_time_t (time_t unixtime)
1276 char date[MAXDATELEN];
1279 ftm = gmtime (&unixtime);
1281 /* This is a system, like VMS, where the system clock is in local
1282 time. Hopefully using localtime here matches the "zero timezone"
1283 hack I added to get_date (get_date of course being the relevant
1284 issue for Make_Date, and for history.c too I think). */
1285 ftm = localtime (&unixtime);
1287 (void) sprintf (date, DATEFORM,
1288 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1289 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1290 ftm->tm_min, ftm->tm_sec);
1291 ret = xstrdup (date);
1297 /* Convert a date to RFC822/1123 format. This is used in contexts like
1298 dates to send in the protocol; it should not vary based on locale or
1299 other such conventions for users. We should have another routine which
1300 does that kind of thing.
1302 The SOURCE date is in our internal RCS format. DEST should point to
1303 storage managed by the caller, at least MAXDATELEN characters. */
1305 date_to_internet (char *dest, const char *source)
1309 date_to_tm (&date, source);
1310 tm_to_internet (dest, &date);
1316 date_to_tm (struct tm *dest, const char *source)
1318 if (sscanf (source, SDATEFORM,
1319 &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
1320 &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
1322 /* Is there a better way to handle errors here? I made this
1323 non-fatal in case we are called from the code which can't
1324 deal with fatal errors. */
1325 error (0, 0, "internal error: bad date %s", source);
1327 if (dest->tm_year > 100)
1328 dest->tm_year -= 1900;
1335 /* Convert a date to RFC822/1123 format. This is used in contexts like
1336 dates to send in the protocol; it should not vary based on locale or
1337 other such conventions for users. We should have another routine which
1338 does that kind of thing.
1340 The SOURCE date is a pointer to a struct tm. DEST should point to
1341 storage managed by the caller, at least MAXDATELEN characters. */
1343 tm_to_internet (char *dest, const struct tm *source)
1345 /* Just to reiterate, these strings are from RFC822 and do not vary
1346 according to locale. */
1347 static const char *const month_names[] =
1348 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1349 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1351 sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday,
1352 source->tm_mon < 0 || source->tm_mon > 11
1353 ? "???" : month_names[source->tm_mon],
1354 source->tm_year + 1900, source->tm_hour, source->tm_min,
1361 * Format a date for the current locale.
1364 * UNIXTIME The UNIX seconds since the epoch.
1367 * If my_strftime() encounters an error, this function can return NULL.
1369 * Otherwise, returns a date string in ISO8601 format, e.g.:
1371 * 2004-04-29 13:24:22 -0700
1373 * It is the responsibility of the caller to return of this string.
1376 format_time_t (time_t unixtime)
1378 static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
1379 /* Convert to a time in the local time zone. */
1380 struct tm ltm = *(localtime (&unixtime));
1382 if (!my_strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", <m, 0, 0))
1385 return xstrdup (buf);
1390 /* Like format_time_t(), but return time in UTC.
1393 gmformat_time_t (time_t unixtime)
1395 static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
1396 /* Convert to a time in the local time zone. */
1397 struct tm ltm = *(gmtime (&unixtime));
1399 if (!my_strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", <m, 0, 0))
1402 return xstrdup (buf);
1407 /* Format a date in the local timezone using format_time_t() given a date from
1408 * an arbitrary timezone in a string.
1411 * DATESTR A string that looks like anything get_date() can parse, e.g.:
1413 * 2004-04-29 20:24:22
1416 * As get_date() & format_time_t(). Prints a warning if either provide
1417 * error return values. See RETURNS.
1420 * A freshly allocated string that is a copy of the input string if either
1421 * get_date() or format_time_t() encounter an error and as format_time_t()
1425 format_date_alloc (char *datestr)
1430 TRACE (TRACE_FUNCTION, "format_date (%s)", datestr);
1432 /* Convert the date string to seconds since the epoch. */
1433 if (!get_date (&t, datestr, NULL))
1435 error (0, 0, "Can't parse date/time: `%s'.", datestr);
1439 /* Get the time into a string, truncating any nanoseconds returned by
1442 if ((buf = format_time_t (t.tv_sec)) == NULL)
1444 error (0, 0, "Unable to reformat date `%s'.", datestr);
1451 return xstrdup (datestr);
1457 usage (register const char *const *cpp)
1459 (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
1461 (void) fprintf (stderr, *cpp);
1462 exit (EXIT_FAILURE);
1465 /* vim:tabstop=8:shiftwidth=4