1 /* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 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. 7 * 8 * This is the main C driver for the CVS system. 9 * 10 * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing 11 * the shell-script CVS system that this is based on. 12 * 13 */ 14 15 #include <assert.h> 16 #include "cvs.h" 17 18 #ifdef HAVE_WINSOCK_H 19 #include <winsock.h> 20 #else 21 extern int gethostname (); 22 #endif 23 24 char *program_name; 25 char *program_path; 26 char *command_name; 27 28 /* I'd dynamically allocate this, but it seems like gethostname 29 requires a fixed size array. If I'm remembering the RFCs right, 30 256 should be enough. */ 31 #ifndef MAXHOSTNAMELEN 32 #define MAXHOSTNAMELEN 256 33 #endif 34 35 char hostname[MAXHOSTNAMELEN]; 36 37 int use_editor = 1; 38 int use_cvsrc = 1; 39 int cvswrite = !CVSREAD_DFLT; 40 int really_quiet = 0; 41 int quiet = 0; 42 int trace = 0; 43 int noexec = 0; 44 int readonlyfs = 0; 45 int logoff = 0; 46 47 /* Set if we should be writing CVSADM directories at top level. At 48 least for now we'll make the default be off (the CVS 1.9, not CVS 49 1.9.2, behavior). */ 50 int top_level_admin = 0; 51 52 mode_t cvsumask = UMASK_DFLT; 53 char *RCS_citag = NULL; 54 int disable_mdocdate = 0; 55 56 char *CurDir; 57 58 /* 59 * Defaults, for the environment variables that are not set 60 */ 61 char *Tmpdir = TMPDIR_DFLT; 62 char *Editor = EDITOR_DFLT; 63 64 65 /* When our working directory contains subdirectories with different 66 values in CVS/Root files, we maintain a list of them. */ 67 List *root_directories = NULL; 68 69 /* We step through the above values. This variable is set to reflect 70 * the currently active value. 71 * 72 * Now static. FIXME - this variable should be removable (well, localizable) 73 * with a little more work. 74 */ 75 static char *current_root = NULL; 76 77 78 static const struct cmd 79 { 80 char *fullname; /* Full name of the function (e.g. "commit") */ 81 82 /* Synonyms for the command, nick1 and nick2. We supply them 83 mostly for two reasons: (1) CVS has always supported them, and 84 we need to maintain compatibility, (2) if there is a need for a 85 version which is shorter than the fullname, for ease in typing. 86 Synonyms have the disadvantage that people will see "new" and 87 then have to think about it, or look it up, to realize that is 88 the operation they know as "add". Also, this means that one 89 cannot create a command "cvs new" with a different meaning. So 90 new synonyms are probably best used sparingly, and where used 91 should be abbreviations of the fullname (preferably consisting 92 of the first 2 or 3 or so letters). 93 94 One thing that some systems do is to recognize any unique 95 abbreviation, for example "annotat" "annota", etc., for 96 "annotate". The problem with this is that scripts and user 97 habits will expect a certain abbreviation to be unique, and in 98 a future release of CVS it may not be. So it is better to 99 accept only an explicit list of abbreviations and plan on 100 supporting them in the future as well as now. */ 101 102 char *nick1; 103 char *nick2; 104 105 int (*func) (); /* Function takes (argc, argv) arguments. */ 106 unsigned long attr; /* Attributes. */ 107 } cmds[] = 108 109 { 110 { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 111 { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 112 { "annotate", "ann", "blame", annotate, CVS_CMD_USES_WORK_DIR }, 113 { "checkout", "co", "get", checkout, 0 }, 114 { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 115 { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR }, 116 { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 117 { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR }, 118 { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR }, 119 { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR }, 120 { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT}, 121 { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY }, 122 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) 123 { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ 124 #endif 125 { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR }, 126 #ifdef AUTH_CLIENT_SUPPORT 127 { "login", "logon", "lgn", login, 0 }, 128 { "logout", NULL, NULL, logout, 0 }, 129 #endif /* AUTH_CLIENT_SUPPORT */ 130 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) 131 { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ 132 #endif 133 { "rannotate","rann", "ra", annotate, 0 }, 134 { "rdiff", "patch", "pa", patch, 0 }, 135 { "release", "re", "rel", release, 0 }, 136 { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 137 { "rlog", "rl", NULL, cvslog, 0 }, 138 { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY }, 139 #ifdef SERVER_SUPPORT 140 { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 141 #endif 142 { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR }, 143 { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 144 { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 145 { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR }, 146 { "version", "ve", "ver", version, 0 }, 147 { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, 148 { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR }, 149 { NULL, NULL, NULL, NULL, 0 }, 150 }; 151 152 static const char *const usg[] = 153 { 154 /* CVS usage messages never have followed the GNU convention of 155 putting metavariables in uppercase. I don't know whether that 156 is a good convention or not, but if it changes it would have to 157 change in all the usage messages. For now, they consistently 158 use lowercase, as far as I know. Puncutation is pretty funky, 159 though. Sometimes they use none, as here. Sometimes they use 160 single quotes (not the TeX-ish `' stuff), as in --help-options. 161 Sometimes they use double quotes, as in cvs -H add. 162 163 Most (not all) of the usage messages seem to have periods at 164 the end of each line. I haven't tried to duplicate this style 165 in --help as it is a rather different format from the rest. */ 166 167 "Usage: %s [cvs-options] command [command-options-and-arguments]\n", 168 " where cvs-options are -q, -n, etc.\n", 169 " (specify --help-options for a list of options)\n", 170 " where command is add, admin, etc.\n", 171 " (specify --help-commands for a list of commands\n", 172 " or --help-synonyms for a list of command synonyms)\n", 173 " where command-options-and-arguments depend on the specific command\n", 174 " (specify -H followed by a command name for command-specific help)\n", 175 " Specify --help to receive this message\n", 176 "\n", 177 178 /* Some people think that a bug-reporting address should go here. IMHO, 179 the web sites are better because anything else is very likely to go 180 obsolete in the years between a release and when someone might be 181 reading this help. Besides, we could never adequately discuss 182 bug reporting in a concise enough way to put in a help message. */ 183 184 /* I was going to put this at the top, but usage() wants the %s to 185 be in the first line. */ 186 "The Concurrent Versions System (CVS) is a tool for version control.\n", 187 /* I really don't think I want to try to define "version control" 188 in one line. I'm not sure one can get more concise than the 189 paragraph in ../cvs.spec without assuming the reader knows what 190 version control means. */ 191 192 "For CVS updates and additional information, see\n", 193 " the CVS home page at http://www.cvshome.org/ or\n", 194 " Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n", 195 NULL, 196 }; 197 198 static const char *const cmd_usage[] = 199 { 200 "CVS commands are:\n", 201 " add Add a new file/directory to the repository\n", 202 " admin Administration front end for rcs\n", 203 " annotate Show last revision where each line was modified\n", 204 " checkout Checkout sources for editing\n", 205 " commit Check files into the repository\n", 206 " diff Show differences between revisions\n", 207 " edit Get ready to edit a watched file\n", 208 " editors See who is editing a watched file\n", 209 " export Export sources from CVS, similar to checkout\n", 210 " history Show repository access history\n", 211 " import Import sources into CVS, using vendor branches\n", 212 " init Create a CVS repository if it doesn't exist\n", 213 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) 214 " kserver Kerberos server mode\n", 215 #endif 216 " log Print out history information for files\n", 217 #ifdef AUTH_CLIENT_SUPPORT 218 " login Prompt for password for authenticating server\n", 219 " logout Removes entry in .cvspass for remote repository\n", 220 #endif /* AUTH_CLIENT_SUPPORT */ 221 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) 222 " pserver Password server mode\n", 223 #endif 224 " rannotate Show last revision where each line of module was modified\n", 225 " rdiff Create 'patch' format diffs between releases\n", 226 " release Indicate that a Module is no longer in use\n", 227 " remove Remove an entry from the repository\n", 228 " rlog Print out history information for a module\n", 229 " rtag Add a symbolic tag to a module\n", 230 #ifdef SERVER_SUPPORT 231 " server Server mode\n", 232 #endif 233 " status Display status information on checked out files\n", 234 " tag Add a symbolic tag to checked out version of files\n", 235 " unedit Undo an edit command\n", 236 " update Bring work tree in sync with repository\n", 237 " version Show current CVS version(s)\n", 238 " watch Set watches\n", 239 " watchers See who is watching a file\n", 240 "(Specify the --help option for a list of other help options)\n", 241 NULL, 242 }; 243 244 static const char *const opt_usage[] = 245 { 246 /* Omit -b because it is just for compatibility. */ 247 "CVS global options (specified before the command name) are:\n", 248 " -H Displays usage information for command.\n", 249 " -Q Cause CVS to be really quiet.\n", 250 " -q Cause CVS to be somewhat quiet.\n", 251 " -r Make checked-out files read-only.\n", 252 " -w Make checked-out files read-write (default).\n", 253 " -l Turn history logging off.\n", 254 " -n Do not execute anything that will change the disk.\n", 255 " -t Show trace of program execution -- try with -n.\n", 256 " -v CVS version and copyright.\n", 257 " -R Read-only repository.\n", 258 " -T tmpdir Use 'tmpdir' for temporary files.\n", 259 " -e editor Use 'editor' for editing log information.\n", 260 " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n", 261 " -f Do not use the ~/.cvsrc file.\n", 262 #ifdef CLIENT_SUPPORT 263 " -z # Use compression level '#' for net traffic.\n", 264 #ifdef ENCRYPTION 265 " -x Encrypt all net traffic.\n", 266 #endif 267 " -a Authenticate all net traffic.\n", 268 #endif 269 " -s VAR=VAL Set CVS user variable.\n", 270 "(Specify the --help option for a list of other help options)\n", 271 NULL 272 }; 273 274 275 static int 276 set_root_directory (p, ignored) 277 Node *p; 278 void *ignored; 279 { 280 if (current_root == NULL && p->data == NULL) 281 { 282 current_root = p->key; 283 return 1; 284 } 285 return 0; 286 } 287 288 289 static const char * const* 290 cmd_synonyms () 291 { 292 char ** synonyms; 293 char ** line; 294 const struct cmd *c = &cmds[0]; 295 /* Three more for title, "specify --help" line, and NULL. */ 296 int numcmds = 3; 297 298 while (c->fullname != NULL) 299 { 300 numcmds++; 301 c++; 302 } 303 304 synonyms = (char **) xmalloc(numcmds * sizeof(char *)); 305 line = synonyms; 306 *line++ = "CVS command synonyms are:\n"; 307 for (c = &cmds[0]; c->fullname != NULL; c++) 308 { 309 if (c->nick1 || c->nick2) 310 { 311 *line = xmalloc (strlen (c->fullname) 312 + (c->nick1 != NULL ? strlen (c->nick1) : 0) 313 + (c->nick2 != NULL ? strlen (c->nick2) : 0) 314 + 40); 315 sprintf(*line, " %-12s %s %s\n", c->fullname, 316 c->nick1 ? c->nick1 : "", 317 c->nick2 ? c->nick2 : ""); 318 line++; 319 } 320 } 321 *line++ = "(Specify the --help option for a list of other help options)\n"; 322 *line = NULL; 323 324 return (const char * const*) synonyms; /* will never be freed */ 325 } 326 327 328 unsigned long int 329 lookup_command_attribute (cmd_name) 330 char *cmd_name; 331 { 332 const struct cmd *cm; 333 334 for (cm = cmds; cm->fullname; cm++) 335 { 336 if (strcmp (cmd_name, cm->fullname) == 0) 337 break; 338 } 339 return cm->attr; 340 } 341 342 343 static RETSIGTYPE 344 main_cleanup (sig) 345 int sig; 346 { 347 #ifndef DONT_USE_SIGNALS 348 const char *name; 349 char temp[10]; 350 351 switch (sig) 352 { 353 #ifdef SIGABRT 354 case SIGABRT: 355 name = "abort"; 356 break; 357 #endif 358 #ifdef SIGHUP 359 case SIGHUP: 360 name = "hangup"; 361 break; 362 #endif 363 #ifdef SIGINT 364 case SIGINT: 365 name = "interrupt"; 366 break; 367 #endif 368 #ifdef SIGQUIT 369 case SIGQUIT: 370 name = "quit"; 371 break; 372 #endif 373 #ifdef SIGPIPE 374 case SIGPIPE: 375 name = "broken pipe"; 376 break; 377 #endif 378 #ifdef SIGTERM 379 case SIGTERM: 380 name = "termination"; 381 break; 382 #endif 383 default: 384 /* This case should never be reached, because we list above all 385 the signals for which we actually establish a signal handler. */ 386 sprintf (temp, "%d", sig); 387 name = temp; 388 break; 389 } 390 391 error (1, 0, "received %s signal", name); 392 #endif /* !DONT_USE_SIGNALS */ 393 } 394 395 int 396 main (argc, argv) 397 int argc; 398 char **argv; 399 { 400 char *CVSroot = CVSROOT_DFLT; 401 char *cp, *end; 402 const struct cmd *cm; 403 int c, err = 0; 404 int tmpdir_update_env, cvs_update_env; 405 int free_CVSroot = 0; 406 int free_Editor = 0; 407 int free_Tmpdir = 0; 408 409 int help = 0; /* Has the user asked for help? This 410 lets us support the `cvs -H cmd' 411 convention to give help for cmd. */ 412 static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xaR"; 413 static struct option long_options[] = 414 { 415 {"help", 0, NULL, 'H'}, 416 {"version", 0, NULL, 'v'}, 417 {"help-commands", 0, NULL, 1}, 418 {"help-synonyms", 0, NULL, 2}, 419 {"help-options", 0, NULL, 4}, 420 {"allow-root", required_argument, NULL, 3}, 421 {0, 0, 0, 0} 422 }; 423 /* `getopt_long' stores the option index here, but right now we 424 don't use it. */ 425 int option_index = 0; 426 427 #ifdef SYSTEM_INITIALIZE 428 /* Hook for OS-specific behavior, for example socket subsystems on 429 NT and OS2 or dealing with windows and arguments on Mac. */ 430 SYSTEM_INITIALIZE (&argc, &argv); 431 #endif 432 433 #ifdef HAVE_TZSET 434 /* On systems that have tzset (which is almost all the ones I know 435 of), it's a good idea to call it. */ 436 tzset (); 437 #endif 438 439 /* 440 * Just save the last component of the path for error messages 441 */ 442 program_path = xstrdup (argv[0]); 443 #ifdef ARGV0_NOT_PROGRAM_NAME 444 /* On some systems, e.g. VMS, argv[0] is not the name of the command 445 which the user types to invoke the program. */ 446 program_name = "cvs"; 447 #else 448 program_name = last_component (argv[0]); 449 #endif 450 451 /* 452 * Query the environment variables up-front, so that 453 * they can be overridden by command line arguments 454 */ 455 cvs_update_env = 0; 456 tmpdir_update_env = *Tmpdir; /* TMPDIR_DFLT must be set */ 457 if ((cp = getenv (TMPDIR_ENV)) != NULL) 458 { 459 Tmpdir = cp; 460 tmpdir_update_env = 0; /* it's already there */ 461 } 462 if ((cp = getenv (EDITOR1_ENV)) != NULL) 463 Editor = cp; 464 else if ((cp = getenv (EDITOR2_ENV)) != NULL) 465 Editor = cp; 466 else if ((cp = getenv (EDITOR3_ENV)) != NULL) 467 Editor = cp; 468 if ((cp = getenv (CVSROOT_ENV)) != NULL) 469 { 470 CVSroot = cp; 471 cvs_update_env = 0; /* it's already there */ 472 } 473 if (getenv (CVSREAD_ENV) != NULL) 474 cvswrite = 0; 475 if (getenv (CVSREADONLYFS_ENV)) { 476 readonlyfs = 1; 477 logoff = 1; 478 } 479 480 /* Set this to 0 to force getopt initialization. getopt() sets 481 this to 1 internally. */ 482 optind = 0; 483 484 /* We have to parse the options twice because else there is no 485 chance to avoid reading the global options from ".cvsrc". Set 486 opterr to 0 for avoiding error messages about invalid options. 487 */ 488 opterr = 0; 489 490 while ((c = getopt_long 491 (argc, argv, short_options, long_options, &option_index)) 492 != EOF) 493 { 494 if (c == 'f') 495 use_cvsrc = 0; 496 } 497 498 /* 499 * Scan cvsrc file for global options. 500 */ 501 if (use_cvsrc) 502 read_cvsrc (&argc, &argv, "cvs"); 503 504 optind = 0; 505 opterr = 1; 506 507 while ((c = getopt_long 508 (argc, argv, short_options, long_options, &option_index)) 509 != EOF) 510 { 511 switch (c) 512 { 513 case 1: 514 /* --help-commands */ 515 usage (cmd_usage); 516 break; 517 case 2: 518 /* --help-synonyms */ 519 usage (cmd_synonyms()); 520 break; 521 case 4: 522 /* --help-options */ 523 usage (opt_usage); 524 break; 525 case 3: 526 /* --allow-root */ 527 root_allow_add (optarg); 528 break; 529 case 'Q': 530 really_quiet = 1; 531 /* FALL THROUGH */ 532 case 'q': 533 quiet = 1; 534 break; 535 case 'r': 536 cvswrite = 0; 537 break; 538 case 'w': 539 cvswrite = 1; 540 break; 541 case 't': 542 trace = 1; 543 break; 544 case 'n': 545 noexec = 1; 546 case 'l': /* Fall through */ 547 logoff = 1; 548 break; 549 case 'R': 550 logoff = 1; 551 readonlyfs = 1; 552 break; 553 case 'v': 554 (void) fputs ("\n", stdout); 555 version (0, (char **) NULL); 556 (void) fputs ("\n", stdout); 557 (void) fputs ("\ 558 Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ 559 Jeff Polk, and other authors\n", stdout); 560 (void) fputs ("\n", stdout); 561 (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); 562 (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout); 563 (void) fputs ("\n", stdout); 564 565 (void) fputs ("Specify the --help option for further information about CVS\n", stdout); 566 567 exit (0); 568 break; 569 case 'b': 570 /* This option used to specify the directory for RCS 571 executables. But since we don't run them any more, 572 this is a noop. Silently ignore it so that .cvsrc 573 and scripts and inetd.conf and such can work with 574 either new or old CVS. */ 575 break; 576 case 'T': 577 Tmpdir = xstrdup (optarg); 578 free_Tmpdir = 1; 579 tmpdir_update_env = 1; /* need to update environment */ 580 break; 581 case 'e': 582 Editor = xstrdup (optarg); 583 free_Editor = 1; 584 break; 585 case 'd': 586 if (CVSroot_cmdline != NULL) 587 free (CVSroot_cmdline); 588 CVSroot_cmdline = xstrdup (optarg); 589 if (free_CVSroot) 590 free (CVSroot); 591 CVSroot = xstrdup (optarg); 592 free_CVSroot = 1; 593 cvs_update_env = 1; /* need to update environment */ 594 break; 595 case 'H': 596 help = 1; 597 break; 598 case 'f': 599 use_cvsrc = 0; /* unnecessary, since we've done it above */ 600 break; 601 case 'z': 602 #ifdef CLIENT_SUPPORT 603 gzip_level = atoi (optarg); 604 if (gzip_level < 0 || gzip_level > 9) 605 error (1, 0, 606 "gzip compression level must be between 0 and 9"); 607 #endif 608 /* If no CLIENT_SUPPORT, we just silently ignore the gzip 609 level, so that users can have it in their .cvsrc and not 610 cause any trouble. */ 611 break; 612 case 's': 613 variable_set (optarg); 614 break; 615 case 'x': 616 #ifdef CLIENT_SUPPORT 617 cvsencrypt = 1; 618 #endif /* CLIENT_SUPPORT */ 619 /* If no CLIENT_SUPPORT, ignore -x, so that users can 620 have it in their .cvsrc and not cause any trouble. 621 If no ENCRYPTION, we still accept -x, but issue an 622 error if we are being run as a client. */ 623 break; 624 case 'a': 625 #ifdef CLIENT_SUPPORT 626 cvsauthenticate = 1; 627 #endif 628 /* If no CLIENT_SUPPORT, ignore -a, so that users can 629 have it in their .cvsrc and not cause any trouble. 630 We will issue an error later if stream 631 authentication is not supported. */ 632 break; 633 case '?': 634 default: 635 usage (usg); 636 } 637 } 638 639 argc -= optind; 640 argv += optind; 641 if (argc < 1) 642 usage (usg); 643 644 645 /* Look up the command name. */ 646 647 command_name = argv[0]; 648 for (cm = cmds; cm->fullname; cm++) 649 { 650 if (cm->nick1 && !strcmp (command_name, cm->nick1)) 651 break; 652 if (cm->nick2 && !strcmp (command_name, cm->nick2)) 653 break; 654 if (!strcmp (command_name, cm->fullname)) 655 break; 656 } 657 658 if (!cm->fullname) 659 { 660 fprintf (stderr, "Unknown command: `%s'\n\n", command_name); 661 usage (cmd_usage); 662 } 663 else 664 command_name = cm->fullname; /* Global pointer for later use */ 665 666 if (help) 667 { 668 argc = -1; /* some functions only check for this */ 669 err = (*(cm->func)) (argc, argv); 670 } 671 else 672 { 673 /* The user didn't ask for help, so go ahead and authenticate, 674 set up CVSROOT, and the rest of it. */ 675 676 /* The UMASK environment variable isn't handled with the 677 others above, since we don't want to signal errors if the 678 user has asked for help. This won't work if somebody adds 679 a command-line flag to set the umask, since we'll have to 680 parse it before we get here. */ 681 682 if ((cp = getenv (CVSUMASK_ENV)) != NULL) 683 { 684 /* FIXME: Should be accepting symbolic as well as numeric mask. */ 685 cvsumask = strtol (cp, &end, 8) & 0777; 686 if (*end != '\0') 687 error (1, errno, "invalid umask value in %s (%s)", 688 CVSUMASK_ENV, cp); 689 } 690 691 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) 692 /* If we are invoked with a single argument "kserver", then we are 693 running as Kerberos server as root. Do the authentication as 694 the very first thing, to minimize the amount of time we are 695 running as root. */ 696 if (strcmp (command_name, "kserver") == 0) 697 { 698 kserver_authenticate_connection (); 699 700 /* Pretend we were invoked as a plain server. */ 701 command_name = "server"; 702 } 703 #endif /* HAVE_KERBEROS */ 704 705 706 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) 707 if (strcmp (command_name, "pserver") == 0) 708 { 709 /* The reason that --allow-root is not a command option 710 is mainly the comment in server() about how argc,argv 711 might be from .cvsrc. I'm not sure about that, and 712 I'm not sure it is only true of command options, but 713 it seems easier to make it a global option. */ 714 715 /* Gets username and password from client, authenticates, then 716 switches to run as that user and sends an ACK back to the 717 client. */ 718 pserver_authenticate_connection (); 719 720 /* Pretend we were invoked as a plain server. */ 721 command_name = "server"; 722 } 723 #endif /* (AUTH_SERVER_SUPPORT || HAVE_GSSAPI) && SERVER_SUPPORT */ 724 725 #ifdef SERVER_SUPPORT 726 server_active = strcmp (command_name, "server") == 0; 727 #endif 728 729 /* This is only used for writing into the history file. For 730 remote connections, it might be nice to have hostname 731 and/or remote path, on the other hand I'm not sure whether 732 it is worth the trouble. */ 733 734 #ifdef SERVER_SUPPORT 735 if (server_active) 736 CurDir = xstrdup ("<remote>"); 737 else 738 #endif 739 { 740 CurDir = xgetwd (); 741 if (CurDir == NULL) 742 error (1, errno, "cannot get working directory"); 743 } 744 745 if (Tmpdir == NULL || Tmpdir[0] == '\0') 746 Tmpdir = "/tmp"; 747 748 #ifdef HAVE_PUTENV 749 if (tmpdir_update_env) 750 { 751 char *env; 752 env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1); 753 (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir); 754 (void) putenv (env); 755 /* do not free env, as putenv has control of it */ 756 } 757 #endif 758 759 #ifndef DONT_USE_SIGNALS 760 /* make sure we clean up on error */ 761 #ifdef SIGABRT 762 (void) SIG_register (SIGABRT, main_cleanup); 763 #endif 764 #ifdef SIGHUP 765 (void) SIG_register (SIGHUP, main_cleanup); 766 #endif 767 #ifdef SIGINT 768 (void) SIG_register (SIGINT, main_cleanup); 769 #endif 770 #ifdef SIGQUIT 771 (void) SIG_register (SIGQUIT, main_cleanup); 772 #endif 773 #ifdef SIGPIPE 774 (void) SIG_register (SIGPIPE, main_cleanup); 775 #endif 776 #ifdef SIGTERM 777 (void) SIG_register (SIGTERM, main_cleanup); 778 #endif 779 #endif /* !DONT_USE_SIGNALS */ 780 781 gethostname(hostname, sizeof (hostname)); 782 783 #ifdef KLUDGE_FOR_WNT_TESTSUITE 784 /* Probably the need for this will go away at some point once 785 we call fflush enough places (e.g. fflush (stdout) in 786 cvs_outerr). */ 787 (void) setvbuf (stdout, (char *) NULL, _IONBF, 0); 788 (void) setvbuf (stderr, (char *) NULL, _IONBF, 0); 789 #endif /* KLUDGE_FOR_WNT_TESTSUITE */ 790 791 if (use_cvsrc) 792 read_cvsrc (&argc, &argv, command_name); 793 794 #ifdef SERVER_SUPPORT 795 /* Fiddling with CVSROOT doesn't make sense if we're running 796 in server mode, since the client will send the repository 797 directory after the connection is made. */ 798 799 if (!server_active) 800 #endif 801 { 802 char *CVSADM_Root; 803 804 /* See if we are able to find a 'better' value for CVSroot 805 in the CVSADM_ROOT directory. */ 806 807 CVSADM_Root = NULL; 808 809 /* "cvs import" shouldn't check CVS/Root; in general it 810 ignores CVS directories and CVS/Root is likely to 811 specify a different repository than the one we are 812 importing to. */ 813 814 if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT) 815 816 /* -d overrides CVS/Root, so don't give an error if the 817 latter points to a nonexistent repository. */ 818 && CVSroot_cmdline == NULL) 819 { 820 CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); 821 } 822 823 if (CVSADM_Root != NULL) 824 { 825 if (CVSroot == NULL || !cvs_update_env) 826 { 827 CVSroot = CVSADM_Root; 828 cvs_update_env = 1; /* need to update environment */ 829 } 830 } 831 832 /* Now we've reconciled CVSROOT from the command line, the 833 CVS/Root file, and the environment variable. Do the 834 last sanity checks on the variable. */ 835 836 if (! CVSroot) 837 { 838 error (0, 0, 839 "No CVSROOT specified! Please use the `-d' option"); 840 error (1, 0, 841 "or set the %s environment variable.", CVSROOT_ENV); 842 } 843 844 if (! *CVSroot) 845 { 846 error (0, 0, 847 "CVSROOT is set but empty! Make sure that the"); 848 error (0, 0, 849 "specification of CVSROOT is legal, either via the"); 850 error (0, 0, 851 "`-d' option, the %s environment variable, or the", 852 CVSROOT_ENV); 853 error (1, 0, 854 "CVS/Root file (if any)."); 855 } 856 } 857 858 /* Here begins the big loop over unique cvsroot values. We 859 need to call do_recursion once for each unique value found 860 in CVS/Root. Prime the list with the current value. */ 861 862 /* Create the list. */ 863 assert (root_directories == NULL); 864 root_directories = getlist (); 865 866 /* Prime it. */ 867 if (CVSroot != NULL) 868 { 869 Node *n; 870 n = getnode (); 871 n->type = NT_UNKNOWN; 872 n->key = xstrdup (CVSroot); 873 n->data = NULL; 874 875 if (addnode (root_directories, n)) 876 error (1, 0, "cannot add initial CVSROOT %s", n->key); 877 } 878 879 assert (current_root == NULL); 880 881 /* If we're running the server, we want to execute this main 882 loop once and only once (we won't be serving multiple roots 883 from this connection, so there's no need to do it more than 884 once). To get out of the loop, we perform a "break" at the 885 end of things. */ 886 887 while ( 888 #ifdef SERVER_SUPPORT 889 server_active || 890 #endif 891 walklist (root_directories, set_root_directory, NULL) 892 ) 893 { 894 #ifdef SERVER_SUPPORT 895 /* Fiddling with CVSROOT doesn't make sense if we're running 896 in server mode, since the client will send the repository 897 directory after the connection is made. */ 898 899 if (!server_active) 900 #endif 901 { 902 /* Now we're 100% sure that we have a valid CVSROOT 903 variable. Parse it to see if we're supposed to do 904 remote accesses or use a special access method. */ 905 906 if (current_parsed_root != NULL) 907 free_cvsroot_t (current_parsed_root); 908 if ((current_parsed_root = parse_cvsroot (current_root)) == NULL) 909 error (1, 0, "Bad CVSROOT."); 910 911 if (trace) 912 fprintf (stderr, "%s-> main loop with CVSROOT=%s\n", 913 CLIENT_SERVER_STR, current_root); 914 915 /* 916 * Check to see if the repository exists. 917 */ 918 #ifdef CLIENT_SUPPORT 919 if (!current_parsed_root->isremote) 920 #endif /* CLIENT_SUPPORT */ 921 { 922 char *path; 923 int save_errno; 924 925 path = xmalloc (strlen (current_parsed_root->directory) 926 + sizeof (CVSROOTADM) 927 + 20); 928 (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); 929 if (readonlyfs == 0 && !isaccessible (path, R_OK | X_OK)) 930 { 931 save_errno = errno; 932 /* If this is "cvs init", the root need not exist yet. */ 933 if (strcmp (command_name, "init") != 0) 934 { 935 error (1, save_errno, "%s", path); 936 } 937 } 938 free (path); 939 } 940 941 #ifdef HAVE_PUTENV 942 /* Update the CVSROOT environment variable if necessary. */ 943 /* FIXME (njc): should we always set this with the CVSROOT from the command line? */ 944 if (cvs_update_env) 945 { 946 static char *prev; 947 char *env; 948 env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) 949 + 1 + 1); 950 (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot); 951 (void) putenv (env); 952 /* do not free env yet, as putenv has control of it */ 953 /* but do free the previous value, if any */ 954 if (prev != NULL) 955 free (prev); 956 prev = env; 957 } 958 #endif 959 } 960 961 /* Parse the CVSROOT/config file, but only for local. For the 962 server, we parse it after we know $CVSROOT. For the 963 client, it doesn't get parsed at all, obviously. The 964 presence of the parse_config call here is not mean to 965 predetermine whether CVSROOT/config overrides things from 966 read_cvsrc and other such places or vice versa. That sort 967 of thing probably needs more thought. */ 968 if (1 969 #ifdef SERVER_SUPPORT 970 && !server_active 971 #endif 972 #ifdef CLIENT_SUPPORT 973 && !current_parsed_root->isremote 974 #endif 975 ) 976 { 977 /* If there was an error parsing the config file, parse_config 978 already printed an error. We keep going. Why? Because 979 if we didn't, then there would be no way to check in a new 980 CVSROOT/config file to fix the broken one! */ 981 parse_config (current_parsed_root->directory); 982 } 983 984 #ifdef CLIENT_SUPPORT 985 /* Need to check for current_parsed_root != NULL here since 986 * we could still be in server mode before the server function 987 * gets called below and sets the root 988 */ 989 if (current_parsed_root != NULL && current_parsed_root->isremote) 990 { 991 /* Create a new list for directory names that we've 992 sent to the server. */ 993 if (dirs_sent_to_server != NULL) 994 dellist (&dirs_sent_to_server); 995 dirs_sent_to_server = getlist (); 996 } 997 #endif 998 999 err = (*(cm->func)) (argc, argv); 1000 1001 /* Mark this root directory as done. When the server is 1002 active, current_root will be NULL -- don't try and 1003 remove it from the list. */ 1004 1005 if (current_root != NULL) 1006 { 1007 Node *n = findnode (root_directories, current_root); 1008 assert (n != NULL); 1009 n->data = (void *) 1; 1010 current_root = NULL; 1011 } 1012 1013 #if 0 1014 /* This will not work yet, since it tries to free (void *) 1. */ 1015 dellist (&root_directories); 1016 #endif 1017 1018 #ifdef SERVER_SUPPORT 1019 if (server_active) 1020 break; 1021 #endif 1022 } /* end of loop for cvsroot values */ 1023 1024 } /* end of stuff that gets done if the user DOESN'T ask for help */ 1025 1026 Lock_Cleanup (); 1027 1028 free (program_path); 1029 if (CVSroot_cmdline != NULL) 1030 free (CVSroot_cmdline); 1031 if (free_CVSroot) 1032 free (CVSroot); 1033 if (free_Editor) 1034 free (Editor); 1035 if (free_Tmpdir) 1036 free (Tmpdir); 1037 root_allow_free (); 1038 1039 #ifdef SYSTEM_CLEANUP 1040 /* Hook for OS-specific behavior, for example socket subsystems on 1041 NT and OS2 or dealing with windows and arguments on Mac. */ 1042 SYSTEM_CLEANUP (); 1043 #endif 1044 1045 /* This is exit rather than return because apparently that keeps 1046 some tools which check for memory leaks happier. */ 1047 exit (err ? EXIT_FAILURE : 0); 1048 /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */ 1049 return 0; 1050 } 1051 1052 char * 1053 Make_Date (rawdate) 1054 char *rawdate; 1055 { 1056 time_t unixtime; 1057 1058 unixtime = get_date (rawdate, (struct timeb *) NULL); 1059 if (unixtime == (time_t) - 1) 1060 error (1, 0, "Can't parse date/time: %s", rawdate); 1061 return date_from_time_t (unixtime); 1062 } 1063 1064 /* Convert a time_t to an RCS format date. This is mainly for the 1065 use of "cvs history", because the CVSROOT/history file contains 1066 time_t format dates; most parts of CVS will want to avoid using 1067 time_t's directly, and instead use RCS_datecmp, Make_Date, &c. 1068 Assuming that the time_t is in GMT (as it generally should be), 1069 then the result will be in GMT too. 1070 1071 Returns a newly malloc'd string. */ 1072 1073 char * 1074 date_from_time_t (unixtime) 1075 time_t unixtime; 1076 { 1077 struct tm *ftm; 1078 char date[MAXDATELEN]; 1079 char *ret; 1080 1081 ftm = gmtime (&unixtime); 1082 if (ftm == NULL) 1083 /* This is a system, like VMS, where the system clock is in local 1084 time. Hopefully using localtime here matches the "zero timezone" 1085 hack I added to get_date (get_date of course being the relevant 1086 issue for Make_Date, and for history.c too I think). */ 1087 ftm = localtime (&unixtime); 1088 1089 (void) sprintf (date, DATEFORM, 1090 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 1091 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 1092 ftm->tm_min, ftm->tm_sec); 1093 ret = xstrdup (date); 1094 return (ret); 1095 } 1096 1097 /* Convert a date to RFC822/1123 format. This is used in contexts like 1098 dates to send in the protocol; it should not vary based on locale or 1099 other such conventions for users. We should have another routine which 1100 does that kind of thing. 1101 1102 The SOURCE date is in our internal RCS format. DEST should point to 1103 storage managed by the caller, at least MAXDATELEN characters. */ 1104 void 1105 date_to_internet (dest, source) 1106 char *dest; 1107 const char *source; 1108 { 1109 struct tm date; 1110 1111 date_to_tm (&date, source); 1112 tm_to_internet (dest, &date); 1113 } 1114 1115 void 1116 date_to_tm (dest, source) 1117 struct tm *dest; 1118 const char *source; 1119 { 1120 if (sscanf (source, SDATEFORM, 1121 &dest->tm_year, &dest->tm_mon, &dest->tm_mday, 1122 &dest->tm_hour, &dest->tm_min, &dest->tm_sec) 1123 != 6) 1124 /* Is there a better way to handle errors here? I made this 1125 non-fatal in case we are called from the code which can't 1126 deal with fatal errors. */ 1127 error (0, 0, "internal error: bad date %s", source); 1128 1129 if (dest->tm_year > 100) 1130 dest->tm_year -= 1900; 1131 1132 dest->tm_mon -= 1; 1133 } 1134 1135 /* Convert a date to RFC822/1123 format. This is used in contexts like 1136 dates to send in the protocol; it should not vary based on locale or 1137 other such conventions for users. We should have another routine which 1138 does that kind of thing. 1139 1140 The SOURCE date is a pointer to a struct tm. DEST should point to 1141 storage managed by the caller, at least MAXDATELEN characters. */ 1142 void 1143 tm_to_internet (dest, source) 1144 char *dest; 1145 const struct tm *source; 1146 { 1147 /* Just to reiterate, these strings are from RFC822 and do not vary 1148 according to locale. */ 1149 static const char *const month_names[] = 1150 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 1151 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 1152 1153 sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday, 1154 source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon], 1155 source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); 1156 } 1157 1158 void 1159 usage (cpp) 1160 register const char *const *cpp; 1161 { 1162 (void) fprintf (stderr, *cpp++, program_name, command_name); 1163 for (; *cpp; cpp++) 1164 (void) fprintf (stderr, *cpp); 1165 error_exit(); 1166 } 1167