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