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