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