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