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