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
;
47 const char *cvsDir
= "CVS";
53 *** CVSROOT/config options
56 struct config
*config
;
60 mode_t cvsumask
= UMASK_DFLT
;
65 * Defaults, for the environment variables that are not set
67 char *Editor
= EDITOR_DFLT
;
73 /* Temp dir, if set by the user. */
74 static char *tmpdir_cmdline
;
78 /* Returns in order of precedence:
80 * 1. Temp dir as set via the command line.
81 * 2. Temp dir as set in CVSROOT/config.
82 * 3. Temp dir as set in $TMPDIR env var.
83 * 4. Contents of TMPDIR_DFLT preprocessor macro.
86 * It is a fatal error if this function would otherwise return NULL or an
90 get_cvs_tmp_dir (void)
93 if (tmpdir_cmdline
) retval
= tmpdir_cmdline
;
94 else if (config
&& config
->TmpDir
) retval
= config
->TmpDir
;
95 else retval
= get_system_temp_dir ();
96 if (!retval
) retval
= TMPDIR_DFLT
;
98 if (!retval
|| !*retval
) error (1, 0, "No temp dir specified.");
105 /* When our working directory contains subdirectories with different
106 values in CVS/Root files, we maintain a list of them. */
107 List
*root_directories
= NULL
;
109 static const struct cmd
111 const char *fullname
; /* Full name of the function (e.g. "commit") */
113 /* Synonyms for the command, nick1 and nick2. We supply them
114 mostly for two reasons: (1) CVS has always supported them, and
115 we need to maintain compatibility, (2) if there is a need for a
116 version which is shorter than the fullname, for ease in typing.
117 Synonyms have the disadvantage that people will see "new" and
118 then have to think about it, or look it up, to realize that is
119 the operation they know as "add". Also, this means that one
120 cannot create a command "cvs new" with a different meaning. So
121 new synonyms are probably best used sparingly, and where used
122 should be abbreviations of the fullname (preferably consisting
123 of the first 2 or 3 or so letters).
125 One thing that some systems do is to recognize any unique
126 abbreviation, for example "annotat" "annota", etc., for
127 "annotate". The problem with this is that scripts and user
128 habits will expect a certain abbreviation to be unique, and in
129 a future release of CVS it may not be. So it is better to
130 accept only an explicit list of abbreviations and plan on
131 supporting them in the future as well as now. */
136 int (*func
) (int, char **); /* Function takes (argc, argv) arguments. */
137 unsigned long attr
; /* Attributes. */
141 { "add", "ad", "new", add
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
142 { "admin", "adm", "rcs", admin
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
143 { "annotate", "ann", NULL
, annotate
, CVS_CMD_USES_WORK_DIR
},
144 { "checkout", "co", "get", checkout
, 0 },
145 { "commit", "ci", "com", commit
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
146 { "diff", "di", "dif", diff
, CVS_CMD_USES_WORK_DIR
},
147 { "edit", NULL
, NULL
, edit
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
148 { "editors", NULL
, NULL
, editors
, CVS_CMD_USES_WORK_DIR
},
149 { "export", "exp", "ex", checkout
, CVS_CMD_USES_WORK_DIR
},
150 { "history", "hi", "his", history
, CVS_CMD_USES_WORK_DIR
},
151 { "import", "im", "imp", import
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
| CVS_CMD_IGNORE_ADMROOT
},
152 { "init", NULL
, NULL
, init
, CVS_CMD_MODIFIES_REPOSITORY
},
153 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
154 { "kserver", NULL
, NULL
, server
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
}, /* placeholder */
156 { "log", "lo", NULL
, cvslog
, CVS_CMD_USES_WORK_DIR
},
157 #ifdef AUTH_CLIENT_SUPPORT
158 { "login", "logon", "lgn", login
, 0 },
159 { "logout", NULL
, NULL
, logout
, 0 },
160 #endif /* AUTH_CLIENT_SUPPORT */
161 { "ls", "dir", "list", ls
, 0 },
162 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
163 { "pserver", NULL
, NULL
, server
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
}, /* placeholder */
165 { "rannotate","rann", "ra", annotate
, 0 },
166 { "rdiff", "patch", "pa", patch
, 0 },
167 { "release", "re", "rel", release
, CVS_CMD_MODIFIES_REPOSITORY
},
168 { "remove", "rm", "delete", cvsremove
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
169 { "rlog", "rl", NULL
, cvslog
, 0 },
170 { "rls", "rdir", "rlist", ls
, 0 },
171 { "rtag", "rt", "rfreeze", cvstag
, CVS_CMD_MODIFIES_REPOSITORY
},
172 #ifdef SERVER_SUPPORT
173 { "server", NULL
, NULL
, server
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
175 { "status", "st", "stat", cvsstatus
, CVS_CMD_USES_WORK_DIR
},
176 { "tag", "ta", "freeze", cvstag
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
177 { "unedit", NULL
, NULL
, unedit
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
178 { "update", "up", "upd", update
, CVS_CMD_USES_WORK_DIR
},
179 { "version", "ve", "ver", version
, 0 },
180 { "watch", NULL
, NULL
, watch
, CVS_CMD_MODIFIES_REPOSITORY
| CVS_CMD_USES_WORK_DIR
},
181 { "watchers", NULL
, NULL
, watchers
, CVS_CMD_USES_WORK_DIR
},
182 { NULL
, NULL
, NULL
, NULL
, 0 },
185 static const char *const usg
[] =
187 /* CVS usage messages never have followed the GNU convention of
188 putting metavariables in uppercase. I don't know whether that
189 is a good convention or not, but if it changes it would have to
190 change in all the usage messages. For now, they consistently
191 use lowercase, as far as I know. Punctuation is pretty funky,
192 though. Sometimes they use none, as here. Sometimes they use
193 single quotes (not the TeX-ish `' stuff), as in --help-options.
194 Sometimes they use double quotes, as in cvs -H add.
196 Most (not all) of the usage messages seem to have periods at
197 the end of each line. I haven't tried to duplicate this style
198 in --help as it is a rather different format from the rest. */
200 "Usage: %s [cvs-options] command [command-options-and-arguments]\n",
201 " where cvs-options are -q, -n, etc.\n",
202 " (specify --help-options for a list of options)\n",
203 " where command is add, admin, etc.\n",
204 " (specify --help-commands for a list of commands\n",
205 " or --help-synonyms for a list of command synonyms)\n",
206 " where command-options-and-arguments depend on the specific command\n",
207 " (specify -H followed by a command name for command-specific help)\n",
208 " Specify --help to receive this message\n",
211 /* Some people think that a bug-reporting address should go here. IMHO,
212 the web sites are better because anything else is very likely to go
213 obsolete in the years between a release and when someone might be
214 reading this help. Besides, we could never adequately discuss
215 bug reporting in a concise enough way to put in a help message. */
217 /* I was going to put this at the top, but usage() wants the %s to
218 be in the first line. */
219 "The Concurrent Versions System (CVS) is a tool for version control.\n",
220 /* I really don't think I want to try to define "version control"
221 in one line. I'm not sure one can get more concise than the
222 paragraph in ../cvs.spec without assuming the reader knows what
223 version control means. */
225 "For CVS updates and additional information, see\n",
226 " the CVS home page at http://www.nongnu.org/cvs/ or\n",
227 " the CVSNT home page at http://www.cvsnt.org/\n",
231 static const char *const cmd_usage
[] =
233 "CVS commands are:\n",
234 " add Add a new file/directory to the repository\n",
235 " admin Administration front end for rcs\n",
236 " annotate Show last revision where each line was modified\n",
237 " checkout Checkout sources for editing\n",
238 " commit Check files into the repository\n",
239 " diff Show differences between revisions\n",
240 " edit Get ready to edit a watched file\n",
241 " editors See who is editing a watched file\n",
242 " export Export sources from CVS, similar to checkout\n",
243 " history Show repository access history\n",
244 " import Import sources into CVS, using vendor branches\n",
245 " init Create a CVS repository if it doesn't exist\n",
246 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
247 " kserver Kerberos server mode\n",
249 " log Print out history information for files\n",
250 #ifdef AUTH_CLIENT_SUPPORT
251 " login Prompt for password for authenticating server\n",
252 " logout Removes entry in .cvspass for remote repository\n",
253 #endif /* AUTH_CLIENT_SUPPORT */
254 " ls List files available from CVS\n",
255 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
256 " pserver Password server mode\n",
258 " rannotate Show last revision where each line of module was modified\n",
259 " rdiff Create 'patch' format diffs between releases\n",
260 " release Indicate that a Module is no longer in use\n",
261 " remove Remove an entry from the repository\n",
262 " rlog Print out history information for a module\n",
263 " rls List files in a module\n",
264 " rtag Add a symbolic tag to a module\n",
265 #ifdef SERVER_SUPPORT
266 " server Server mode\n",
268 " status Display status information on checked out files\n",
269 " tag Add a symbolic tag to checked out version of files\n",
270 " unedit Undo an edit command\n",
271 " update Bring work tree in sync with repository\n",
272 " version Show current CVS version(s)\n",
273 " watch Set watches\n",
274 " watchers See who is watching a file\n",
275 "(Specify the --help option for a list of other help options)\n",
279 static const char *const opt_usage
[] =
281 /* Omit -b because it is just for compatibility. */
282 "CVS global options (specified before the command name) are:\n",
283 " -H Displays usage information for command.\n",
284 " -Q Cause CVS to be really quiet.\n",
285 " -q Cause CVS to be somewhat quiet.\n",
286 " -r Make checked-out files read-only.\n",
287 " -w Make checked-out files read-write (default).\n",
288 " -n Do not execute anything that will change the disk.\n",
289 " -u Don't create locks (implies -l).\n",
290 " -t Show trace of program execution (repeat for more\n",
291 " verbosity) -- try with -n.\n",
292 " -R Assume repository is read-only, such as CDROM\n",
293 " -v CVS version and copyright.\n",
294 " -T tmpdir Use 'tmpdir' for temporary files.\n",
295 " -e editor Use 'editor' for editing log information.\n",
296 " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
297 " -D dir Use DIR as the bookkeeping directory instead of CVS.\n"
298 " -f Do not use the ~/.cvsrc file.\n",
299 #ifdef CLIENT_SUPPORT
300 " -z # Request compression level '#' for net traffic.\n",
302 " -x Encrypt all net traffic.\n",
304 " -a Authenticate all net traffic.\n",
306 " -s VAR=VAL Set CVS user variable.\n",
307 "(Specify the --help option for a list of other help options)\n",
313 set_root_directory (Node
*p
, void *ignored
)
315 if (current_parsed_root
== NULL
&& p
->data
!= NULL
)
317 current_parsed_root
= p
->data
;
318 original_parsed_root
= current_parsed_root
;
325 static const char * const*
330 const struct cmd
*c
= &cmds
[0];
331 /* Three more for title, "specify --help" line, and NULL. */
334 while (c
->fullname
!= NULL
)
340 synonyms
= xnmalloc (numcmds
, sizeof(char *));
342 *line
++ = "CVS command synonyms are:\n";
343 for (c
= &cmds
[0]; c
->fullname
!= NULL
; c
++)
345 if (c
->nick1
|| c
->nick2
)
347 *line
= Xasprintf (" %-12s %s %s\n", c
->fullname
,
348 c
->nick1
? c
->nick1
: "",
349 c
->nick2
? c
->nick2
: "");
353 *line
++ = "(Specify the --help option for a list of other help options)\n";
356 return (const char * const*) synonyms
; /* will never be freed */
362 lookup_command_attribute (const char *cmd_name
)
364 const struct cmd
*cm
;
366 for (cm
= cmds
; cm
->fullname
; cm
++)
368 if (strcmp (cmd_name
, cm
->fullname
) == 0)
372 error (1, 0, "unknown command: %s", cmd_name
);
379 * Exit with an error code and an informative message about the signal
380 * received. This function, by virtue of causing an actual call to exit(),
381 * causes all the atexit() handlers to be called.
384 * sig The signal recieved.
387 * The cleanup routines registered via atexit() and the error function
388 * itself can potentially change the exit status. They shouldn't do this
389 * unless they encounter problems doing their own jobs.
392 * Nothing. This function will always exit. It should exit with an exit
393 * status of 1, but might not, as noted in the ERRORS section above.
395 #ifndef DONT_USE_SIGNALS
396 static RETSIGTYPE
main_cleanup (int) __attribute__ ((__noreturn__
));
397 #endif /* DONT_USE_SIGNALS */
399 main_cleanup (int sig
)
401 #ifndef DONT_USE_SIGNALS
404 static int reenter
= 0;
433 name
= "broken pipe";
438 name
= "termination";
442 /* This case should never be reached, because we list above all
443 the signals for which we actually establish a signal handler. */
444 sprintf (temp
, "%d", sig
);
449 /* This always exits, which will cause our exit handlers to be called. */
450 error (1, 0, "received %s signal", name
);
451 /* but make the exit explicit to silence warnings when gcc processes the
452 * noreturn attribute.
455 #endif /* !DONT_USE_SIGNALS */
462 * When !defined ALLOW_CONFIG_OVERRIDE, this will never have any value but
465 extern char *gConfigPath
;
470 enum {RANDOM_BYTES
= 8};
471 enum {COMMITID_RAW_SIZE
= (sizeof(time_t) + RANDOM_BYTES
)};
473 static char const alphabet
[62] =
474 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
476 /* Divide BUF by D, returning the remainder. Replace BUF by the
477 quotient. BUF[0] is the most significant part of BUF.
478 D must not exceed UINT_MAX >> CHAR_BIT. */
480 divide_by (unsigned char buf
[COMMITID_RAW_SIZE
], unsigned int d
)
482 unsigned int carry
= 0;
484 for (i
= 0; i
< COMMITID_RAW_SIZE
; i
++)
486 unsigned int byte
= buf
[i
];
487 unsigned int dividend
= (carry
<< CHAR_BIT
) + byte
;
488 buf
[i
] = dividend
/ d
;
489 carry
= dividend
% d
;
495 convert (char const input
[COMMITID_RAW_SIZE
], char *output
)
497 static char const zero
[COMMITID_RAW_SIZE
] = { 0, };
498 unsigned char buf
[COMMITID_RAW_SIZE
];
500 memcpy (buf
, input
, COMMITID_RAW_SIZE
);
501 while (memcmp (buf
, zero
, COMMITID_RAW_SIZE
) != 0)
502 output
[o
++] = alphabet
[divide_by (buf
, sizeof alphabet
)];
510 main (int argc
, char **argv
)
512 cvsroot_t
*CVSroot_parsed
= NULL
;
513 bool cvsroot_update_env
= true;
515 const struct cmd
*cm
;
519 int help
= 0; /* Has the user asked for help? This
520 lets us support the `cvs -H cmd'
521 convention to give help for cmd. */
522 static const char short_options
[] = "+QqrwtlnRuvb:T:e:d:D:Hfz:s:xa";
523 static struct option long_options
[] =
525 {"help", 0, NULL
, 'H'},
526 {"version", 0, NULL
, 'v'},
527 {"help-commands", 0, NULL
, 1},
528 {"help-synonyms", 0, NULL
, 2},
529 {"help-options", 0, NULL
, 4},
530 #ifdef SERVER_SUPPORT
531 {"allow-root", required_argument
, NULL
, 3},
532 #endif /* SERVER_SUPPORT */
535 /* `getopt_long' stores the option index here, but right now we
537 int option_index
= 0;
539 #ifdef SYSTEM_INITIALIZE
540 /* Hook for OS-specific behavior, for example socket subsystems on
541 NT and OS2 or dealing with windows and arguments on Mac. */
542 SYSTEM_INITIALIZE (&argc
, &argv
);
545 #ifdef SYSTEM_CLEANUP
546 /* Hook for OS-specific behavior, for example socket subsystems on
547 NT and OS2 or dealing with windows and arguments on Mac. */
548 cleanup_register (SYSTEM_CLEANUP
);
552 /* On systems that have tzset (which is almost all the ones I know
553 of), it's a good idea to call it. */
558 * Just save the last component of the path for error messages
560 program_path
= xstrdup (argv
[0]);
561 #ifdef ARGV0_NOT_PROGRAM_NAME
562 /* On some systems, e.g. VMS, argv[0] is not the name of the command
563 which the user types to invoke the program. */
564 program_name
= "cvs";
566 program_name
= last_component (argv
[0]);
570 * Query the environment variables up-front, so that
571 * they can be overridden by command line arguments
573 if ((cp
= getenv (EDITOR1_ENV
)) != NULL
)
575 else if ((cp
= getenv (EDITOR2_ENV
)) != NULL
)
577 else if ((cp
= getenv (EDITOR3_ENV
)) != NULL
)
579 if (getenv (CVSREAD_ENV
) != NULL
)
581 if (getenv (CVSREADONLYFS_ENV
) != NULL
) {
586 /* Set this to 0 to force getopt initialization. getopt() sets
587 this to 1 internally. */
590 /* We have to parse the options twice because else there is no
591 chance to avoid reading the global options from ".cvsrc". Set
592 opterr to 0 for avoiding error messages about invalid options.
596 while ((c
= getopt_long
597 (argc
, argv
, short_options
, long_options
, &option_index
))
604 #ifdef SERVER_SUPPORT
605 /* Don't try and read a .cvsrc file if we are a server. */
608 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
609 || !strcmp (argv
[optind
], "pserver")
611 # ifdef HAVE_KERBEROS
612 || !strcmp (argv
[optind
], "kserver")
613 # endif /* HAVE_KERBEROS */
614 || !strcmp (argv
[optind
], "server")))
616 /* Avoid any .cvsrc file. */
618 /* Pre-parse the server options to get the config path. */
619 cvs_cmd_name
= argv
[optind
];
620 parseServerOptions (argc
- optind
, argv
+ optind
);
622 #endif /* SERVER_SUPPORT */
625 * Scan cvsrc file for global options.
628 read_cvsrc (&argc
, &argv
, "cvs");
631 while ((c
= getopt_long
632 (argc
, argv
, short_options
, long_options
, &option_index
))
638 /* --help-commands */
642 /* --help-synonyms */
643 usage (cmd_synonyms());
649 #ifdef SERVER_SUPPORT
652 root_allow_add (optarg
, gConfigPath
);
654 #endif /* SERVER_SUPPORT */
676 case 'u': /* Fall through */
678 case 'l': /* Fall through */
682 (void) fputs ("\n", stdout
);
684 (void) fputs ("\n", stdout
);
686 Copyright (C) 2005 Free Software Foundation, Inc.\n\
688 Senior active maintainers include Larry Jones, Derek R. Price,\n\
689 and Mark D. Baushke. Please see the AUTHORS and README files from the CVS\n\
690 distribution kit for a complete list of contributors and copyrights.\n",
692 (void) fputs ("\n", stdout
);
693 (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout
);
694 (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout
);
695 (void) fputs ("\n", stdout
);
697 (void) fputs ("Specify the --help option for further information about CVS\n", stdout
);
702 /* This option used to specify the directory for RCS
703 executables. But since we don't run them any more,
704 this is a noop. Silently ignore it so that .cvsrc
705 and scripts and inetd.conf and such can work with
706 either new or old CVS. */
709 if (tmpdir_cmdline
) free (tmpdir_cmdline
);
710 tmpdir_cmdline
= xstrdup (optarg
);
713 if (free_Editor
) free (Editor
);
714 Editor
= xstrdup (optarg
);
718 if (CVSroot_cmdline
!= NULL
)
719 free (CVSroot_cmdline
);
720 CVSroot_cmdline
= xstrdup (optarg
);
726 use_cvsrc
= 0; /* unnecessary, since we've done it above */
729 #ifdef CLIENT_SUPPORT
730 gzip_level
= strtol (optarg
, &end
, 10);
731 if (*end
!= '\0' || gzip_level
< 0 || gzip_level
> 9)
733 "gzip compression level must be between 0 and 9");
734 #endif /* CLIENT_SUPPORT */
735 /* If no CLIENT_SUPPORT, we just silently ignore the gzip
736 * level, so that users can have it in their .cvsrc and not
739 * We still parse the argument to -z for correctness since
740 * one user complained of being bitten by a run of
741 * `cvs -z -n up' which read -n as the argument to -z without
745 variable_set (optarg
);
748 #ifdef CLIENT_SUPPORT
750 #endif /* CLIENT_SUPPORT */
751 /* If no CLIENT_SUPPORT, ignore -x, so that users can
752 have it in their .cvsrc and not cause any trouble.
753 If no ENCRYPTION, we still accept -x, but issue an
754 error if we are being run as a client. */
757 #ifdef CLIENT_SUPPORT
760 /* If no CLIENT_SUPPORT, ignore -a, so that users can
761 have it in their .cvsrc and not cause any trouble.
762 We will issue an error later if stream
763 authentication is not supported. */
766 cvsDir
= xstrdup (optarg
);
767 if (strchr (cvsDir
, '/') != NULL
)
768 error (1, 0, "cvsDir is not allowed to have slashes");
781 if (readonlyfs
&& !really_quiet
) {
783 "WARNING: Read-only repository access mode selected via `cvs -R'.\n\
784 Using this option to access a repository which some users write to may\n\
785 cause intermittent sandbox corruption.");
788 /* Calculate the cvs global session ID */
791 char buf
[COMMITID_RAW_SIZE
] = { 0, };
792 char out
[COMMITID_RAW_SIZE
* 2];
794 time_t rightnow
= time (NULL
);
795 char *startrand
= buf
+ sizeof (time_t);
796 unsigned char *p
= (unsigned char *) startrand
;
797 size_t randbytes
= RANDOM_BYTES
;
798 int flags
= O_RDONLY
;
803 if (rightnow
!= (time_t)-1)
804 while (rightnow
> 0) {
805 *--p
= rightnow
% (UCHAR_MAX
+ 1);
806 rightnow
/= UCHAR_MAX
+ 1;
809 /* try to use more random data */
810 randbytes
= COMMITID_RAW_SIZE
;
813 fd
= open ("/dev/urandom", flags
);
815 len
= read (fd
, startrand
, randbytes
);
819 /* no random data was available so use pid */
820 long int pid
= (long int)getpid ();
821 p
= (unsigned char *) (startrand
+ sizeof (pid
));
823 *--p
= pid
% (UCHAR_MAX
+ 1);
824 pid
/= UCHAR_MAX
+ 1;
828 global_session_id
= strdup (out
);
832 TRACE (TRACE_FUNCTION
, "main: Session ID is %s", global_session_id
);
834 /* Look up the command name. */
836 cvs_cmd_name
= argv
[0];
837 for (cm
= cmds
; cm
->fullname
; cm
++)
839 if (cm
->nick1
&& !strcmp (cvs_cmd_name
, cm
->nick1
))
841 if (cm
->nick2
&& !strcmp (cvs_cmd_name
, cm
->nick2
))
843 if (!strcmp (cvs_cmd_name
, cm
->fullname
))
849 fprintf (stderr
, "Unknown command: `%s'\n\n", cvs_cmd_name
);
853 cvs_cmd_name
= cm
->fullname
; /* Global pointer for later use */
857 argc
= -1; /* some functions only check for this */
858 err
= (*(cm
->func
)) (argc
, argv
);
862 /* The user didn't ask for help, so go ahead and authenticate,
863 set up CVSROOT, and the rest of it. */
865 short int lock_cleanup_setup
= 0;
867 /* The UMASK environment variable isn't handled with the
868 others above, since we don't want to signal errors if the
869 user has asked for help. This won't work if somebody adds
870 a command-line flag to set the umask, since we'll have to
871 parse it before we get here. */
873 if ((cp
= getenv (CVSUMASK_ENV
)) != NULL
)
875 /* FIXME: Should be accepting symbolic as well as numeric mask. */
876 cvsumask
= strtol (cp
, &end
, 8) & 0777;
878 error (1, errno
, "invalid umask value in %s (%s)",
882 /* HOSTNAME & SERVER_HOSTNAME need to be set before they are
883 * potentially used in gserver_authenticate_connection() (called from
884 * pserver_authenticate_connection, below).
886 hostname
= xgethostname ();
890 "xgethostname () returned NULL, using \"localhost\"");
891 hostname
= xstrdup ("localhost");
894 /* Keep track of this separately since the client can change
895 * HOSTNAME on the server.
897 server_hostname
= xstrdup (hostname
);
899 #ifdef SERVER_SUPPORT
901 # ifdef HAVE_KERBEROS
902 /* If we are invoked with a single argument "kserver", then we are
903 running as Kerberos server as root. Do the authentication as
904 the very first thing, to minimize the amount of time we are
906 if (strcmp (cvs_cmd_name
, "kserver") == 0)
908 kserver_authenticate_connection ();
910 /* Pretend we were invoked as a plain server. */
911 cvs_cmd_name
= "server";
913 # endif /* HAVE_KERBEROS */
915 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
916 if (strcmp (cvs_cmd_name
, "pserver") == 0)
918 /* The reason that --allow-root is not a command option
919 is mainly that it seems easier to make it a global option. */
921 /* Gets username and password from client, authenticates, then
922 switches to run as that user and sends an ACK back to the
924 pserver_authenticate_connection ();
926 /* Pretend we were invoked as a plain server. */
927 cvs_cmd_name
= "server";
929 # endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
930 #endif /* SERVER_SUPPORT */
932 server_active
= strcmp (cvs_cmd_name
, "server") == 0;
934 #ifdef SERVER_SUPPORT
937 /* This is only used for writing into the history file. For
938 remote connections, it might be nice to have hostname
939 and/or remote path, on the other hand I'm not sure whether
940 it is worth the trouble. */
941 CurDir
= xstrdup ("<remote>");
942 cleanup_register (server_cleanup
);
947 cleanup_register (close_stdout
);
950 error (1, errno
, "cannot get working directory");
955 /* XXX pid < 10^32 */
956 val
= Xasprintf ("%ld", (long) getpid ());
957 setenv (CVS_PID_ENV
, val
, 1);
961 /* make sure we clean up on error */
962 signals_register (main_cleanup
);
964 #ifdef KLUDGE_FOR_WNT_TESTSUITE
965 /* Probably the need for this will go away at some point once
966 we call fflush enough places (e.g. fflush (stdout) in
968 (void) setvbuf (stdout
, NULL
, _IONBF
, 0);
969 (void) setvbuf (stderr
, NULL
, _IONBF
, 0);
970 #endif /* KLUDGE_FOR_WNT_TESTSUITE */
973 read_cvsrc (&argc
, &argv
, cvs_cmd_name
);
975 /* Fiddling with CVSROOT doesn't make sense if we're running
976 * in server mode, since the client will send the repository
977 * directory after the connection is made.
981 /* First check if a root was set via the command line. */
984 if (!(CVSroot_parsed
= parse_cvsroot (CVSroot_cmdline
)))
985 error (1, 0, "Bad CVSROOT: `%s'.", CVSroot_cmdline
);
988 /* See if we are able to find a 'better' value for CVSroot
989 * in the CVSADM_ROOT directory.
991 * "cvs import" shouldn't check CVS/Root; in general it
992 * ignores CVS directories and CVS/Root is likely to
993 * specify a different repository than the one we are
994 * importing to, but if this is not import and no root was
995 * specified on the command line, set the root from the
999 && !(cm
->attr
& CVS_CMD_IGNORE_ADMROOT
)
1001 CVSroot_parsed
= Name_Root (NULL
, NULL
);
1003 /* Now, if there is no root on the command line and we didn't find
1004 * one in a file, set it via the $CVSROOT env var.
1006 if (!CVSroot_parsed
)
1008 char *tmp
= getenv (CVSROOT_ENV
);
1011 if (!(CVSroot_parsed
= parse_cvsroot (tmp
)))
1012 error (1, 0, "Bad CVSROOT: `%s'.", tmp
);
1013 cvsroot_update_env
= false;
1018 if (!CVSroot_parsed
)
1020 if (!(CVSroot_parsed
= parse_cvsroot (CVSROOT_DFLT
)))
1021 error (1, 0, "Bad CVSROOT: `%s'.", CVSROOT_DFLT
);
1023 #endif /* CVSROOT_DFLT */
1025 /* Now we've reconciled CVSROOT from the command line, the
1026 CVS/Root file, and the environment variable. Do the
1027 last sanity checks on the variable. */
1028 if (!CVSroot_parsed
)
1031 "No CVSROOT specified! Please use the `-d' option");
1033 "or set the %s environment variable.", CVSROOT_ENV
);
1037 /* Here begins the big loop over unique cvsroot values. We
1038 need to call do_recursion once for each unique value found
1039 in CVS/Root. Prime the list with the current value. */
1041 /* Create the list. */
1042 assert (root_directories
== NULL
);
1043 root_directories
= getlist ();
1050 n
->type
= NT_UNKNOWN
;
1051 n
->key
= xstrdup (CVSroot_parsed
->original
);
1052 n
->data
= CVSroot_parsed
;
1054 if (addnode (root_directories
, n
))
1055 error (1, 0, "cannot add initial CVSROOT %s", n
->key
);
1058 assert (current_parsed_root
== NULL
);
1060 /* If we're running the server, we want to execute this main
1061 loop once and only once (we won't be serving multiple roots
1062 from this connection, so there's no need to do it more than
1063 once). To get out of the loop, we perform a "break" at the
1066 while (server_active
||
1067 walklist (root_directories
, set_root_directory
, NULL
))
1069 /* Fiddling with CVSROOT doesn't make sense if we're running
1070 in server mode, since the client will send the repository
1071 directory after the connection is made. */
1075 /* Now we're 100% sure that we have a valid CVSROOT
1076 variable. Parse it to see if we're supposed to do
1077 remote accesses or use a special access method. */
1079 TRACE (TRACE_FUNCTION
,
1080 "main loop with CVSROOT=%s",
1081 current_parsed_root
? current_parsed_root
->directory
1085 * Check to see if the repository exists.
1087 if (!current_parsed_root
->isremote
&& !nolock
)
1092 path
= Xasprintf ("%s/%s", current_parsed_root
->directory
,
1094 if (!isaccessible (path
, R_OK
| X_OK
))
1097 /* If this is "cvs init", the root need not exist yet.
1099 if (strcmp (cvs_cmd_name
, "init"))
1100 error (1, save_errno
, "%s", path
);
1105 /* Update the CVSROOT environment variable. */
1106 if (cvsroot_update_env
)
1107 setenv (CVSROOT_ENV
, current_parsed_root
->original
, 1);
1110 /* Parse the CVSROOT/config file, but only for local. For the
1111 server, we parse it after we know $CVSROOT. For the
1112 client, it doesn't get parsed at all, obviously. The
1113 presence of the parse_config call here is not meant to
1114 predetermine whether CVSROOT/config overrides things from
1115 read_cvsrc and other such places or vice versa. That sort
1116 of thing probably needs more thought. */
1117 if (!server_active
&& !current_parsed_root
->isremote
)
1119 /* If there was an error parsing the config file, parse_config
1120 already printed an error. We keep going. Why? Because
1121 if we didn't, then there would be no way to check in a new
1122 CVSROOT/config file to fix the broken one! */
1123 if (config
) free_config (config
);
1124 config
= parse_config (current_parsed_root
->directory
, NULL
);
1126 /* Can set TMPDIR in the environment if necessary now, since
1127 * if it was set in config, we now know it.
1129 push_env_temp_dir ();
1132 #ifdef CLIENT_SUPPORT
1133 /* Need to check for current_parsed_root != NULL here since
1134 * we could still be in server mode before the server function
1135 * gets called below and sets the root
1137 if (current_parsed_root
!= NULL
&& current_parsed_root
->isremote
)
1139 /* Create a new list for directory names that we've
1140 sent to the server. */
1141 if (dirs_sent_to_server
!= NULL
)
1142 dellist (&dirs_sent_to_server
);
1143 dirs_sent_to_server
= getlist ();
1148 #ifdef SERVER_SUPPORT
1149 /* Don't worry about lock_cleanup_setup when the server is
1150 * active since we can only go through this loop once in that
1156 #ifdef CLIENT_SUPPORT
1157 !current_parsed_root
->isremote
&&
1159 !lock_cleanup_setup
))
1161 /* Set up to clean up any locks we might create on exit. */
1162 cleanup_register (Lock_Cleanup
);
1163 lock_cleanup_setup
= 1;
1166 /* Call our worker function. */
1167 err
= (*(cm
->func
)) (argc
, argv
);
1169 /* Mark this root directory as done. When the server is
1170 active, our list will be empty -- don't try and
1171 remove it from the list. */
1175 Node
*n
= findnode (root_directories
,
1176 original_parsed_root
->original
);
1178 assert (n
->data
!= NULL
);
1180 current_parsed_root
= NULL
;
1185 } /* end of loop for cvsroot values */
1187 dellist (&root_directories
);
1188 } /* end of stuff that gets done if the user DOESN'T ask for help */
1192 /* This is exit rather than return because apparently that keeps
1193 some tools which check for memory leaks happier. */
1194 exit (err
? EXIT_FAILURE
: 0);
1195 /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */
1202 Make_Date (const char *rawdate
)
1206 if (!get_date (&t
, rawdate
, NULL
))
1207 error (1, 0, "Can't parse date/time: `%s'", rawdate
);
1209 /* Truncate nanoseconds. */
1210 return date_from_time_t (t
.tv_sec
);
1215 /* Parse a string of the form TAG[:DATE], where TAG could be the empty string.
1218 * input The string to be parsed.
1221 * tag The tag found, if any. If TAG is the empty string, then leave
1222 * this value unchanged.
1223 * date The date found, if any. If DATE is the empty string or is
1224 * missing, leave this value unchanged.
1227 * If either TAG or DATE is replaced for output, the previous value is freed.
1230 * If either TAG or DATE cannot be parsed, then this function will exit with
1231 * a fatal error message.
1237 parse_tagdate (char **tag
, char **date
, const char *input
)
1241 TRACE (TRACE_FUNCTION
, "parse_tagdate (%s, %s, %s)",
1242 *tag
? *tag
: "(null)", *date
? *date
: "(null)",
1245 if ((p
= strchr (input
, ':')))
1247 /* Parse the tag. */
1250 /* The tag has > 0 length. */
1251 if (*tag
) free (*tag
);
1252 *tag
= xmalloc (p
- input
+ 1);
1253 strncpy (*tag
, input
, p
- input
);
1254 (*tag
)[p
- input
] = '\0';
1257 /* Parse the date. */
1260 if (*date
) free (*date
);
1261 *date
= Make_Date (p
);
1264 else if (strlen (input
))
1266 /* The tag has > 0 length. */
1267 if (*tag
) free (*tag
);
1268 *tag
= xstrdup (input
);
1271 TRACE (TRACE_DATA
, "parse_tagdate: got tag = `%s', date = `%s'",
1272 *tag
? *tag
: "(null)", *date
? *date
: "(null)");
1277 /* Convert a time_t to an RCS format date. This is mainly for the
1278 use of "cvs history", because the CVSROOT/history file contains
1279 time_t format dates; most parts of CVS will want to avoid using
1280 time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
1281 Assuming that the time_t is in GMT (as it generally should be),
1282 then the result will be in GMT too.
1284 Returns a newly malloc'd string. */
1287 date_from_time_t (time_t unixtime
)
1290 char date
[MAXDATELEN
];
1293 ftm
= gmtime (&unixtime
);
1295 /* This is a system, like VMS, where the system clock is in local
1296 time. Hopefully using localtime here matches the "zero timezone"
1297 hack I added to get_date (get_date of course being the relevant
1298 issue for Make_Date, and for history.c too I think). */
1299 ftm
= localtime (&unixtime
);
1301 (void) sprintf (date
, DATEFORM
,
1302 ftm
->tm_year
+ (ftm
->tm_year
< 100 ? 0 : 1900),
1303 ftm
->tm_mon
+ 1, ftm
->tm_mday
, ftm
->tm_hour
,
1304 ftm
->tm_min
, ftm
->tm_sec
);
1305 ret
= xstrdup (date
);
1311 getCVSDir (const char *suffix
)
1313 static const char *buf
[20][2];
1316 for (i
= 0; i
< 20; i
++) {
1317 if (buf
[i
][0] == NULL
)
1319 if (strcmp (buf
[i
][0], suffix
) == 0)
1324 error (1, 0, "Out of static buffer space");
1327 buf
[i
][1] = xmalloc (len
= strlen(cvsDir
) + strlen(suffix
) + 1);
1328 snprintf ((char *)buf
[i
][1], len
, "%s%s", cvsDir
, suffix
);
1334 /* Convert a date to RFC822/1123 format. This is used in contexts like
1335 dates to send in the protocol; it should not vary based on locale or
1336 other such conventions for users. We should have another routine which
1337 does that kind of thing.
1339 The SOURCE date is in our internal RCS format. DEST should point to
1340 storage managed by the caller, at least MAXDATELEN characters. */
1342 date_to_internet (char *dest
, const char *source
)
1346 date_to_tm (&date
, source
);
1347 tm_to_internet (dest
, &date
);
1353 date_to_tm (struct tm
*dest
, const char *source
)
1355 if (sscanf (source
, SDATEFORM
,
1356 &dest
->tm_year
, &dest
->tm_mon
, &dest
->tm_mday
,
1357 &dest
->tm_hour
, &dest
->tm_min
, &dest
->tm_sec
)
1359 /* Is there a better way to handle errors here? I made this
1360 non-fatal in case we are called from the code which can't
1361 deal with fatal errors. */
1362 error (0, 0, "internal error: bad date %s", source
);
1364 if (dest
->tm_year
> 100)
1365 dest
->tm_year
-= 1900;
1372 /* Convert a date to RFC822/1123 format. This is used in contexts like
1373 dates to send in the protocol; it should not vary based on locale or
1374 other such conventions for users. We should have another routine which
1375 does that kind of thing.
1377 The SOURCE date is a pointer to a struct tm. DEST should point to
1378 storage managed by the caller, at least MAXDATELEN characters. */
1380 tm_to_internet (char *dest
, const struct tm
*source
)
1382 /* Just to reiterate, these strings are from RFC822 and do not vary
1383 according to locale. */
1384 static const char *const month_names
[] =
1385 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1386 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1388 sprintf (dest
, "%d %s %d %02d:%02d:%02d -0000", source
->tm_mday
,
1389 source
->tm_mon
< 0 || source
->tm_mon
> 11
1390 ? "???" : month_names
[source
->tm_mon
],
1391 source
->tm_year
+ 1900, source
->tm_hour
, source
->tm_min
,
1398 * Format a date for the current locale.
1401 * UNIXTIME The UNIX seconds since the epoch.
1404 * If my_strftime() encounters an error, this function can return NULL.
1406 * Otherwise, returns a date string in ISO8601 format, e.g.:
1408 * 2004-04-29 13:24:22 -0700
1410 * It is the responsibility of the caller to return of this string.
1413 format_time_t (time_t unixtime
)
1415 static char buf
[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
1416 /* Convert to a time in the local time zone. */
1417 struct tm ltm
= *(localtime (&unixtime
));
1419 if (!my_strftime (buf
, sizeof (buf
), "%Y-%m-%d %H:%M:%S %z", <m
, 0, 0))
1422 return xstrdup (buf
);
1427 /* Like format_time_t(), but return time in UTC.
1430 gmformat_time_t (time_t unixtime
)
1432 static char buf
[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
1433 /* Convert to a time in the local time zone. */
1434 struct tm ltm
= *(gmtime (&unixtime
));
1436 if (!my_strftime (buf
, sizeof (buf
), "%Y-%m-%d %H:%M:%S %z", <m
, 0, 0))
1439 return xstrdup (buf
);
1444 /* Format a date in the local timezone using format_time_t() given a date from
1445 * an arbitrary timezone in a string.
1448 * DATESTR A string that looks like anything get_date() can parse, e.g.:
1450 * 2004-04-29 20:24:22
1453 * As get_date() & format_time_t(). Prints a warning if either provide
1454 * error return values. See RETURNS.
1457 * A freshly allocated string that is a copy of the input string if either
1458 * get_date() or format_time_t() encounter an error and as format_time_t()
1462 format_date_alloc (char *datestr
)
1467 TRACE (TRACE_FUNCTION
, "format_date (%s)", datestr
);
1469 /* Convert the date string to seconds since the epoch. */
1470 if (!get_date (&t
, datestr
, NULL
))
1472 error (0, 0, "Can't parse date/time: `%s'.", datestr
);
1476 /* Get the time into a string, truncating any nanoseconds returned by
1479 if ((buf
= format_time_t (t
.tv_sec
)) == NULL
)
1481 error (0, 0, "Unable to reformat date `%s'.", datestr
);
1488 return xstrdup (datestr
);
1494 #ifdef HAVE_GETOPT_OPTRESET
1505 usage (register const char *const *cpp
)
1507 (void) fprintf (stderr
, *cpp
++, program_name
, cvs_cmd_name
);
1509 (void) fprintf (stderr
, *cpp
);
1510 exit (EXIT_FAILURE
);
1513 /* vim:tabstop=8:shiftwidth=4