diff options
author | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
commit | 8982e501c77217c860f79bba431f46a62b607a21 (patch) | |
tree | 70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/main.c | |
parent | 01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff) | |
download | FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.zip FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.tar.gz |
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Diffstat (limited to 'contrib/cvs/src/main.c')
-rw-r--r-- | contrib/cvs/src/main.c | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c new file mode 100644 index 0000000..daa0230 --- /dev/null +++ b/contrib/cvs/src/main.c @@ -0,0 +1,814 @@ +/* + * Copyright (c) 1992, Brian Berliner and Jeff Polk + * Copyright (c) 1989-1992, Brian Berliner + * + * You may distribute under the terms of the GNU General Public License + * as specified in the README file that comes with the CVS 1.4 kit. + * + * This is the main C driver for the CVS system. + * + * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing + * the shell-script CVS system that this is based on. + * + * Usage: + * cvs [options] command [options] [files/modules...] + * + * Where "command" is composed of: + * admin RCS command + * checkout Check out a module/dir/file + * export Like checkout, but used for exporting sources + * update Brings work tree in sync with repository + * commit Checks files into the repository + * diff Runs diffs between revisions + * log Prints "rlog" information for files + * login Record user, host, repos, password + * add Adds an entry to the repository + * remove Removes an entry from the repository + * status Status info on the revisions + * rdiff "patch" format diff listing between releases + * tag Add/delete a symbolic tag to the RCS file + * rtag Add/delete a symbolic tag to the RCS file + * import Import sources into CVS, using vendor branches + * release Indicate that Module is no longer in use. + * history Display history of Users and Modules. + */ + +#include "cvs.h" + +#ifdef HAVE_WINSOCK_H +#include <winsock.h> +#else +extern int gethostname (); +#endif + +#if HAVE_KERBEROS +#include <sys/socket.h> +#include <netinet/in.h> +#include <krb.h> +#ifndef HAVE_KRB_GET_ERR_TEXT +#define krb_get_err_text(status) krb_err_txt[status] +#endif +#endif + +char *program_name; +char *program_path; +/* + * Initialize comamnd_name to "cvs" so that the first call to + * read_cvsrc tries to find global cvs options. + */ +char *command_name = ""; + +/* + * Since some systems don't define this... + */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +char hostname[MAXHOSTNAMELEN]; + +#ifdef AUTH_CLIENT_SUPPORT +int use_authenticating_server = FALSE; +#endif /* AUTH_CLIENT_SUPPORT */ +int use_editor = TRUE; +int use_cvsrc = TRUE; +int cvswrite = !CVSREAD_DFLT; +int really_quiet = FALSE; +int quiet = FALSE; +int trace = FALSE; +int noexec = FALSE; +int logoff = FALSE; +mode_t cvsumask = UMASK_DFLT; + +char *CurDir; + +/* + * Defaults, for the environment variables that are not set + */ +char *Rcsbin = RCSBIN_DFLT; +char *Editor = EDITOR_DFLT; +char *CVSroot = CVSROOT_DFLT; +/* + * The path found in CVS/Root must match $CVSROOT and/or 'cvs -d root' + */ +char *CVSADM_Root = CVSROOT_DFLT; + +int add PROTO((int argc, char **argv)); +int admin PROTO((int argc, char **argv)); +int checkout PROTO((int argc, char **argv)); +int commit PROTO((int argc, char **argv)); +int diff PROTO((int argc, char **argv)); +int history PROTO((int argc, char **argv)); +int import PROTO((int argc, char **argv)); +int cvslog PROTO((int argc, char **argv)); +#ifdef AUTH_CLIENT_SUPPORT +int login PROTO((int argc, char **argv)); +#endif /* AUTH_CLIENT_SUPPORT */ +int patch PROTO((int argc, char **argv)); +int release PROTO((int argc, char **argv)); +int cvsremove PROTO((int argc, char **argv)); +int rtag PROTO((int argc, char **argv)); +int status PROTO((int argc, char **argv)); +int tag PROTO((int argc, char **argv)); +int update PROTO((int argc, char **argv)); + +const struct cmd +{ + char *fullname; /* Full name of the function (e.g. "commit") */ + char *nick1; /* alternate name (e.g. "ci") */ + char *nick2; /* another alternate names (e.g. "ci") */ + int (*func) (); /* Function takes (argc, argv) arguments. */ +#ifdef CLIENT_SUPPORT + int (*client_func) (); /* Function to do it via the protocol. */ +#endif +} cmds[] = + +{ +#ifdef CLIENT_SUPPORT +#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1, f2 } +#else +#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1 } +#endif + + CMD_ENTRY("add", "ad", "new", add, client_add), + CMD_ENTRY("admin", "adm", "rcs", admin, client_admin), + CMD_ENTRY("annotate", NULL, NULL, annotate, client_annotate), + CMD_ENTRY("checkout", "co", "get", checkout, client_checkout), + CMD_ENTRY("commit", "ci", "com", commit, client_commit), + CMD_ENTRY("diff", "di", "dif", diff, client_diff), + CMD_ENTRY("edit", "edit", "edit", edit, client_edit), + CMD_ENTRY("editors", "editors","editors",editors, client_editors), + CMD_ENTRY("export", "exp", "ex", checkout, client_export), + CMD_ENTRY("history", "hi", "his", history, client_history), + CMD_ENTRY("import", "im", "imp", import, client_import), + CMD_ENTRY("init", NULL, NULL, init, client_init), + CMD_ENTRY("log", "lo", "rlog", cvslog, client_log), +#ifdef AUTH_CLIENT_SUPPORT + CMD_ENTRY("login", "logon", "lgn", login, login), +#endif /* AUTH_CLIENT_SUPPORT */ + CMD_ENTRY("rdiff", "patch", "pa", patch, client_rdiff), + CMD_ENTRY("release", "re", "rel", release, client_release), + CMD_ENTRY("remove", "rm", "delete", cvsremove, client_remove), + CMD_ENTRY("status", "st", "stat", status, client_status), + CMD_ENTRY("rtag", "rt", "rfreeze", rtag, client_rtag), + CMD_ENTRY("tag", "ta", "freeze", tag, client_tag), + CMD_ENTRY("unedit", "unedit","unedit", unedit, client_unedit), + CMD_ENTRY("update", "up", "upd", update, client_update), + CMD_ENTRY("watch", "watch", "watch", watch, client_watch), + CMD_ENTRY("watchers", "watchers","watchers",watchers,client_watchers), +#ifdef SERVER_SUPPORT + /* + * The client_func is also server because we might have picked up a + * CVSROOT environment variable containing a colon. The client will send + * the real root later. + */ + CMD_ENTRY("server", "server", "server", server, server), +#endif + CMD_ENTRY(NULL, NULL, NULL, NULL, NULL), + +#undef CMD_ENTRY +}; + +static const char *const usg[] = +{ + "Usage: %s [cvs-options] command [command-options] [files...]\n", + " Where 'cvs-options' are:\n", + " -H Displays Usage information for command\n", + " -Q Cause CVS to be really quiet.\n", + " -q Cause CVS to be somewhat quiet.\n", + " -r Make checked-out files read-only\n", + " -w Make checked-out files read-write (default)\n", + " -l Turn History logging off\n", + " -n Do not execute anything that will change the disk\n", + " -t Show trace of program execution -- Try with -n\n", + " -v CVS version and copyright\n", + " -b bindir Find RCS programs in 'bindir'\n", + " -e editor Use 'editor' for editing log information\n", + " -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n", + " -f Do not use the ~/.cvsrc file\n", +#ifdef CLIENT_SUPPORT + " -z # Use 'gzip -#' for net traffic if possible.\n", +#endif + " -s VAR=VAL Set CVS user variable.\n", + "\n", + " and where 'command' is: add, admin, etc. (use the --help-commands\n", + " option for a list of commands)\n", + NULL, +}; + +static const char *const cmd_usage[] = +{ + "CVS commands are:\n", + " add Adds a new file/directory to the repository\n", + " admin Administration front end for rcs\n", + " annotate Show revision where each line was modified\n", + " checkout Checkout sources for editing\n", + " commit Checks files into the repository\n", + " diff Runs diffs between revisions\n", + " edit Get ready to edit a watched file\n", + " editors See who is editing a watched file\n", + " history Shows status of files and users\n", + " import Import sources into CVS, using vendor branches\n", + " export Export sources from CVS, similar to checkout\n", + " log Prints out 'rlog' information for files\n", +#ifdef AUTH_CLIENT_SUPPORT + " login Prompt for password for authenticating server.\n", +#endif /* AUTH_CLIENT_SUPPORT */ + " rdiff 'patch' format diffs between releases\n", + " release Indicate that a Module is no longer in use\n", + " remove Removes an entry from the repository\n", + " status Status info on the revisions\n", + " tag Add a symbolic tag to checked out version of RCS file\n", + " unedit Undo an edit command\n", + " rtag Add a symbolic tag to the RCS file\n", + " update Brings work tree in sync with repository\n", + " watch Set watches\n", + " watchers See who is watching a file\n", + NULL, +}; + +static RETSIGTYPE +main_cleanup () +{ + exit (EXIT_FAILURE); +} + +static void +error_cleanup PROTO((void)) +{ + Lock_Cleanup(); +#ifdef SERVER_SUPPORT + if (server_active) + server_cleanup (0); +#endif +} + +int +main (argc, argv) + int argc; + char **argv; +{ + extern char *version_string; + extern char *config_string; + char *cp, *end; + const struct cmd *cm; + int c, err = 0; + static int help = FALSE; + static int version_flag = FALSE; + static int help_commands = FALSE; + int rcsbin_update_env, cvs_update_env = 0; + static struct option long_options[] = + { + {"help", 0, &help, TRUE}, + {"version", 0, &version_flag, TRUE}, + {"help-commands", 0, &help_commands, TRUE}, + {0, 0, 0, 0} + }; + /* `getopt_long' stores the option index here, but right now we + don't use it. */ + int option_index = 0; + + error_set_cleanup (error_cleanup); + +/* The socket subsystems on NT and OS2 must be initialized before use */ +#ifdef INITIALIZE_SOCKET_SUBSYSTEM + INITIALIZE_SOCKET_SUBSYSTEM(); +#endif /* INITIALIZE_SOCKET_SUBSYSTEM */ + + /* + * Just save the last component of the path for error messages + */ + program_path = xstrdup (argv[0]); + program_name = last_component (argv[0]); + + CurDir = xmalloc (PATH_MAX); +#ifndef SERVER_SUPPORT + if (!getwd (CurDir)) + error (1, 0, "cannot get working directory: %s", CurDir); +#endif + + /* + * Query the environment variables up-front, so that + * they can be overridden by command line arguments + */ + rcsbin_update_env = *Rcsbin; /* RCSBIN_DFLT must be set */ + cvs_update_env = 0; + if ((cp = getenv (RCSBIN_ENV)) != NULL) + { + Rcsbin = cp; + rcsbin_update_env = 0; /* it's already there */ + } + if ((cp = getenv (EDITOR1_ENV)) != NULL) + Editor = cp; + else if ((cp = getenv (EDITOR2_ENV)) != NULL) + Editor = cp; + else if ((cp = getenv (EDITOR3_ENV)) != NULL) + Editor = cp; + if ((cp = getenv (CVSROOT_ENV)) != NULL) + { + CVSroot = cp; + cvs_update_env = 0; /* it's already there */ + } + if (getenv (CVSREAD_ENV) != NULL) + cvswrite = FALSE; + if ((cp = getenv (CVSUMASK_ENV)) != NULL) + { + /* FIXME: Should be accepting symbolic as well as numeric mask. */ + cvsumask = strtol (cp, &end, 8) & 0777; + if (*end != '\0') + error (1, errno, "invalid umask value in %s (%s)", + CVSUMASK_ENV, cp); + } + + /* This has the effect of setting getopt's ordering to REQUIRE_ORDER, + which is what we need to distinguish between global options and + command options. FIXME: It would appear to be possible to do this + much less kludgily by passing "+" as the first character to the + option string we pass to getopt_long. */ + optind = 1; + + + /* We have to parse the options twice because else there is no + chance to avoid reading the global options from ".cvsrc". Set + opterr to 0 for avoiding error messages about invalid options. + */ + opterr = 0; + + while ((c = getopt_long + (argc, argv, "f", NULL, NULL)) + != EOF) + { + if (c == 'f') + use_cvsrc = FALSE; + } + + /* + * Scan cvsrc file for global options. + */ + if (use_cvsrc) + read_cvsrc (&argc, &argv, "cvs"); + + optind = 1; + opterr = 1; + + while ((c = getopt_long + (argc, argv, "Qqrwtnlvb:e:d:Hfz:s:", long_options, &option_index)) + != EOF) + { + switch (c) + { + case 0: + /* getopt_long took care of setting the flag. */ + break; + case 'Q': + really_quiet = TRUE; + /* FALL THROUGH */ + case 'q': + quiet = TRUE; + break; + case 'r': + cvswrite = FALSE; + break; + case 'w': + cvswrite = TRUE; + break; + case 't': + trace = TRUE; + break; + case 'n': + noexec = TRUE; + case 'l': /* Fall through */ + logoff = TRUE; + break; + case 'v': + version_flag = TRUE; + break; + case 'b': + Rcsbin = optarg; + rcsbin_update_env = 1; /* need to update environment */ + break; + case 'e': + Editor = optarg; + break; + case 'd': + CVSroot = optarg; + cvs_update_env = 1; /* need to update environment */ + break; + case 'H': + use_cvsrc = FALSE; /* this ensure that cvs -H works */ + help = TRUE; + break; + case 'f': + use_cvsrc = FALSE; + break; + case 'z': +#ifdef CLIENT_SUPPORT + gzip_level = atoi (optarg); + if (gzip_level <= 0 || gzip_level > 9) + error (1, 0, + "gzip compression level must be between 1 and 9"); +#endif + /* If no CLIENT_SUPPORT, we just silently ignore the gzip + level, so that users can have it in their .cvsrc and not + cause any trouble. */ + break; + case 's': + variable_set (optarg); + break; + case '?': + default: + usage (usg); + } + } + + if (version_flag == TRUE) + { + (void) fputs (version_string, stdout); + (void) fputs (config_string, stdout); + (void) fputs ("\n", stdout); + (void) fputs ("Copyright (c) 1993-1994 Brian Berliner\n", stdout); + (void) fputs ("Copyright (c) 1993-1994 david d `zoo' zuhn\n", stdout); + (void) fputs ("Copyright (c) 1992, Brian Berliner and Jeff Polk\n", stdout); + (void) fputs ("Copyright (c) 1989-1992, Brian Berliner\n", stdout); + (void) fputs ("\n", stdout); + (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); + (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout); + exit (0); + } + else if (help_commands) + usage (cmd_usage); + + argc -= optind; + argv += optind; + if (argc < 1) + usage (usg); + +#ifdef HAVE_KERBEROS + /* If we are invoked with a single argument "kserver", then we are + running as Kerberos server as root. Do the authentication as + the very first thing, to minimize the amount of time we are + running as root. */ + if (strcmp (argv[0], "kserver") == 0) + { + int status; + char instance[INST_SZ]; + struct sockaddr_in peer; + struct sockaddr_in laddr; + int len; + KTEXT_ST ticket; + AUTH_DAT auth; + char version[KRB_SENDAUTH_VLEN]; + Key_schedule sched; + char user[ANAME_SZ]; + struct passwd *pw; + + strcpy (instance, "*"); + len = sizeof peer; + if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0 + || getsockname (STDIN_FILENO, (struct sockaddr *) &laddr, + &len) < 0) + { + printf ("E Fatal error, aborting.\n\ +error %s getpeername or getsockname failed\n", strerror (errno)); + exit (EXIT_FAILURE); + } + + status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd", + instance, &peer, &laddr, &auth, "", sched, + version); + if (status != KSUCCESS) + { + printf ("E Fatal error, aborting.\n\ +error 0 kerberos: %s\n", krb_get_err_text(status)); + exit (EXIT_FAILURE); + } + + /* Get the local name. */ + status = krb_kntoln (&auth, user); + if (status != KSUCCESS) + { + printf ("E Fatal error, aborting.\n\ +error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status)); + exit (EXIT_FAILURE); + } + + pw = getpwnam (user); + if (pw == NULL) + { + printf ("E Fatal error, aborting.\n\ +error 0 %s: no such user\n", user); + exit (EXIT_FAILURE); + } + + initgroups (pw->pw_name, pw->pw_gid); + setgid (pw->pw_gid); + setuid (pw->pw_uid); + /* Inhibit access by randoms. Don't want people randomly + changing our temporary tree before we check things in. */ + umask (077); + +#if HAVE_PUTENV + /* Set LOGNAME and USER in the environment, in case they are + already set to something else. */ + { + char *env; + + env = xmalloc (sizeof "LOGNAME=" + strlen (user)); + (void) sprintf (env, "LOGNAME=%s", user); + (void) putenv (env); + + env = xmalloc (sizeof "USER=" + strlen (user)); + (void) sprintf (env, "USER=%s", user); + (void) putenv (env); + } +#endif + + /* Pretend we were invoked as a plain server. */ + argv[0] = "server"; + } +#endif /* HAVE_KERBEROS */ + + +#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT) + if (strcmp (argv[0], "pserver") == 0) + { + /* Gets username and password from client, authenticates, then + switches to run as that user and sends an ACK back to the + client. */ + authenticate_connection (); + + /* Pretend we were invoked as a plain server. */ + argv[0] = "server"; + } +#endif /* AUTH_SERVER_SUPPORT && SERVER_SUPPORT */ + + + /* + * See if we are able to find a 'better' value for CVSroot in the + * CVSADM_ROOT directory. + */ +#ifdef SERVER_SUPPORT + if (strcmp (argv[0], "server") == 0 && CVSroot == NULL) + CVSADM_Root = NULL; + else + CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); +#else /* No SERVER_SUPPORT */ + CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); +#endif /* No SERVER_SUPPORT */ + if (CVSADM_Root != NULL) + { + if (CVSroot == NULL || !cvs_update_env) + { + CVSroot = CVSADM_Root; + cvs_update_env = 1; /* need to update environment */ + } +#ifdef CLIENT_SUPPORT + else if (!getenv ("CVS_IGNORE_REMOTE_ROOT")) +#else /* ! CLIENT_SUPPORT */ + else +#endif /* CLIENT_SUPPORT */ + { + /* + * Now for the hard part, compare the two directories. If they + * are not identical, then abort this command. + */ + if ((fncmp (CVSroot, CVSADM_Root) != 0) && + !same_directories(CVSroot, CVSADM_Root)) + { + error (0, 0, "%s value for CVS Root found in %s", + CVSADM_Root, CVSADM_ROOT); + error (0, 0, "does not match command line -d %s setting", + CVSroot); + error (1, 0, + "you may wish to try the cvs command again without the -d option "); + } + } + } + + /* CVSroot may need fixing up, if an access-method was specified, + * but not a user. Later code assumes that if CVSroot contains an + * access-method, then it also has a user. We print a warning and + * die if we can't guarantee that. + */ + if (CVSroot + && *CVSroot + && (CVSroot[0] == ':') + && (strchr (CVSroot, '@') == NULL)) + { + error (1, 0, + "must also give a username if specifying access method"); + } + + /* + * Specifying just the '-H' flag to the sub-command causes a Usage + * message to be displayed. + */ + command_name = cp = argv[0]; + if (help == TRUE || (argc > 1 && strcmp (argv[1], "-H") == 0)) + argc = -1; + else + { + /* + * Check to see if we can write into the history file. If not, + * we assume that we can't work in the repository. + * BUT, only if the history file exists. + */ +#ifdef SERVER_SUPPORT + if (strcmp (command_name, "server") != 0 || CVSroot != NULL) +#endif + { + char path[PATH_MAX]; + int save_errno; + + if (!CVSroot || !*CVSroot) + error (1, 0, "You don't have a %s environment variable", + CVSROOT_ENV); + (void) sprintf (path, "%s/%s", CVSroot, CVSROOTADM); + if (!isaccessible (path, R_OK | X_OK)) + { + save_errno = errno; + /* If this is "cvs init", the root need not exist yet. */ + if (strcmp (command_name, "init") != 0 +#ifdef CLIENT_SUPPORT + /* If we are a remote client, the root need not exist + on the client machine (FIXME: we should also skip + the check for CVSROOTADM_HISTORY being writable; + it shouldn't matter if there is a read-only file + which happens to have the same name on the client + machine). */ + && strchr (CVSroot, ':') == NULL) +#endif + { + error (0, 0, + "Sorry, you don't have sufficient access to %s", CVSroot); + error (1, save_errno, "%s", path); + } + } + (void) strcat (path, "/"); + (void) strcat (path, CVSROOTADM_HISTORY); + if (isfile (path) && !isaccessible (path, R_OK | W_OK)) + { + save_errno = errno; + error (0, 0, + "Sorry, you don't have read/write access to the history file"); + error (1, save_errno, "%s", path); + } + } + } + +#ifdef SERVER_SUPPORT + if (strcmp (command_name, "server") == 0) + /* This is only used for writing into the history file. Might + be nice to have hostname and/or remote path, on the other hand + I'm not sure whether it is worth the trouble. */ + strcpy (CurDir, "<remote>"); + else if (!getwd (CurDir)) + error (1, 0, "cannot get working directory: %s", CurDir); +#endif + +#ifdef HAVE_PUTENV + /* Now, see if we should update the environment with the Rcsbin value */ + if (cvs_update_env) + { + char *env; + + env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1); + (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot); + (void) putenv (env); + /* do not free env, as putenv has control of it */ + } + if (rcsbin_update_env) + { + char *env; + + env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1); + (void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin); + (void) putenv (env); + /* do not free env, as putenv has control of it */ + } +#endif + + /* + * If Rcsbin is set to something, make sure it is terminated with + * a slash character. If not, add one. + */ + if (*Rcsbin) + { + int len = strlen (Rcsbin); + char *rcsbin; + + if (Rcsbin[len - 1] != '/') + { + rcsbin = Rcsbin; + Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */ + (void) strcpy (Rcsbin, rcsbin); + (void) strcat (Rcsbin, "/"); + } + } + + for (cm = cmds; cm->fullname; cm++) + { + if (cm->nick1 && !strcmp (cp, cm->nick1)) + break; + if (cm->nick2 && !strcmp (cp, cm->nick2)) + break; + if (!strcmp (cp, cm->fullname)) + break; + } + + if (!cm->fullname) + usage (usg); /* no match */ + else + { + command_name = cm->fullname; /* Global pointer for later use */ + + /* make sure we clean up on error */ +#ifdef SIGHUP + (void) SIG_register (SIGHUP, main_cleanup); + (void) SIG_register (SIGHUP, Lock_Cleanup); +#endif +#ifdef SIGINT + (void) SIG_register (SIGINT, main_cleanup); + (void) SIG_register (SIGINT, Lock_Cleanup); +#endif +#ifdef SIGQUIT + (void) SIG_register (SIGQUIT, main_cleanup); + (void) SIG_register (SIGQUIT, Lock_Cleanup); +#endif +#ifdef SIGPIPE + (void) SIG_register (SIGPIPE, main_cleanup); + (void) SIG_register (SIGPIPE, Lock_Cleanup); +#endif +#ifdef SIGTERM + (void) SIG_register (SIGTERM, main_cleanup); + (void) SIG_register (SIGTERM, Lock_Cleanup); +#endif + + gethostname(hostname, sizeof (hostname)); + +#ifdef HAVE_SETVBUF + /* + * Make stdout line buffered, so 'tail -f' can monitor progress. + * Patch creates too much output to monitor and it runs slowly. + */ + if (strcmp (cm->fullname, "patch")) + (void) setvbuf (stdout, (char *) NULL, _IOLBF, 0); +#endif + + if (use_cvsrc) + read_cvsrc (&argc, &argv, command_name); + +#ifdef CLIENT_SUPPORT + /* If cvsroot contains a colon, try to do it via the protocol. */ + { + char *p = CVSroot == NULL ? NULL : strchr (CVSroot, ':'); + if (p) + err = (*(cm->client_func)) (argc, argv); + else + err = (*(cm->func)) (argc, argv); + } +#else /* No CLIENT_SUPPORT */ + err = (*(cm->func)) (argc, argv); + +#endif /* No CLIENT_SUPPORT */ + } + Lock_Cleanup (); + if (err) + return (EXIT_FAILURE); + return 0; +} + +char * +Make_Date (rawdate) + char *rawdate; +{ + struct tm *ftm; + time_t unixtime; + char date[256]; /* XXX bigger than we'll ever need? */ + char *ret; + + unixtime = get_date (rawdate, (struct timeb *) NULL); + if (unixtime == (time_t) - 1) + error (1, 0, "Can't parse date/time: %s", rawdate); +#ifdef HAVE_RCS5 + ftm = gmtime (&unixtime); +#else + ftm = localtime (&unixtime); +#endif + (void) sprintf (date, DATEFORM, + ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), + ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, + ftm->tm_min, ftm->tm_sec); + ret = xstrdup (date); + return (ret); +} + +void +usage (cpp) + register const char *const *cpp; +{ + (void) fprintf (stderr, *cpp++, program_name, command_name); + for (; *cpp; cpp++) + (void) fprintf (stderr, *cpp); + exit (EXIT_FAILURE); +} |