From aab6aeadd4dbf9718f16e2c79a3c4253d2e17a04 Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 11 Dec 1999 13:00:18 +0000 Subject: Merge cyclic changes from 1.10.7 into our mainline. I did this seperately as cvs update -j had kittens over the whole thing and I ended up merging it by hand. --- contrib/cvs/src/main.c | 483 ++++++++++++++++++++++++++++++------------------- 1 file changed, 301 insertions(+), 182 deletions(-) (limited to 'contrib/cvs/src') diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c index 6792245..39bfaa2 100644 --- a/contrib/cvs/src/main.c +++ b/contrib/cvs/src/main.c @@ -10,10 +10,10 @@ * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing * the shell-script CVS system that this is based on. * + * $FreeBSD$ */ -/* $FreeBSD$ */ - +#include #include "cvs.h" #include "prepend_args.h" @@ -62,6 +62,16 @@ char *CurDir; char *Tmpdir = TMPDIR_DFLT; char *Editor = EDITOR_DFLT; + +/* When our working directory contains subdirectories with different + values in CVS/Root files, we maintain a list of them. */ +List *root_directories = NULL; + +/* We step through the above values. This variable is set to reflect + the currently active value. */ +char *current_root = NULL; + + static const struct cmd { char *fullname; /* Full name of the function (e.g. "commit") */ @@ -214,6 +224,7 @@ static const char *const cmd_usage[] = static const char *const opt_usage[] = { + /* Omit -b because it is just for compatibility. */ "CVS global options (specified before the command name) are:\n", " -H Displays usage information for command.\n", " -Q Cause CVS to be really quiet.\n", @@ -226,7 +237,6 @@ static const char *const opt_usage[] = " -t Show trace of program execution -- try with -n.\n", " -R Assume repository is read-only, such as CDROM\n", " -v CVS version and copyright.\n", - " -b bindir Find RCS programs in 'bindir'.\n", " -T tmpdir Use 'tmpdir' for temporary files.\n", " -e editor Use 'editor' for editing log information.\n", " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n", @@ -243,6 +253,21 @@ static const char *const opt_usage[] = NULL }; + +static int +set_root_directory (p, ignored) + Node *p; + void *ignored; +{ + if (current_root == NULL && p->data == NULL) + { + current_root = p->key; + return 1; + } + return 0; +} + + static const char * const* cmd_synonyms () { @@ -318,7 +343,6 @@ lookup_command_attribute (cmd_name) (strcmp (cmd_name, "diff") != 0) && (strcmp (cmd_name, "rdiff") != 0) && (strcmp (cmd_name, "update") != 0) && - (strcmp (cmd_name, "history") != 0) && (strcmp (cmd_name, "editors") != 0) && (strcmp (cmd_name, "export") != 0) && (strcmp (cmd_name, "history") != 0) && @@ -413,7 +437,6 @@ main (argc, argv) /* `getopt_long' stores the option index here, but right now we don't use it. */ int option_index = 0; - int need_to_create_root = 0; #ifdef SYSTEM_INITIALIZE /* Hook for OS-specific behavior, for example socket subsystems on @@ -586,6 +609,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ free_Editor = 1; break; case 'd': + if (CVSroot_cmdline != NULL) + free (CVSroot_cmdline); + CVSroot_cmdline = xstrdup (optarg); CVSroot = xstrdup (optarg); free_CVSroot = 1; cvs_update_env = 1; /* need to update environment */ @@ -673,7 +699,10 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ } if (help) + { argc = -1; /* some functions only check for this */ + err = (*(cm->func)) (argc, argv); + } else { /* The user didn't ask for help, so go ahead and authenticate, @@ -730,152 +759,8 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ #ifdef SERVER_SUPPORT server_active = strcmp (command_name, "server") == 0; - - /* Fiddling with CVSROOT doesn't make sense if we're running - in server mode, since the client will send the repository - directory after the connection is made. */ - - if (!server_active) #endif - { - char *CVSADM_Root; - - /* See if we are able to find a 'better' value for CVSroot - in the CVSADM_ROOT directory. */ - CVSADM_Root = NULL; - - /* "cvs import" shouldn't check CVS/Root; in general it - ignores CVS directories and CVS/Root is likely to - specify a different repository than the one we are - importing to. */ - - if (lookup_command_attribute (command_name) - & CVS_CMD_IGNORE_ADMROOT) - { - CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); - } - - if (CVSADM_Root != NULL) - { - if (CVSroot == NULL || !cvs_update_env) - { - CVSroot = CVSADM_Root; - cvs_update_env = 1; /* need to update environment */ - } - /* Let -d override CVS/Root file. The user might want - to change the access method, use a different server - (if there are two server machines which share the - repository using a networked file system), etc. */ - else if ( -#ifdef CLIENT_SUPPORT - !getenv ("CVS_IGNORE_REMOTE_ROOT") && -#endif - strcmp (CVSroot, CVSADM_Root) != 0) - { - /* Once we have verified that this root is usable, - we will want to write it into CVS/Root. - - Don't do it for the "login" command, however. - Consider: if the user executes "cvs login" with - the working directory inside an already checked - out module, we'd incorrectly change the - CVS/Root file to reflect the CVSROOT of the - "cvs login" command. Ahh, the things one - discovers. */ - - if (lookup_command_attribute (command_name) - & CVS_CMD_USES_WORK_DIR) - { - need_to_create_root = 1; - } - - } - } - - /* Now we've reconciled CVSROOT from the command line, the - CVS/Root file, and the environment variable. Do the - last sanity checks on the variable. */ - - if (! CVSroot) - { - error (0, 0, - "No CVSROOT specified! Please use the `-d' option"); - error (1, 0, - "or set the %s environment variable.", CVSROOT_ENV); - } - - if (! *CVSroot) - { - error (0, 0, - "CVSROOT is set but empty! Make sure that the"); - error (0, 0, - "specification of CVSROOT is legal, either via the"); - error (0, 0, - "`-d' option, the %s environment variable, or the", - CVSROOT_ENV); - error (1, 0, - "CVS/Root file (if any)."); - } - - /* Now we're 100% sure that we have a valid CVSROOT - variable. Parse it to see if we're supposed to do - remote accesses or use a special access method. */ - - if (parse_cvsroot (CVSroot)) - error (1, 0, "Bad CVSROOT."); - - /* - * 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. - */ - - if (!client_active) - { - char *path; - int save_errno; - - path = xmalloc (strlen (CVSroot_directory) - + sizeof (CVSROOTADM) - + 20 - + sizeof (CVSROOTADM_HISTORY)); - (void) sprintf (path, "%s/%s", CVSroot_directory, 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) - { - error (1, save_errno, "%s", path); - } - } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (readonlyfs == 0 && 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); - } - free (path); - } - -#ifdef HAVE_PUTENV - /* Update the CVSROOT environment variable if necessary. */ - - 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 */ - } -#endif - } - /* This is only used for writing into the history file. For remote connections, it might be nice to have hostname and/or remote path, on the other hand I'm not sure whether @@ -949,49 +834,246 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ if (use_cvsrc) read_cvsrc (&argc, &argv, command_name); - /* Parse the CVSROOT/config file, but only for local. For the - server, we parse it after we know $CVSROOT. For the - client, it doesn't get parsed at all, obviously. The - presence of the parse_config call here is not mean to - predetermine whether CVSROOT/config overrides things from - read_cvsrc and other such places or vice versa. That sort - of thing probably needs more thought. */ - if (1 #ifdef SERVER_SUPPORT - && !server_active -#endif -#ifdef CLIENT_SUPPORT - && !client_active + /* Fiddling with CVSROOT doesn't make sense if we're running + in server mode, since the client will send the repository + directory after the connection is made. */ + + if (!server_active) #endif - ) { - /* If there was an error parsing the config file, parse_config - already printed an error. We keep going. Why? Because - if we didn't, then there would be no way to check in a new - CVSROOT/config file to fix the broken one! */ - parse_config (CVSroot_directory); - - /* Now is a convenient time to read CVSROOT/options */ - parseopts(CVSroot_directory); + char *CVSADM_Root; + + /* See if we are able to find a 'better' value for CVSroot + in the CVSADM_ROOT directory. */ + + CVSADM_Root = NULL; + + /* "cvs import" shouldn't check CVS/Root; in general it + ignores CVS directories and CVS/Root is likely to + specify a different repository than the one we are + importing to. */ + + if ((lookup_command_attribute (command_name) + & CVS_CMD_IGNORE_ADMROOT) + + /* -d overrides CVS/Root, so don't give an error if the + latter points to a nonexistent repository. */ + && CVSroot_cmdline == NULL) + { + CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); + } + + if (CVSADM_Root != NULL) + { + if (CVSroot == NULL || !cvs_update_env) + { + CVSroot = CVSADM_Root; + cvs_update_env = 1; /* need to update environment */ + } + } + + /* Now we've reconciled CVSROOT from the command line, the + CVS/Root file, and the environment variable. Do the + last sanity checks on the variable. */ + + if (! CVSroot) + { + error (0, 0, + "No CVSROOT specified! Please use the `-d' option"); + error (1, 0, + "or set the %s environment variable.", CVSROOT_ENV); + } + + if (! *CVSroot) + { + error (0, 0, + "CVSROOT is set but empty! Make sure that the"); + error (0, 0, + "specification of CVSROOT is legal, either via the"); + error (0, 0, + "`-d' option, the %s environment variable, or the", + CVSROOT_ENV); + error (1, 0, + "CVS/Root file (if any)."); + } } - } /* end of stuff that gets done if the user DOESN'T ask for help */ - err = (*(cm->func)) (argc, argv); + /* Here begins the big loop over unique cvsroot values. We + need to call do_recursion once for each unique value found + in CVS/Root. Prime the list with the current value. */ - if (need_to_create_root) - { - /* Update the CVS/Root file. We might want to do this in - all directories that we recurse into, but currently we - don't. Note that if there is an error writing the file, - we give an error/warning. This is so if users try to rewrite - CVS/Root with the -d option (a documented feature), they will - either succeed, or be told why it didn't work. */ - Create_Root (NULL, CVSroot); - } + /* Create the list. */ + assert (root_directories == NULL); + root_directories = getlist (); + + /* Prime it. */ + if (CVSroot != NULL) + { + Node *n; + n = getnode (); + n->type = UNKNOWN; + n->key = xstrdup (CVSroot); + n->data = NULL; + + if (addnode (root_directories, n)) + error (1, 0, "cannot add initial CVSROOT %s", n->key); + } + + assert (current_root == NULL); + + /* If we're running the server, we want to execute this main + loop once and only once (we won't be serving multiple roots + from this connection, so there's no need to do it more than + once). To get out of the loop, we perform a "break" at the + end of things. */ + + while ( +#ifdef SERVER_SUPPORT + server_active || +#endif + walklist (root_directories, set_root_directory, NULL) + ) + { +#ifdef SERVER_SUPPORT + /* Fiddling with CVSROOT doesn't make sense if we're running + in server mode, since the client will send the repository + directory after the connection is made. */ + + if (!server_active) +#endif + { + /* Now we're 100% sure that we have a valid CVSROOT + variable. Parse it to see if we're supposed to do + remote accesses or use a special access method. */ + + if (parse_cvsroot (current_root)) + error (1, 0, "Bad CVSROOT."); + + if (trace) + error (0, 0, "notice: main loop with CVSROOT=%s", + current_root); + + /* + * 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. + */ + + if (!client_active) + { + char *path; + int save_errno; + + path = xmalloc (strlen (CVSroot_directory) + + sizeof (CVSROOTADM) + + 20 + + sizeof (CVSROOTADM_HISTORY)); + (void) sprintf (path, "%s/%s", CVSroot_directory, 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) + { + error (1, save_errno, "%s", path); + } + } + (void) strcat (path, "/"); + (void) strcat (path, CVSROOTADM_HISTORY); + if (readonlyfs == 0 && 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); + } + free (path); + } + +#ifdef HAVE_PUTENV + /* Update the CVSROOT environment variable if necessary. */ + /* FIXME (njc): should we always set this with the CVSROOT from the command line? */ + 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 */ + } +#endif + } + + /* Parse the CVSROOT/config file, but only for local. For the + server, we parse it after we know $CVSROOT. For the + client, it doesn't get parsed at all, obviously. The + presence of the parse_config call here is not mean to + predetermine whether CVSROOT/config overrides things from + read_cvsrc and other such places or vice versa. That sort + of thing probably needs more thought. */ + if (1 +#ifdef SERVER_SUPPORT + && !server_active +#endif +#ifdef CLIENT_SUPPORT + && !client_active +#endif + ) + { + /* If there was an error parsing the config file, parse_config + already printed an error. We keep going. Why? Because + if we didn't, then there would be no way to check in a new + CVSROOT/config file to fix the broken one! */ + parse_config (CVSroot_directory); + + /* Now is a convenient time to read CVSROOT/options */ + parseopts(CVSroot_directory); + } + +#ifdef CLIENT_SUPPORT + if (client_active) + { + /* Create a new list for directory names that we've + sent to the server. */ + if (dirs_sent_to_server != NULL) + dellist (&dirs_sent_to_server); + dirs_sent_to_server = getlist (); + } +#endif + + err = (*(cm->func)) (argc, argv); + + /* Mark this root directory as done. When the server is + active, current_root will be NULL -- don't try and + remove it from the list. */ + + if (current_root != NULL) + { + Node *n = findnode (root_directories, current_root); + assert (n != NULL); + n->data = (void *) 1; + current_root = NULL; + } + +#if 0 + /* This will not work yet, since it tries to free (void *) 1. */ + dellist (&root_directories); +#endif + +#ifdef SERVER_SUPPORT + if (server_active) + break; +#endif + } /* end of loop for cvsroot values */ + + } /* end of stuff that gets done if the user DOESN'T ask for help */ Lock_Cleanup (); free (program_path); + if (CVSroot_cmdline != NULL) + free (CVSroot_cmdline); if (free_CVSroot) free (CVSroot); if (free_Editor) @@ -1058,6 +1140,43 @@ date_from_time_t (unixtime) return (ret); } +/* Convert a date to RFC822/1123 format. This is used in contexts like + dates to send in the protocol; it should not vary based on locale or + other such conventions for users. We should have another routine which + does that kind of thing. + + The SOURCE date is in our internal RCS format. DEST should point to + storage managed by the caller, at least MAXDATELEN characters. */ +void +date_to_internet (dest, source) + char *dest; + char *source; +{ + int year, month, day, hour, minute, second; + + /* Just to reiterate, these strings are from RFC822 and do not vary + according to locale. */ + static const char *const month_names[] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (sscanf (source, SDATEFORM, + &year, &month, &day, &hour, &minute, &second) + != 6) + /* Is there a better way to handle errors here? I made this + non-fatal in case we are called from the code which can't + deal with fatal errors. */ + error (0, 0, "internal error: bad date %s", source); + + /* Always send a four digit year. */ + if (year < 100) + year += 1900; + + sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", day, + month < 1 || month > 12 ? "???" : month_names[month - 1], + year, hour, minute, second); +} + void usage (cpp) register const char *const *cpp; -- cgit v1.1