2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the CVS source distribution.
8 * This is the main C driver for the CVS system.
10 * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
11 * the shell-script CVS system that this is based on.
18 #include "prepend_args.h"
23 extern int gethostname ();
26 const char *program_name;
27 const char *program_path;
28 const char *cvs_cmd_name;
30 /* I'd dynamically allocate this, but it seems like gethostname
31 requires a fixed size array. If I'm remembering the RFCs right,
32 256 should be enough. */
33 #ifndef MAXHOSTNAMELEN
34 #define MAXHOSTNAMELEN 256
37 char hostname[MAXHOSTNAMELEN];
41 int cvswrite = !CVSREAD_DFLT;
47 int require_real_user = 0;
50 /* Set if we should be writing CVSADM directories at top level. At
51 least for now we'll make the default be off (the CVS 1.9, not CVS
53 int top_level_admin = 0;
55 mode_t cvsumask = UMASK_DFLT;
60 * Defaults, for the environment variables that are not set
62 char *Tmpdir = TMPDIR_DFLT;
63 char *Editor = EDITOR_DFLT;
66 /* When our working directory contains subdirectories with different
67 values in CVS/Root files, we maintain a list of them. */
68 List *root_directories = NULL;
70 /* We step through the above values. This variable is set to reflect
71 * the currently active value.
73 * Now static. FIXME - this variable should be removable (well, localizable)
74 * with a little more work.
76 static char *current_root = NULL;
79 static const struct cmd
81 char *fullname; /* Full name of the function (e.g. "commit") */
83 /* Synonyms for the command, nick1 and nick2. We supply them
84 mostly for two reasons: (1) CVS has always supported them, and
85 we need to maintain compatibility, (2) if there is a need for a
86 version which is shorter than the fullname, for ease in typing.
87 Synonyms have the disadvantage that people will see "new" and
88 then have to think about it, or look it up, to realize that is
89 the operation they know as "add". Also, this means that one
90 cannot create a command "cvs new" with a different meaning. So
91 new synonyms are probably best used sparingly, and where used
92 should be abbreviations of the fullname (preferably consisting
93 of the first 2 or 3 or so letters).
95 One thing that some systems do is to recognize any unique
96 abbreviation, for example "annotat" "annota", etc., for
97 "annotate". The problem with this is that scripts and user
98 habits will expect a certain abbreviation to be unique, and in
99 a future release of CVS it may not be. So it is better to
100 accept only an explicit list of abbreviations and plan on
101 supporting them in the future as well as now. */
106 int (*func) (); /* Function takes (argc, argv) arguments. */
107 unsigned long attr; /* Attributes. */
111 { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
112 { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
113 { "annotate", "ann", "blame", annotate, CVS_CMD_USES_WORK_DIR },
114 { "checkout", "co", "get", checkout, 0 },
115 { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
116 { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR },
117 { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
118 { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR },
119 { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR },
120 { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR },
121 { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT},
122 { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY },
123 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
124 { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
126 { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR },
127 #ifdef AUTH_CLIENT_SUPPORT
128 { "login", "logon", "lgn", login, 0 },
129 { "logout", NULL, NULL, logout, 0 },
130 #endif /* AUTH_CLIENT_SUPPORT */
131 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
132 { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
134 { "rannotate","rann", "ra", annotate, 0 },
135 { "rdiff", "patch", "pa", patch, 0 },
136 { "release", "re", "rel", release, 0 },
137 { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
138 { "rlog", "rl", NULL, cvslog, 0 },
139 { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY },
140 #ifdef SERVER_SUPPORT
141 { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
143 { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR },
144 { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
145 { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
146 { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR },
147 { "version", "ve", "ver", version, 0 },
148 { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
149 { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR },
150 { NULL, NULL, NULL, NULL, 0 },
153 static const char *const usg[] =
155 /* CVS usage messages never have followed the GNU convention of
156 putting metavariables in uppercase. I don't know whether that
157 is a good convention or not, but if it changes it would have to
158 change in all the usage messages. For now, they consistently
159 use lowercase, as far as I know. Punctuation is pretty funky,
160 though. Sometimes they use none, as here. Sometimes they use
161 single quotes (not the TeX-ish `' stuff), as in --help-options.
162 Sometimes they use double quotes, as in cvs -H add.
164 Most (not all) of the usage messages seem to have periods at
165 the end of each line. I haven't tried to duplicate this style
166 in --help as it is a rather different format from the rest. */
168 "Usage: %s [cvs-options] command [command-options-and-arguments]\n",
169 " where cvs-options are -q, -n, etc.\n",
170 " (specify --help-options for a list of options)\n",
171 " where command is add, admin, etc.\n",
172 " (specify --help-commands for a list of commands\n",
173 " or --help-synonyms for a list of command synonyms)\n",
174 " where command-options-and-arguments depend on the specific command\n",
175 " (specify -H followed by a command name for command-specific help)\n",
176 " Specify --help to receive this message\n",
179 /* Some people think that a bug-reporting address should go here. IMHO,
180 the web sites are better because anything else is very likely to go
181 obsolete in the years between a release and when someone might be
182 reading this help. Besides, we could never adequately discuss
183 bug reporting in a concise enough way to put in a help message. */
185 /* I was going to put this at the top, but usage() wants the %s to
186 be in the first line. */
187 "The Concurrent Versions System (CVS) is a tool for version control.\n",
188 /* I really don't think I want to try to define "version control"
189 in one line. I'm not sure one can get more concise than the
190 paragraph in ../cvs.spec without assuming the reader knows what
191 version control means. */
193 "For CVS updates and additional information, see\n",
194 " the CVS home page at http://www.cvshome.org/ or\n",
195 " Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
199 static const char *const cmd_usage[] =
201 "CVS commands are:\n",
202 " add Add a new file/directory to the repository\n",
203 " admin Administration front end for rcs\n",
204 " annotate Show last revision where each line was modified\n",
205 " checkout Checkout sources for editing\n",
206 " commit Check files into the repository\n",
207 " diff Show differences between revisions\n",
208 " edit Get ready to edit a watched file\n",
209 " editors See who is editing a watched file\n",
210 " export Export sources from CVS, similar to checkout\n",
211 " history Show repository access history\n",
212 " import Import sources into CVS, using vendor branches\n",
213 " init Create a CVS repository if it doesn't exist\n",
214 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
215 " kserver Kerberos server mode\n",
217 " log Print out history information for files\n",
218 #ifdef AUTH_CLIENT_SUPPORT
219 " login Prompt for password for authenticating server\n",
220 " logout Removes entry in .cvspass for remote repository\n",
221 #endif /* AUTH_CLIENT_SUPPORT */
222 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
223 " pserver Password server mode\n",
225 " rannotate Show last revision where each line of module was modified\n",
226 " rdiff Create 'patch' format diffs between releases\n",
227 " release Indicate that a Module is no longer in use\n",
228 " remove Remove an entry from the repository\n",
229 " rlog Print out history information for a module\n",
230 " rtag Add a symbolic tag to a module\n",
231 #ifdef SERVER_SUPPORT
232 " server Server mode\n",
234 " status Display status information on checked out files\n",
235 " tag Add a symbolic tag to checked out version of files\n",
236 " unedit Undo an edit command\n",
237 " update Bring work tree in sync with repository\n",
238 " version Show current CVS version(s)\n",
239 " watch Set watches\n",
240 " watchers See who is watching a file\n",
241 "(Specify the --help option for a list of other help options)\n",
245 static const char *const opt_usage[] =
247 /* Omit -b because it is just for compatibility. */
248 "CVS global options (specified before the command name) are:\n",
249 " -H Displays usage information for command.\n",
250 " -Q Cause CVS to be really quiet.\n",
251 " -q Cause CVS to be somewhat quiet.\n",
252 " -r Make checked-out files read-only.\n",
253 " -w Make checked-out files read-write (default).\n",
254 " -g Force group-write perms on checked-out files.\n",
255 " -n Do not execute anything that will change the disk.\n",
256 " -t Show trace of program execution -- try with -n.\n",
257 " -R Assume repository is read-only, such as CDROM\n",
258 " -v CVS version and copyright.\n",
259 " -T tmpdir Use 'tmpdir' for temporary files.\n",
260 " -e editor Use 'editor' for editing log information.\n",
261 " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
262 " -f Do not use the ~/.cvsrc file.\n",
263 #ifdef CLIENT_SUPPORT
264 " -z # Use compression level '#' for net traffic.\n",
266 " -x Encrypt all net traffic.\n",
268 " -a Authenticate all net traffic.\n",
270 " -s VAR=VAL Set CVS user variable.\n",
271 "(Specify the --help option for a list of other help options)\n",
277 set_root_directory (p, ignored)
281 if (current_root == NULL && p->data == NULL)
283 current_root = p->key;
290 static const char * const*
295 const struct cmd *c = &cmds[0];
296 /* Three more for title, "specify --help" line, and NULL. */
299 while (c->fullname != NULL)
305 synonyms = (char **) xmalloc(numcmds * sizeof(char *));
307 *line++ = "CVS command synonyms are:\n";
308 for (c = &cmds[0]; c->fullname != NULL; c++)
310 if (c->nick1 || c->nick2)
312 *line = xmalloc (strlen (c->fullname)
313 + (c->nick1 != NULL ? strlen (c->nick1) : 0)
314 + (c->nick2 != NULL ? strlen (c->nick2) : 0)
316 sprintf(*line, " %-12s %s %s\n", c->fullname,
317 c->nick1 ? c->nick1 : "",
318 c->nick2 ? c->nick2 : "");
322 *line++ = "(Specify the --help option for a list of other help options)\n";
325 return (const char * const*) synonyms; /* will never be freed */
330 lookup_command_attribute (cmd_name)
333 const struct cmd *cm;
335 for (cm = cmds; cm->fullname; cm++)
337 if (strcmp (cmd_name, cm->fullname) == 0)
341 error (1, 0, "unknown command: %s", cmd_name);
350 #ifndef DONT_USE_SIGNALS
378 name = "broken pipe";
383 name = "termination";
387 /* This case should never be reached, because we list above all
388 the signals for which we actually establish a signal handler. */
389 sprintf (temp, "%d", sig);
394 error (1, 0, "received %s signal", name);
395 #endif /* !DONT_USE_SIGNALS */
403 char *CVSroot = CVSROOT_DFLT;
405 const struct cmd *cm;
407 int tmpdir_update_env, cvs_update_env;
408 int free_CVSroot = 0;
412 int help = 0; /* Has the user asked for help? This
413 lets us support the `cvs -H cmd'
414 convention to give help for cmd. */
415 static const char short_options[] = "+QqgrwtnRvb:T:e:d:Hfz:s:xaU";
416 static struct option long_options[] =
418 {"help", 0, NULL, 'H'},
419 {"version", 0, NULL, 'v'},
420 {"help-commands", 0, NULL, 1},
421 {"help-synonyms", 0, NULL, 2},
422 {"help-options", 0, NULL, 4},
423 {"allow-root", required_argument, NULL, 3},
426 /* `getopt_long' stores the option index here, but right now we
428 int option_index = 0;
430 #ifdef SYSTEM_INITIALIZE
431 /* Hook for OS-specific behavior, for example socket subsystems on
432 NT and OS2 or dealing with windows and arguments on Mac. */
433 SYSTEM_INITIALIZE (&argc, &argv);
437 /* On systems that have tzset (which is almost all the ones I know
438 of), it's a good idea to call it. */
443 * Just save the last component of the path for error messages
445 program_path = xstrdup (argv[0]);
446 #ifdef ARGV0_NOT_PROGRAM_NAME
447 /* On some systems, e.g. VMS, argv[0] is not the name of the command
448 which the user types to invoke the program. */
449 program_name = "cvs";
451 program_name = last_component (argv[0]);
455 * Query the environment variables up-front, so that
456 * they can be overridden by command line arguments
459 tmpdir_update_env = *Tmpdir; /* TMPDIR_DFLT must be set */
460 if ((cp = getenv (TMPDIR_ENV)) != NULL)
463 tmpdir_update_env = 0; /* it's already there */
465 if ((cp = getenv (EDITOR1_ENV)) != NULL)
467 else if ((cp = getenv (EDITOR2_ENV)) != NULL)
469 else if ((cp = getenv (EDITOR3_ENV)) != NULL)
471 if ((cp = getenv (CVSROOT_ENV)) != NULL)
474 cvs_update_env = 0; /* it's already there */
476 if (getenv (CVSREAD_ENV) != NULL)
478 if (getenv (CVSREADONLYFS_ENV) != NULL) {
483 prepend_default_options (getenv ("CVS_OPTIONS"), &argc, &argv);
485 /* Set this to 0 to force getopt initialization. getopt() sets
486 this to 1 internally. */
489 /* We have to parse the options twice because else there is no
490 chance to avoid reading the global options from ".cvsrc". Set
491 opterr to 0 for avoiding error messages about invalid options.
495 while ((c = getopt_long
496 (argc, argv, short_options, long_options, &option_index))
504 * Scan cvsrc file for global options.
507 read_cvsrc (&argc, &argv, "cvs");
512 while ((c = getopt_long
513 (argc, argv, short_options, long_options, &option_index))
519 /* --help-commands */
523 /* --help-synonyms */
524 usage (cmd_synonyms());
532 root_allow_add (optarg);
548 * force full group write perms (used for shared checked-out
549 * source trees, see manual page)
551 umask(umask(077) & 007);
565 (void) fputs ("\n", stdout);
566 version (0, (char **) NULL);
567 (void) fputs ("\n", stdout);
569 Copyright (c) 1989-2004 Brian Berliner, david d `zoo' zuhn, \n\
570 Jeff Polk, and other authors\n", stdout);
571 (void) fputs ("\n", stdout);
572 (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
573 (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
574 (void) fputs ("\n", stdout);
576 (void) fputs ("Specify the --help option for further information about CVS\n", stdout);
581 /* This option used to specify the directory for RCS
582 executables. But since we don't run them any more,
583 this is a noop. Silently ignore it so that .cvsrc
584 and scripts and inetd.conf and such can work with
585 either new or old CVS. */
588 Tmpdir = xstrdup (optarg);
590 tmpdir_update_env = 1; /* need to update environment */
593 Editor = xstrdup (optarg);
597 if (CVSroot_cmdline != NULL)
598 free (CVSroot_cmdline);
599 CVSroot_cmdline = xstrdup (optarg);
602 CVSroot = xstrdup (optarg);
604 cvs_update_env = 1; /* need to update environment */
610 use_cvsrc = 0; /* unnecessary, since we've done it above */
613 #ifdef CLIENT_SUPPORT
614 gzip_level = strtol (optarg, &end, 10);
615 if (*end != '\0' || gzip_level < 0 || gzip_level > 9)
617 "gzip compression level must be between 0 and 9");
618 #endif /* CLIENT_SUPPORT */
619 /* If no CLIENT_SUPPORT, we just silently ignore the gzip
620 * level, so that users can have it in their .cvsrc and not
623 * We still parse the argument to -z for correctness since
624 * one user complained of being bitten by a run of
625 * `cvs -z -n up' which read -n as the argument to -z without
629 variable_set (optarg);
632 #ifdef CLIENT_SUPPORT
634 #endif /* CLIENT_SUPPORT */
635 /* If no CLIENT_SUPPORT, ignore -x, so that users can
636 have it in their .cvsrc and not cause any trouble.
637 If no ENCRYPTION, we still accept -x, but issue an
638 error if we are being run as a client. */
641 #ifdef CLIENT_SUPPORT
644 /* If no CLIENT_SUPPORT, ignore -a, so that users can
645 have it in their .cvsrc and not cause any trouble.
646 We will issue an error later if stream
647 authentication is not supported. */
650 #ifdef SERVER_SUPPORT
651 require_real_user = 1;
666 /* Look up the command name. */
668 cvs_cmd_name = argv[0];
669 for (cm = cmds; cm->fullname; cm++)
671 if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1))
673 if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2))
675 if (!strcmp (cvs_cmd_name, cm->fullname))
681 fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name);
685 cvs_cmd_name = cm->fullname; /* Global pointer for later use */
689 argc = -1; /* some functions only check for this */
690 err = (*(cm->func)) (argc, argv);
694 /* The user didn't ask for help, so go ahead and authenticate,
695 set up CVSROOT, and the rest of it. */
697 /* The UMASK environment variable isn't handled with the
698 others above, since we don't want to signal errors if the
699 user has asked for help. This won't work if somebody adds
700 a command-line flag to set the umask, since we'll have to
701 parse it before we get here. */
703 if ((cp = getenv (CVSUMASK_ENV)) != NULL)
705 /* FIXME: Should be accepting symbolic as well as numeric mask. */
706 cvsumask = strtol (cp, &end, 8) & 0777;
708 error (1, errno, "invalid umask value in %s (%s)",
712 #ifdef SERVER_SUPPORT
714 # ifdef HAVE_KERBEROS
715 /* If we are invoked with a single argument "kserver", then we are
716 running as Kerberos server as root. Do the authentication as
717 the very first thing, to minimize the amount of time we are
719 if (strcmp (cvs_cmd_name, "kserver") == 0)
721 kserver_authenticate_connection ();
723 /* Pretend we were invoked as a plain server. */
724 cvs_cmd_name = "server";
726 # endif /* HAVE_KERBEROS */
729 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
730 if (strcmp (cvs_cmd_name, "pserver") == 0)
732 /* The reason that --allow-root is not a command option
733 is mainly the comment in server() about how argc,argv
734 might be from .cvsrc. I'm not sure about that, and
735 I'm not sure it is only true of command options, but
736 it seems easier to make it a global option. */
738 /* Gets username and password from client, authenticates, then
739 switches to run as that user and sends an ACK back to the
741 pserver_authenticate_connection ();
743 /* Pretend we were invoked as a plain server. */
744 cvs_cmd_name = "server";
746 # endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
748 server_active = strcmp (cvs_cmd_name, "server") == 0;
750 #endif /* SERVER_SUPPORT */
752 /* This is only used for writing into the history file. For
753 remote connections, it might be nice to have hostname
754 and/or remote path, on the other hand I'm not sure whether
755 it is worth the trouble. */
757 #ifdef SERVER_SUPPORT
759 CurDir = xstrdup ("<remote>");
765 error (1, errno, "cannot get working directory");
768 if (Tmpdir == NULL || Tmpdir[0] == '\0')
772 if (tmpdir_update_env)
775 env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1);
776 (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir);
778 /* do not free env, as putenv has control of it */
782 env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */
783 (void) sprintf (env, "CVS_PID=%ld", (long) getpid ());
788 #ifndef DONT_USE_SIGNALS
789 /* make sure we clean up on error */
791 (void) SIG_register (SIGABRT, main_cleanup);
794 (void) SIG_register (SIGHUP, main_cleanup);
797 (void) SIG_register (SIGINT, main_cleanup);
800 (void) SIG_register (SIGQUIT, main_cleanup);
803 (void) SIG_register (SIGPIPE, main_cleanup);
806 (void) SIG_register (SIGTERM, main_cleanup);
808 #endif /* !DONT_USE_SIGNALS */
810 gethostname(hostname, sizeof (hostname));
812 #ifdef KLUDGE_FOR_WNT_TESTSUITE
813 /* Probably the need for this will go away at some point once
814 we call fflush enough places (e.g. fflush (stdout) in
816 (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
817 (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
818 #endif /* KLUDGE_FOR_WNT_TESTSUITE */
821 read_cvsrc (&argc, &argv, cvs_cmd_name);
823 #ifdef SERVER_SUPPORT
824 /* Fiddling with CVSROOT doesn't make sense if we're running
825 in server mode, since the client will send the repository
826 directory after the connection is made. */
833 /* See if we are able to find a 'better' value for CVSroot
834 in the CVSADM_ROOT directory. */
838 /* "cvs import" shouldn't check CVS/Root; in general it
839 ignores CVS directories and CVS/Root is likely to
840 specify a different repository than the one we are
843 if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT)
845 /* -d overrides CVS/Root, so don't give an error if the
846 latter points to a nonexistent repository. */
847 && CVSroot_cmdline == NULL)
849 CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
852 if (CVSADM_Root != NULL)
854 if (CVSroot == NULL || !cvs_update_env)
856 CVSroot = CVSADM_Root;
857 cvs_update_env = 1; /* need to update environment */
861 /* Now we've reconciled CVSROOT from the command line, the
862 CVS/Root file, and the environment variable. Do the
863 last sanity checks on the variable. */
868 "No CVSROOT specified! Please use the `-d' option");
870 "or set the %s environment variable.", CVSROOT_ENV);
876 "CVSROOT is set but empty! Make sure that the");
878 "specification of CVSROOT is valid, either via the");
880 "`-d' option, the %s environment variable, or the",
883 "CVS/Root file (if any).");
887 /* Here begins the big loop over unique cvsroot values. We
888 need to call do_recursion once for each unique value found
889 in CVS/Root. Prime the list with the current value. */
891 /* Create the list. */
892 assert (root_directories == NULL);
893 root_directories = getlist ();
900 n->type = NT_UNKNOWN;
901 n->key = xstrdup (CVSroot);
904 if (addnode (root_directories, n))
905 error (1, 0, "cannot add initial CVSROOT %s", n->key);
908 assert (current_root == NULL);
910 /* If we're running the server, we want to execute this main
911 loop once and only once (we won't be serving multiple roots
912 from this connection, so there's no need to do it more than
913 once). To get out of the loop, we perform a "break" at the
917 #ifdef SERVER_SUPPORT
920 walklist (root_directories, set_root_directory, NULL)
923 #ifdef SERVER_SUPPORT
924 /* Fiddling with CVSROOT doesn't make sense if we're running
925 in server mode, since the client will send the repository
926 directory after the connection is made. */
931 /* Now we're 100% sure that we have a valid CVSROOT
932 variable. Parse it to see if we're supposed to do
933 remote accesses or use a special access method. */
935 if (current_parsed_root != NULL)
936 free_cvsroot_t (current_parsed_root);
937 if ((current_parsed_root = parse_cvsroot (current_root)) == NULL)
938 error (1, 0, "Bad CVSROOT: `%s'.", current_root);
941 fprintf (stderr, "%s-> main loop with CVSROOT=%s\n",
942 CLIENT_SERVER_STR, current_root);
945 * Check to see if the repository exists.
947 #ifdef CLIENT_SUPPORT
948 if (!current_parsed_root->isremote)
949 #endif /* CLIENT_SUPPORT */
954 path = xmalloc (strlen (current_parsed_root->directory)
955 + sizeof (CVSROOTADM)
957 (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
958 if (!isaccessible (path, R_OK | X_OK))
961 /* If this is "cvs init", the root need not exist yet. */
962 if (strcmp (cvs_cmd_name, "init") != 0)
964 error (1, save_errno, "%s", path);
971 /* Update the CVSROOT environment variable if necessary. */
972 /* FIXME (njc): should we always set this with the CVSROOT from the command line? */
977 env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
979 (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
981 /* do not free env yet, as putenv has control of it */
982 /* but do free the previous value, if any */
990 /* Parse the CVSROOT/config file, but only for local. For the
991 server, we parse it after we know $CVSROOT. For the
992 client, it doesn't get parsed at all, obviously. The
993 presence of the parse_config call here is not mean to
994 predetermine whether CVSROOT/config overrides things from
995 read_cvsrc and other such places or vice versa. That sort
996 of thing probably needs more thought. */
998 #ifdef SERVER_SUPPORT
1001 #ifdef CLIENT_SUPPORT
1002 && !current_parsed_root->isremote
1006 /* If there was an error parsing the config file, parse_config
1007 already printed an error. We keep going. Why? Because
1008 if we didn't, then there would be no way to check in a new
1009 CVSROOT/config file to fix the broken one! */
1010 parse_config (current_parsed_root->directory);
1012 /* Now is a convenient time to read CVSROOT/options */
1013 parseopts(current_parsed_root->directory);
1016 #ifdef CLIENT_SUPPORT
1017 /* Need to check for current_parsed_root != NULL here since
1018 * we could still be in server mode before the server function
1019 * gets called below and sets the root
1021 if (current_parsed_root != NULL && current_parsed_root->isremote)
1023 /* Create a new list for directory names that we've
1024 sent to the server. */
1025 if (dirs_sent_to_server != NULL)
1026 dellist (&dirs_sent_to_server);
1027 dirs_sent_to_server = getlist ();
1031 err = (*(cm->func)) (argc, argv);
1033 /* Mark this root directory as done. When the server is
1034 active, current_root will be NULL -- don't try and
1035 remove it from the list. */
1037 if (current_root != NULL)
1039 Node *n = findnode (root_directories, current_root);
1041 n->data = (void *) 1;
1042 current_root = NULL;
1046 /* This will not work yet, since it tries to free (void *) 1. */
1047 dellist (&root_directories);
1050 #ifdef SERVER_SUPPORT
1057 } /* end of loop for cvsroot values */
1059 } /* end of stuff that gets done if the user DOESN'T ask for help */
1063 /* It's okay to cast out the const below since we know we allocated this in
1064 * this function. The const was to keep other functions from messing with
1067 free ((char *)program_path);
1068 if (CVSroot_cmdline != NULL)
1069 free (CVSroot_cmdline);
1078 #ifdef SYSTEM_CLEANUP
1079 /* Hook for OS-specific behavior, for example socket subsystems on
1080 NT and OS2 or dealing with windows and arguments on Mac. */
1084 /* This is exit rather than return because apparently that keeps
1085 some tools which check for memory leaks happier. */
1086 exit (err ? EXIT_FAILURE : 0);
1087 /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */
1097 unixtime = get_date (rawdate, (struct timeb *) NULL);
1098 if (unixtime == (time_t) - 1)
1099 error (1, 0, "Can't parse date/time: %s", rawdate);
1100 return date_from_time_t (unixtime);
1103 /* Convert a time_t to an RCS format date. This is mainly for the
1104 use of "cvs history", because the CVSROOT/history file contains
1105 time_t format dates; most parts of CVS will want to avoid using
1106 time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
1107 Assuming that the time_t is in GMT (as it generally should be),
1108 then the result will be in GMT too.
1110 Returns a newly malloc'd string. */
1113 date_from_time_t (unixtime)
1117 char date[MAXDATELEN];
1120 ftm = gmtime (&unixtime);
1122 /* This is a system, like VMS, where the system clock is in local
1123 time. Hopefully using localtime here matches the "zero timezone"
1124 hack I added to get_date (get_date of course being the relevant
1125 issue for Make_Date, and for history.c too I think). */
1126 ftm = localtime (&unixtime);
1128 (void) sprintf (date, DATEFORM,
1129 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1130 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1131 ftm->tm_min, ftm->tm_sec);
1132 ret = xstrdup (date);
1136 /* Convert a date to RFC822/1123 format. This is used in contexts like
1137 dates to send in the protocol; it should not vary based on locale or
1138 other such conventions for users. We should have another routine which
1139 does that kind of thing.
1141 The SOURCE date is in our internal RCS format. DEST should point to
1142 storage managed by the caller, at least MAXDATELEN characters. */
1144 date_to_internet (dest, source)
1150 date_to_tm (&date, source);
1151 tm_to_internet (dest, &date);
1155 date_to_tm (dest, source)
1159 if (sscanf (source, SDATEFORM,
1160 &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
1161 &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
1163 /* Is there a better way to handle errors here? I made this
1164 non-fatal in case we are called from the code which can't
1165 deal with fatal errors. */
1166 error (0, 0, "internal error: bad date %s", source);
1168 if (dest->tm_year > 100)
1169 dest->tm_year -= 1900;
1174 /* Convert a date to RFC822/1123 format. This is used in contexts like
1175 dates to send in the protocol; it should not vary based on locale or
1176 other such conventions for users. We should have another routine which
1177 does that kind of thing.
1179 The SOURCE date is a pointer to a struct tm. DEST should point to
1180 storage managed by the caller, at least MAXDATELEN characters. */
1182 tm_to_internet (dest, source)
1184 const struct tm *source;
1186 /* Just to reiterate, these strings are from RFC822 and do not vary
1187 according to locale. */
1188 static const char *const month_names[] =
1189 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1190 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1192 sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday,
1193 source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon],
1194 source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec);
1199 register const char *const *cpp;
1201 (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
1203 (void) fprintf (stderr, *cpp);
1211 char path[PATH_MAX];
1219 printf("no CVSROOT in parseopts\n");
1222 p = strchr (root, ':');
1228 printf("mangled CVSROOT in parseopts\n");
1231 (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
1232 if ((fp = fopen(path, "r")) != NULL) {
1233 while (fgets(buf, sizeof buf, fp) != NULL) {
1236 q = strrchr(buf, '\n');
1240 if (!strcmp(buf, "iso8601")) {
1243 if (!strncmp(buf, "tag=", 4)) {
1247 rcs_localid = buf + 4;
1248 RCS_setlocalid(rcs_localid);
1250 if (!strncmp(buf, "tagexpand=", 10)) {
1254 rcs_incexc = buf + 10;
1255 RCS_setincexc(rcs_incexc);
1258 * OpenBSD has a "umask=" and "dlimit=" command, we silently
1259 * ignore them here since they are not much use to us. cvsumask
1260 * defaults to 002 already, and the dlimit (data size limit)
1261 * should really be handled elsewhere (eg: login.conf).