diff options
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r-- | contrib/cvs/src/NOTES | 60 | ||||
-rw-r--r-- | contrib/cvs/src/README-rm-add | 31 | ||||
-rw-r--r-- | contrib/cvs/src/client.c | 351 | ||||
-rw-r--r-- | contrib/cvs/src/commit.c | 93 | ||||
-rw-r--r-- | contrib/cvs/src/cvs.h | 66 | ||||
-rw-r--r-- | contrib/cvs/src/diff.c | 124 | ||||
-rw-r--r-- | contrib/cvs/src/filesubr.c | 259 | ||||
-rw-r--r-- | contrib/cvs/src/import.c | 32 | ||||
-rw-r--r-- | contrib/cvs/src/lock.c | 31 | ||||
-rw-r--r-- | contrib/cvs/src/login.c | 760 | ||||
-rw-r--r-- | contrib/cvs/src/logmsg.c | 104 | ||||
-rw-r--r-- | contrib/cvs/src/main.c | 316 | ||||
-rw-r--r-- | contrib/cvs/src/mkmodules.c | 15 | ||||
-rw-r--r-- | contrib/cvs/src/prepend_args.c | 86 | ||||
-rw-r--r-- | contrib/cvs/src/prepend_args.h | 26 | ||||
-rw-r--r-- | contrib/cvs/src/rcs.c | 413 | ||||
-rw-r--r-- | contrib/cvs/src/rcs.h | 15 | ||||
-rw-r--r-- | contrib/cvs/src/rcscmds.c | 10 | ||||
-rw-r--r-- | contrib/cvs/src/recurse.c | 25 | ||||
-rw-r--r-- | contrib/cvs/src/server.c | 457 | ||||
-rw-r--r-- | contrib/cvs/src/update.c | 135 |
21 files changed, 1699 insertions, 1710 deletions
diff --git a/contrib/cvs/src/NOTES b/contrib/cvs/src/NOTES deleted file mode 100644 index 646ebdf..0000000 --- a/contrib/cvs/src/NOTES +++ /dev/null @@ -1,60 +0,0 @@ -wishlist - Tue Nov 2 15:22:58 PST 1993 - -* bcopy -> memcpy & friends. - ** done 12/18/93 - -* remove static buffers. -* replace list & node cache with recursive obstacks, (xmalloc, - getnode, getlist) -* check all io functions for error return codes. also check all - system calls. -* error check mkdir. - ---- -Old notes... - -* All sizing limits are gone. The rest of these items were incidental - in that effort. - -* login name from history was duplicated. taught existing routine to - cache and use that instead. Also add routines to cache uid, pid, - etc. - -* ign strings were never freed. Now they are. - -* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now - fixed. - -* The environment variables TMPDIR, HOME, and LOGNAME were not - honored. Now they are. - -* extra line inserted by do_editor() is gone. Then obviated. Editor - is now called exactly once per checkin. - -* revised editor behaviour. Never use /dev/tty. If the editor - session fails, we haven't yet done anything. Therefor the user can - safely rerun cvs and we should just fail. Also use the editor for - initial log messages on added files. Also omit the confirmation - when adding directories. Adding directories will require an - explicit "commit" step soon. Make it possible to prevent null login - messages using #define REQUIRE_LOG_MESSAGES - -* prototypes for all callbacks. - -* all callbacks get ref pointers. - -* do_recursion/start_recursion now use recusion_frame's rather than a - list of a lot of pointers and global variables. - -* corrected types on status_dirproc(). - -* CONFIRM_DIRECTORY_ADDS - -* re_comp was innappropriate in a few places. I've eliminated it. - -* FORCE_MESSAGE_ON_ADD - -* So I built a regression test. Let's call it a sanity check to be - less ambitious. It exposed that cvs is difficult to call from - scripts. - diff --git a/contrib/cvs/src/README-rm-add b/contrib/cvs/src/README-rm-add deleted file mode 100644 index 87fd7c6..0000000 --- a/contrib/cvs/src/README-rm-add +++ /dev/null @@ -1,31 +0,0 @@ -WHAT THE "DEATH SUPPORT" FEATURES DO: - -(Some of the death support stuff is documented in the main manual, but -this file is for stuff which noone has gotten around to adding to the -main manual yet). - -CVS with death support can record when a file is active, or alive, and -when it is removed, or dead. With this facility you can record the -history of a file, including the fact that at some point in its life -the file was removed and then later added. - -Files can now be added or removed in a branch and later merged -into the trunk. - - cvs update -A - touch a b c - cvs add a b c ; cvs ci -m "added" a b c - cvs tag -b branchtag - cvs update -r branchtag - touch d ; cvs add d - rm a ; cvs rm a - cvs ci -m "added d, removed a" - cvs update -A - cvs update -jbranchtag - -Added and removed files may also be merged between branches. - -Files removed in the trunk may be merged into branches. - -Files added on the trunk are a special case. They cannot be merged -into a branch. Instead, simply branch the file by hand. diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c index 0b57b35..525cb79 100644 --- a/contrib/cvs/src/client.c +++ b/contrib/cvs/src/client.c @@ -12,6 +12,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +/* + * $FreeBSD$ + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ @@ -32,7 +36,6 @@ # else /* No winsock.h */ # include <sys/socket.h> # include <netinet/in.h> -# include <arpa/inet.h> # include <netdb.h> # endif /* No winsock.h */ #endif @@ -78,7 +81,19 @@ static Key_schedule sched; #ifdef HAVE_GSSAPI -# include "xgssapi.h" +#ifdef HAVE_GSSAPI_H +#include <gssapi.h> +#endif +#ifdef HAVE_GSSAPI_GSSAPI_H +#include <gssapi/gssapi.h> +#endif +#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +#include <gssapi/gssapi_generic.h> +#endif + +#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif /* This is needed for GSSAPI encryption. */ static gss_ctx_id_t gcontext; @@ -86,7 +101,7 @@ static gss_ctx_id_t gcontext; static int connect_to_gserver PROTO((int, struct hostent *)); #endif /* HAVE_GSSAPI */ - + static void add_prune_candidate PROTO((char *)); /* All the commands. */ @@ -187,7 +202,7 @@ arg_should_not_be_sent_to_server (arg) 4) the argument lies within one of the paths in dirs_sent_to_server. - */ + 4) */ if (list_isempty (dirs_sent_to_server)) return 0; /* always send it */ @@ -252,8 +267,8 @@ arg_should_not_be_sent_to_server (arg) } /* Now check the value for root. */ - if (this_root && current_parsed_root - && (strcmp (this_root, current_parsed_root->original) != 0)) + if (CVSroot_cmdline == NULL && this_root && current_root + && (strcmp (this_root, current_root) != 0)) { /* Don't send this, since the CVSROOTs don't match. */ free (this_root); @@ -1266,32 +1281,6 @@ warning: server is not creating directories one at a time"); if ( CVS_CHDIR (dir_name) < 0) error (1, errno, "could not chdir to %s", dir_name); } - else if (!isdir (CVSADM)) - { - /* - * Put repository in CVS/Repository. For historical - * (pre-CVS/Root) reasons, this is an absolute pathname, - * but what really matters is the part of it which is - * relative to cvsroot. - */ - char *repo; - - if (reposdirname_absolute) - repo = reposdirname; - else - { - repo = xmalloc (strlen (reposdirname) - + strlen (toplevel_repos) - + 10); - strcpy (repo, toplevel_repos); - strcat (repo, "/"); - strcat (repo, reposdirname); - } - - Create_Admin (".", ".", repo, (char *)NULL, (char *)NULL, 0, 1, 1); - if (repo != reposdirname) - free (repo); - } if (strcmp (command_name, "export") != 0) { @@ -2297,7 +2286,7 @@ static int is_cvsroot_level (pathname) char *pathname; { - if (strcmp (toplevel_repos, current_parsed_root->directory) != 0) + if (strcmp (toplevel_repos, CVSroot_directory) != 0) return 0; return strchr (pathname, '/') == NULL; @@ -2937,14 +2926,14 @@ send_a_repository (dir, repository, update_dir) from REPOSITORY. If the path elements don't exist in REPOSITORY, or the removal of those path elements mean that we "step above" - current_parsed_root->directory, set toplevel_repos to - current_parsed_root->directory. */ + CVSroot_directory, set toplevel_repos to + CVSroot_directory. */ if ((repository_len > update_dir_len) && (strcmp (repository + repository_len - update_dir_len, update_dir) == 0) - /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */ + /* TOPLEVEL_REPOS shouldn't be above CVSroot_directory */ && ((repository_len - update_dir_len) - > strlen (current_parsed_root->directory))) + > strlen (CVSroot_directory))) { /* The repository name contains UPDATE_DIR. Set toplevel_repos to the repository name without @@ -2958,7 +2947,7 @@ send_a_repository (dir, repository, update_dir) } else { - toplevel_repos = xstrdup (current_parsed_root->directory); + toplevel_repos = xstrdup (CVSroot_directory); } } } @@ -3016,7 +3005,7 @@ client_expand_modules (argc, argv, local) for (i = 0; i < argc; ++i) send_arg (argv[i]); - send_a_repository ("", current_parsed_root->directory, ""); + send_a_repository ("", CVSroot_directory, ""); send_to_server ("expand-modules\012", 0); @@ -3054,13 +3043,13 @@ client_send_expansions (local, where, build_dirs) if (isfile (argv[0])) send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0); } - send_a_repository ("", current_parsed_root->directory, ""); + send_a_repository ("", CVSroot_directory, ""); } void client_nonexpanded_setup () { - send_a_repository ("", current_parsed_root->directory, ""); + send_a_repository ("", CVSroot_directory, ""); } /* Receive a cvswrappers line from the server; it must be a line @@ -3575,8 +3564,7 @@ get_responses_and_close () { if (shutdown (server_fd, 1) < 0) error (1, 0, "shutting down connection to %s: %s", - current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); - server_fd = -1; + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); /* * This test will always be true because we dup the descriptor */ @@ -3585,7 +3573,7 @@ get_responses_and_close () if (fclose (to_server_fp) != 0) error (1, errno, "closing down connection to %s", - current_parsed_root->hostname); + CVSroot_hostname); } } else @@ -3603,15 +3591,15 @@ get_responses_and_close () #endif /* START_RSH_WITH_POPEN_RW */ { error (1, errno, "closing connection to %s", - current_parsed_root->hostname); + CVSroot_hostname); } } if (! buf_empty_p (from_server) || getc (from_server_fp) != EOF) - error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname); + error (0, 0, "dying gasps from %s unexpected", CVSroot_hostname); else if (ferror (from_server_fp)) - error (0, errno, "reading from %s", current_parsed_root->hostname); + error (0, errno, "reading from %s", CVSroot_hostname); fclose (from_server_fp); #endif /* SHUTDOWN_SERVER */ @@ -3628,7 +3616,8 @@ get_responses_and_close () /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - sleep_past (last_register_time); + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return errs; @@ -3652,8 +3641,7 @@ supported_request (name) return 0; } - - + #if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) static struct hostent *init_sockaddr PROTO ((struct sockaddr_in *, char *, unsigned int)); @@ -3682,86 +3670,22 @@ init_sockaddr (name, hostname, port) #endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) */ - - #ifdef AUTH_CLIENT_SUPPORT -/* Generic function to do port number lookup tasks. - * - * In order of precedence, will return: - * getenv (envname), if defined - * getservbyname (portname), if defined - * defaultport - */ +static int auth_server_port_number PROTO ((void)); + static int -get_port_number (envname, portname, defaultport) - const char *envname; - const char *portname; - int defaultport; +auth_server_port_number () { - struct servent *s; - char *port_s; + struct servent *s = getservbyname ("cvspserver", "tcp"); - if (envname && (port_s = getenv (envname))) - { - int port = atoi (port_s); - if (port <= 0) - { - error (0, 0, "%s must be a positive integer! If you", envname); - error (0, 0, "are trying to force a connection via rsh, please"); - error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); - error (1, 0, "variable."); - } - return port; - } - else if (portname && (s = getservbyname (portname, "tcp"))) + if (s) return ntohs (s->s_port); else - return defaultport; + return CVS_AUTH_PORT; } - -/* get the port number for a client to connect to based on the port - * and method of a cvsroot_t. - * - * we do this here instead of in parse_cvsroot so that we can keep network - * code confined to a localized area and also to delay the lookup until the - * last possible moment so it remains possible to run cvs client commands that - * skip opening connections to the server (i.e. skip network operations entirely) - * - * and yes, I know none of the the commands do that now, but here's to planning - * for the future, eh? cheers. - * - * FIXME - We could cache the port lookup safely right now as we never change - * it for a single root on the fly, but we'd have to un'const some other - * functions - */ -int -get_cvs_port_number (root) - const cvsroot_t *root; -{ - - if (root->port) return root->port; - - switch (root->method) - { - case gserver_method: - case pserver_method: - return get_port_number ("CVS_CLIENT_PORT", "cvspserver", CVS_AUTH_PORT); -#ifdef HAVE_KERBEROS - case kserver_method: - return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT); -#endif - default: - error(1, EINVAL, "internal error: get_cvs_port_number called for invalid connection method (%s)", - method_names[root->method]); - break; - } -} - - - /* Read a line from socket SOCK. Result does not include the terminating linefeed. This is only used by the authentication protocol, which we call before we set up all the buffering stuff. @@ -3789,7 +3713,7 @@ recv_line (sock, resultp) int n; n = recv (sock, &ch, 1, 0); if (n <= 0) - error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, + error (1, 0, "recv() from server %s: %s", CVSroot_hostname, n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); if (ch == '\012') @@ -3827,15 +3751,11 @@ connect_to_forked_server (tofdp, fromfdp) command[0] = getenv ("CVS_SERVER"); if (! command[0]) - command[0] = program_path; + command[0] = "cvs"; command[1] = "server"; command[2] = NULL; - if (trace) - { - fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]); - } if (! piped_child (command, tofdp, fromfdp)) error (1, 0, "could not fork server process"); } @@ -3863,29 +3783,20 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) int tofd, fromfd; #endif int port_number; - char *username; /* the username we use to connect */ struct sockaddr_in client_sai; struct hostent *hostinfo; - char no_passwd = 0; /* gets set if no password found */ + char no_passwd = 0; /* gets set if no password found */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) { error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); } - port_number = get_cvs_port_number (current_parsed_root); - hostinfo = init_sockaddr (&client_sai, current_parsed_root->hostname, port_number); - if (trace) - { - fprintf (stderr, " -> Connecting to %s(%s):%d\n", - current_parsed_root->hostname, - inet_ntoa (client_sai.sin_addr), port_number); - } + port_number = auth_server_port_number (); + hostinfo = init_sockaddr (&client_sai, CVSroot_hostname, port_number); if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) < 0) - error (1, 0, "connect to %s(%s):%d failed: %s", - current_parsed_root->hostname, - inet_ntoa (client_sai.sin_addr), + error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, port_number, SOCK_STRERROR (SOCK_ERRNO)); /* Run the authorization mini-protocol before anything else. */ @@ -3893,12 +3804,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) { #ifdef HAVE_GSSAPI if (! connect_to_gserver (sock, hostinfo)) - { - error (0, 0, - "authorization failed: server %s rejected access to %s", - current_parsed_root->hostname, current_parsed_root->directory); goto rejected; - } #else error (1, 0, "This client does not support GSSAPI authentication"); #endif @@ -3906,9 +3812,11 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) else { char *begin = NULL; + char *repository = CVSroot_directory; + char *username = CVSroot_username; char *password = NULL; char *end = NULL; - + if (verify_only) { begin = "BEGIN VERIFICATION REQUEST\012"; @@ -3922,8 +3830,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) /* Get the password, probably from ~/.cvspass. */ password = get_cvs_password (); - username = current_parsed_root->username ? current_parsed_root->username : getcaller(); - + /* Send the empty string by default. This is so anonymous CVS access doesn't require client to have done "cvs login". */ if (password == NULL) @@ -3937,7 +3844,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); /* Send the data the server needs. */ - if (send (sock, current_parsed_root->directory, strlen (current_parsed_root->directory), 0) < 0) + if (send (sock, repository, strlen (repository), 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); if (send (sock, "\012", 1, 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); @@ -3968,29 +3875,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (strcmp (read_buf, "I HATE YOU") == 0) { - /* Authorization not granted. - * - * This is a little confusing since we can reach this while loop in GSSAPI - * mode, but if GSSAPI authentication failed, we already jumped to the - * rejected label (there is no case where the connect_to_gserver function - * can return 1 and we will not receive "I LOVE YOU" from the server, barring - * broken connections and garbled messages, of course). - * - * i.e. This is a pserver specific error message and shoiuld be since - * GSSAPI doesn't use username. - */ - error (0, 0, - "authorization failed: server %s rejected access to %s for user %s", - current_parsed_root->hostname, current_parsed_root->directory, username); - - /* Output a special error message if authentication was attempted - with no password -- the user should be made aware that they may - have missed a step. */ - if (no_passwd) - { - error (0, 0, - "used empty password; try \"cvs login\" with a real password"); - } + /* Authorization not granted. */ goto rejected; } else if (strncmp (read_buf, "E ", 2) == 0) @@ -4028,15 +3913,15 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) { error (0, 0, "unrecognized auth response from %s: %s", - current_parsed_root->hostname, read_buf); + CVSroot_hostname, read_buf); error (1, 0, "shutdown() failed, server %s: %s", - current_parsed_root->hostname, + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); } error (1, 0, "unrecognized auth response from %s: %s", - current_parsed_root->hostname, read_buf); + CVSroot_hostname, read_buf); } free (read_buf); } @@ -4045,7 +3930,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (verify_only) { if (shutdown (sock, 2) < 0) - error (0, 0, "shutdown() failed, server %s: %s", current_parsed_root->hostname, + error (0, 0, "shutdown() failed, server %s: %s", CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); return; } @@ -4070,11 +3955,24 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) return; rejected: + error (0, 0, + "authorization failed: server %s rejected access to %s for user %s", + CVSroot_hostname, CVSroot_directory, CVSroot_username); + + /* Output a special error message if authentication was attempted + with no password -- the user should be made aware that they may + have missed a step. */ + if (no_passwd) + { + error (0, 0, + "used empty password; try \"cvs login\" with a real password"); + } + if (shutdown (sock, 2) < 0) { error (0, 0, "shutdown() failed (server %s): %s", - current_parsed_root->hostname, + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); } @@ -4082,9 +3980,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) } #endif /* AUTH_CLIENT_SUPPORT */ - - -#ifdef HAVE_KERBEROS + +#if HAVE_KERBEROS /* This function has not been changed to deal with NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted to file @@ -4106,26 +4003,42 @@ start_tcp_server (tofdp, fromfdp) if (s < 0) error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - port = get_cvs_port_number (current_parsed_root); + /* Get CVS_CLIENT_PORT or look up cvs/tcp with CVS_PORT as default */ + portenv = getenv ("CVS_CLIENT_PORT"); + if (portenv != NULL) + { + port = atoi (portenv); + if (port <= 0) + { + error (0, 0, "CVS_CLIENT_PORT must be a positive number! If you"); + error (0, 0, "are trying to force a connection via rsh, please"); + error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); + error (1, 0, "variable."); + } + if (trace) + fprintf(stderr, "Using TCP port %d to contact server.\n", port); + } + else + { + struct servent *sp; + + sp = getservbyname ("cvs", "tcp"); + if (sp == NULL) + port = CVS_PORT; + else + port = ntohs (sp->s_port); + } - hp = init_sockaddr (&sin, current_parsed_root->hostname, port); + hp = init_sockaddr (&sin, CVSroot_hostname, port); hname = xmalloc (strlen (hp->h_name) + 1); strcpy (hname, hp->h_name); - if (trace) - { - fprintf (stderr, " -> Connecting to %s(%s):%d\n", - current_parsed_root->hostname, - inet_ntoa (client_sai.sin_addr), port); - } - if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) - error (1, 0, "connect to %s(%s):%d failed: %s", - current_parsed_root->hostname, - inet_ntoa (client_sai.sin_addr), + error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, port, SOCK_STRERROR (SOCK_ERRNO)); +#ifdef HAVE_KERBEROS { const char *realm; struct sockaddr_in laddr; @@ -4150,6 +4063,7 @@ start_tcp_server (tofdp, fromfdp) krb_get_err_text (status)); memcpy (kblock, cred.session, sizeof (C_Block)); } +#endif /* HAVE_KERBEROS */ server_fd = s; close_on_exec (server_fd); @@ -4178,10 +4092,9 @@ recv_bytes (sock, buf, need) int got; got = recv (sock, buf, need, 0); - if (got <= 0) - error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, - got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); - + if (got < 0) + error (1, 0, "recv() from server %s: %s", CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); buf += got; need -= got; } @@ -4274,11 +4187,11 @@ connect_to_gserver (sock, hostinfo) got = recv (sock, buf + 2, sizeof buf - 2, 0); if (got < 0) error (1, 0, "recv() from server %s: %s", - current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); buf[got + 2] = '\0'; if (buf[got + 1] == '\n') buf[got + 1] = '\0'; - error (1, 0, "error from server %s: %s", current_parsed_root->hostname, + error (1, 0, "error from server %s: %s", CVSroot_hostname, buf); } @@ -4330,7 +4243,7 @@ start_server () (*really* slow on a 14.4kbps link); the clean way to have a CVS which supports several ways of connecting is with access methods. */ - switch (current_parsed_root->method) + switch (CVSroot_method) { #ifdef AUTH_CLIENT_SUPPORT @@ -4347,7 +4260,7 @@ start_server () break; #endif -#ifdef HAVE_GSSAPI +#if HAVE_GSSAPI case gserver_method: /* GSSAPI authentication is handled by the pserver. */ connect_to_pserver (&tofd, &fromfd, 0, 1); @@ -4366,8 +4279,8 @@ start_server () case server_method: #if defined(START_SERVER) START_SERVER (&tofd, &fromfd, getcaller (), - current_parsed_root->username, current_parsed_root->hostname, - current_parsed_root->directory); + CVSroot_username, CVSroot_hostname, + CVSroot_directory); # if defined (START_SERVER_RETURNS_SOCKET) && defined (NO_SOCKET_TO_FD) /* This is a system on which we can only write to a socket using send/recv. Therefore its START_SERVER needs to @@ -4498,7 +4411,7 @@ the :server: access method is not supported by this port of CVS"); if (!rootless) { send_to_server ("Root ", 0); - send_to_server (current_parsed_root->directory, 0); + send_to_server (CVSroot_directory, 0); send_to_server ("\012", 1); } @@ -4628,7 +4541,7 @@ the :server: access method is not supported by this port of CVS"); on encryption, bomb out; don't let the user think the data is being encrypted when it is not. */ #ifdef HAVE_KERBEROS - if (current_parsed_root->method == kserver_method) + if (CVSroot_method == kserver_method) { if (! supported_request ("Kerberos-encrypt")) error (1, 0, "This server does not support encryption"); @@ -4643,7 +4556,7 @@ the :server: access method is not supported by this port of CVS"); else #endif /* HAVE_KERBEROS */ #ifdef HAVE_GSSAPI - if (current_parsed_root->method == gserver_method) + if (CVSroot_method == gserver_method) { if (! supported_request ("Gssapi-encrypt")) error (1, 0, "This server does not support encryption"); @@ -4716,7 +4629,7 @@ the :server: access method is not supported by this port of CVS"); ability to decrypt the data stream is itself a form of authentication. */ #ifdef HAVE_GSSAPI - if (current_parsed_root->method == gserver_method) + if (CVSroot_method == gserver_method) { if (! supported_request ("Gssapi-authenticate")) error (1, 0, @@ -4807,7 +4720,7 @@ start_rsh_server (tofdp, fromfdp) example in CVS_RSH or other such mechanisms to be devised, if that is what they want (the manual already tells them that). */ - cvs_rsh = "rsh"; + cvs_rsh = "ssh"; if (!cvs_server) cvs_server = "cvs"; @@ -4820,13 +4733,13 @@ start_rsh_server (tofdp, fromfdp) #endif /* RSH_NEEDS_BINARY_FLAG */ /* Then we strcat more things on the end one by one. */ - if (current_parsed_root->username != NULL) + if (CVSroot_username != NULL) { rsh_argv[i++] = "-l"; - rsh_argv[i++] = current_parsed_root->username; + rsh_argv[i++] = CVSroot_username; } - rsh_argv[i++] = current_parsed_root->hostname; + rsh_argv[i++] = CVSroot_hostname; rsh_argv[i++] = cvs_server; rsh_argv[i++] = "server"; @@ -4836,8 +4749,6 @@ start_rsh_server (tofdp, fromfdp) if (trace) { fprintf (stderr, " -> Starting server: "); - for (i = 0; rsh_argv[i]; i++) - fprintf (stderr, "%s ", rsh_argv[i]); putc ('\n', stderr); } @@ -4866,7 +4777,7 @@ start_rsh_server (tofdp, fromfdp) char *command; if (!cvs_rsh) - cvs_rsh = "rsh"; + cvs_rsh = "ssh"; if (!cvs_server) cvs_server = "cvs"; @@ -4875,7 +4786,7 @@ start_rsh_server (tofdp, fromfdp) versions of rsh that grab switches out of the middle of the command (they're calling the GNU getopt routines incorrectly). */ command = xmalloc (strlen (cvs_server) - + strlen (current_parsed_root->directory) + + strlen (CVSroot_directory) + 50); /* If you are running a very old (Nov 3, 1994, before 1.5) @@ -4889,15 +4800,15 @@ start_rsh_server (tofdp, fromfdp) char **p = argv; *p++ = cvs_rsh; - *p++ = current_parsed_root->hostname; + *p++ = CVSroot_hostname; /* If the login names differ between client and server * pass it on to rsh. */ - if (current_parsed_root->username != NULL) + if (CVSroot_username != NULL) { *p++ = "-l"; - *p++ = current_parsed_root->username; + *p++ = CVSroot_username; } *p++ = command; @@ -5624,7 +5535,7 @@ send_files (argc, argv, local, aflag, flags) * latter case; I don't think toplevel_repos matters for the * former. */ - toplevel_repos = xstrdup (current_parsed_root->directory); + toplevel_repos = xstrdup (CVSroot_directory); send_repository ("", toplevel_repos, "."); } @@ -5743,7 +5654,7 @@ client_import_done () */ /* FIXME: "can't happen" now that we call client_import_setup at the beginning. */ - toplevel_repos = xstrdup (current_parsed_root->directory); + toplevel_repos = xstrdup (CVSroot_directory); send_repository ("", toplevel_repos, "."); } @@ -5923,9 +5834,9 @@ client_senddate (date) void send_init_command () { - /* This is here because we need the current_parsed_root->directory variable. */ + /* This is here because we need the CVSroot_directory variable. */ send_to_server ("init ", 0); - send_to_server (current_parsed_root->directory, 0); + send_to_server (CVSroot_directory, 0); send_to_server ("\012", 0); } diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c index 149da7c..3d46e25 100644 --- a/contrib/cvs/src/commit.c +++ b/contrib/cvs/src/commit.c @@ -12,6 +12,7 @@ * * The call is: cvs commit [options] files... * + * $FreeBSD$ */ #include <assert.h> @@ -85,13 +86,13 @@ static time_t last_register_time; static const char *const commit_usage[] = { "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n", - " -n Do not run the module program (if any).\n", - " -R Process directories recursively.\n", - " -l Local directory only (not recursive).\n", - " -f Force the file to be committed; disables recursion.\n", - " -F logfile Read the log message from file.\n", - " -m msg Log message.\n", - " -r rev Commit to this branch or trunk revision.\n", + "\t-n\tDo not run the module program (if any).\n", + "\t-R\tProcess directories recursively.\n", + "\t-l\tLocal directory only (not recursive).\n", + "\t-f\tForce the file to be committed; disables recursion.\n", + "\t-F file\tRead the log message from file.\n", + "\t-m msg\tLog message.\n", + "\t-r rev\tCommit to this branch or trunk revision.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -344,7 +345,7 @@ commit (argc, argv) if (geteuid () == (uid_t) 0 # ifdef CLIENT_SUPPORT /* Who we are on the client side doesn't affect logging. */ - && !current_parsed_root->isremote + && !client_active # endif ) { @@ -432,7 +433,7 @@ commit (argc, argv) } #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) { struct find_data find_args; @@ -498,7 +499,7 @@ commit (argc, argv) /* Run the user-defined script to verify/check information in *the log message */ - do_verify (saved_message, (char *)NULL); + do_verify (&saved_message, (char *)NULL); /* We always send some sort of message, even if empty. */ /* FIXME: is that true? There seems to be some code in do_editor @@ -591,7 +592,8 @@ commit (argc, argv) char *fname; FILE *fp; - fp = cvs_temp_file (&fname); + fname = cvs_temp_name (); + fp = CVS_FOPEN (fname, "w+"); if (fp == NULL) error (1, 0, "cannot create temporary file %s", fname); if (fwrite (saved_message, 1, strlen (saved_message), fp) @@ -600,7 +602,6 @@ commit (argc, argv) if (fclose (fp) < 0) error (0, errno, "cannot close temporary file %s", fname); error (0, 0, "saving log message in %s", fname); - free (fname); } return err; } @@ -615,7 +616,7 @@ commit (argc, argv) wrap_setup (); - lock_tree_for_write (argc, argv, local, W_LOCAL, aflag); + lock_tree_for_write (argc, argv, local, aflag); /* * Set up the master update list and hard link list @@ -663,15 +664,11 @@ commit (argc, argv) Lock_Cleanup (); dellist (&mulist); -#ifdef SERVER_SUPPORT - if (server_active) - return err; -#endif - /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - sleep_past (last_register_time); + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return (err); @@ -782,7 +779,7 @@ check_fileproc (callerdat, finfo) struct commit_info *ci; struct logfile_info *li; - size_t cvsroot_len = strlen (current_parsed_root->directory); + size_t cvsroot_len = strlen (CVSroot_directory); if (!finfo->repository) { @@ -790,7 +787,7 @@ check_fileproc (callerdat, finfo) return (1); } - if (strncmp (finfo->repository, current_parsed_root->directory, cvsroot_len) == 0 + if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0 && ISDIRSEP (finfo->repository[cvsroot_len]) && strncmp (finfo->repository + cvsroot_len + 1, CVSROOTADM, @@ -814,7 +811,9 @@ check_fileproc (callerdat, finfo) switch (status) { case T_CHECKOUT: +#ifdef SERVER_SUPPORT case T_PATCH: +#endif case T_NEEDS_MERGE: case T_CONFLICT: case T_REMOVE_ENTRY: @@ -831,7 +830,7 @@ check_fileproc (callerdat, finfo) * Also, * - if status is T_REMOVED, can't have a numeric tag * - if status is T_ADDED, rcs file must not exist unless on - * a branch or head is dead + * a branch * - if status is T_ADDED, can't have a non-trunk numeric rev * - if status is T_MODIFIED and a Conflict marker exists, don't * allow the commit if timestamp is identical or if we find @@ -928,17 +927,29 @@ warning: file `%s' seems to still contain conflict indicators", { if (vers->tag == NULL) { - if (finfo->rcs != NULL && - !RCS_isdead (finfo->rcs, finfo->rcs->head)) + char *rcs; + + rcs = xmalloc (strlen (finfo->repository) + + strlen (finfo->file) + + sizeof RCSEXT + + 5); + + /* Don't look in the attic; if it exists there we + will move it back out in checkaddfile. */ + sprintf(rcs, "%s/%s%s", finfo->repository, finfo->file, + RCSEXT); + if (isreadable (rcs)) { error (0, 0, "cannot add file `%s' when RCS file `%s' already exists", - finfo->fullname, finfo->rcs->path); + finfo->fullname, rcs); freevers_ts (&vers); + free (rcs); return (1); } + free (rcs); } - else if (isdigit ((unsigned char) *vers->tag) && + if (vers->tag && isdigit ((unsigned char) *vers->tag) && numdots (vers->tag) > 1) { error (0, 0, @@ -1230,7 +1241,7 @@ commit_fileproc (callerdat, finfo) if (use_editor) do_editor (finfo->update_dir, &saved_message, finfo->repository, ulist); - do_verify (saved_message, finfo->repository); + do_verify (&saved_message, finfo->repository); } p = findnode (cilist, finfo->file); @@ -1301,12 +1312,6 @@ commit_fileproc (callerdat, finfo) /* find the max major rev number in this directory */ maxrev = 0; (void) walklist (finfo->entries, findmaxrev, NULL); - if (finfo->rcs->head) { - /* resurrecting: include dead revision */ - int thisrev = atoi (finfo->rcs->head); - if (thisrev > maxrev) - maxrev = thisrev; - } if (maxrev == 0) maxrev = 1; xrev = xmalloc (20); @@ -1426,12 +1431,12 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) { char *p; - if (strncmp (current_parsed_root->directory, repository, - strlen (current_parsed_root->directory)) != 0) + if (strncmp (CVSroot_directory, repository, + strlen (CVSroot_directory)) != 0) error (0, 0, "internal error: repository (%s) doesn't begin with root (%s)", - repository, current_parsed_root->directory); - p = repository + strlen (current_parsed_root->directory); + repository, CVSroot_directory); + p = repository + strlen (CVSroot_directory); if (*p == '/') ++p; if (strcmp ("CVSROOT", p) == 0 @@ -1552,7 +1557,7 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries) got_message = 1; if (use_editor) do_editor (update_dir, &saved_message, real_repos, ulist); - do_verify (saved_message, real_repos); + do_verify (&saved_message, real_repos); free (real_repos); return (R_PROCESS); } @@ -1592,13 +1597,19 @@ findmaxrev (p, closure) Node *p; void *closure; { + char *cp; int thisrev; Entnode *entdata; entdata = (Entnode *) p->data; if (entdata->type != ENT_FILE) return (0); + cp = strchr (entdata->version, '.'); + if (cp != NULL) + *cp = '\0'; thisrev = atoi (entdata->version); + if (cp != NULL) + *cp = '.'; if (thisrev > maxrev) maxrev = thisrev; return (0); @@ -1946,8 +1957,10 @@ checkaddfile (file, repository, tag, options, rcsnode) Attic. */ if (!(rcsfile->flags & INATTIC)) { - error (0, 0, "warning: expected %s to be in Attic", + error (0, 0, "internal error: confused about attic for %s", rcsfile->path); + retval = 1; + goto out; } sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); @@ -2134,6 +2147,8 @@ checkaddfile (file, repository, tag, options, rcsnode) char *head; char *magicrev; + fixbranch(rcsfile, sbranch); + head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL); magicrev = RCS_magicrev (rcsfile, head); diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h index b4e3fa1..6489f07 100644 --- a/contrib/cvs/src/cvs.h +++ b/contrib/cvs/src/cvs.h @@ -9,6 +9,7 @@ /* * basic information used in all source files * + * $FreeBSD$ */ @@ -187,6 +188,7 @@ extern int errno; #define CVSROOTADM_WRITERS "writers" #define CVSROOTADM_PASSWD "passwd" #define CVSROOTADM_CONFIG "config" +#define CVSROOTADM_OPTIONS "options" #define CVSNULLREPOS "Emptydir" /* an empty directory */ @@ -256,6 +258,8 @@ extern int errno; #define CVSREAD_ENV "CVSREAD" /* make files read-only */ #define CVSREAD_DFLT 0 /* writable files by default */ +#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */ + #define TMPDIR_ENV "TMPDIR" /* Temporary directory */ /* #define TMPDIR_DFLT Set by options.h */ @@ -314,7 +318,7 @@ typedef struct entnode Entnode; /* The type of request that is being done in do_module() */ enum mtype { - CHECKOUT, TAG, PATCH, EXPORT, MISC + CHECKOUT, TAG, PATCH, EXPORT }; /* @@ -363,44 +367,41 @@ extern int really_quiet, quiet; extern int use_editor; extern int cvswrite; extern mode_t cvsumask; +extern char *RCS_citag; /* Access method specified in CVSroot. */ typedef enum { - null_method, local_method, server_method, pserver_method, kserver_method, gserver_method, + local_method, server_method, pserver_method, kserver_method, gserver_method, ext_method, fork_method } CVSmethod; extern char *method_names[]; /* change this in root.c if you change the enum above */ -typedef struct cvsroot_s { - char *original; /* the complete source CVSroot string */ - CVSmethod method; /* one of the enum values above */ - char *username; /* the username or NULL if method == local */ - char *password; /* the username or NULL if method == local */ - char *hostname; /* the hostname or NULL if method == local */ - int port; /* the port or zero if method == local */ - char *directory; /* the directory name */ -#ifdef CLIENT_SUPPORT - unsigned char isremote; /* nonzero if we are doing remote access */ -#endif /* CLIENT_SUPPORT */ -} cvsroot_t; - /* This global variable holds the global -d option. It is NULL if -d was not used, which means that we must get the CVSroot information from the CVSROOT environment variable or from a CVS/Root file. */ extern char *CVSroot_cmdline; +extern char *CVSroot_original; /* the active, complete CVSroot string */ +extern int client_active; /* nonzero if we are doing remote access */ +extern CVSmethod CVSroot_method; /* one of the enum values above */ +extern char *CVSroot_username; /* the username or NULL if method == local */ +extern char *CVSroot_hostname; /* the hostname or NULL if method == local */ +extern char *CVSroot_directory; /* the directory name */ + /* These variables keep track of all of the CVSROOT directories that have been seen by the client and the current one of those selected. */ extern List *root_directories; -extern cvsroot_t *current_parsed_root; +extern char *current_root; extern char *emptydir_name PROTO ((void)); extern int safe_location PROTO ((void)); extern int trace; /* Show all commands */ extern int noexec; /* Don't modify disk anywhere */ +extern int readonlyfs; /* fail on all write locks; succeed all read locks */ extern int logoff; /* Don't write history entry */ +extern int require_real_user; /* skip CVSROOT/passwd, /etc/passwd users only*/ extern int top_level_admin; @@ -428,9 +429,8 @@ extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile, char *rev1, char *rev2, char *label1, char *label2, char *workfile)); -extern int diff_exec PROTO ((char *file1, char *file2, - char *label1, char *label2, - char *options, char *out)); +extern int diff_exec PROTO ((char *file1, char *file2, char *options, + char *out)); extern int diff_execv PROTO ((char *file1, char *file2, char *label1, char *label2, char *options, char *out)); @@ -450,18 +450,15 @@ void Subdir_Deregister PROTO((List *, const char *, const char *)); char *Make_Date PROTO((char *rawdate)); char *date_from_time_t PROTO ((time_t)); -void date_to_internet PROTO ((char *, const char *)); -void date_to_tm PROTO ((struct tm *, const char *)); -void tm_to_internet PROTO ((char *, const struct tm *)); +void date_to_internet PROTO ((char *, char *)); char *Name_Repository PROTO((char *dir, char *update_dir)); char *Short_Repository PROTO((char *repository)); void Sanitize_Repository_Name PROTO((char *repository)); char *Name_Root PROTO((char *dir, char *update_dir)); -void free_cvsroot_t PROTO((cvsroot_t *root_in)); -cvsroot_t *parse_cvsroot PROTO((char *root)); -cvsroot_t *local_cvsroot PROTO((char *dir)); +int parse_cvsroot PROTO((char *CVSroot)); +void set_local_cvsroot PROTO((char *dir)); void Create_Root PROTO((char *dir, char *rootdir)); void root_allow_add PROTO ((char *)); void root_allow_free PROTO ((void)); @@ -475,7 +472,6 @@ char *time_stamp PROTO((char *file)); void *xmalloc PROTO((size_t bytes)); void *xrealloc PROTO((void *ptr, size_t bytes)); void expand_string PROTO ((char **, size_t *, size_t)); -void allocate_and_strcat PROTO ((char **, size_t *, const char *)); char *xstrdup PROTO((const char *str)); void strip_trailing_newlines PROTO((char *str)); int pathname_levels PROTO ((char *path)); @@ -498,7 +494,7 @@ char *xreadlink PROTO((const char *link)); char *last_component PROTO((char *path)); char *get_homedir PROTO ((void)); char *cvs_temp_name PROTO ((void)); -FILE *cvs_temp_file PROTO ((char **filename)); +void parseopts PROTO ((const char *root)); int numdots PROTO((const char *s)); char *increment_revnum PROTO ((const char *)); @@ -522,8 +518,7 @@ void Lock_Cleanup PROTO((void)); /* Writelock an entire subtree, well the part specified by ARGC, ARGV, LOCAL, and AFLAG, anyway. */ -void lock_tree_for_write PROTO ((int argc, char **argv, int local, int which, - int aflag)); +void lock_tree_for_write PROTO ((int argc, char **argv, int local, int aflag)); /* See lock.c for description. */ extern void lock_dir_for_write PROTO ((char *)); @@ -560,6 +555,7 @@ void make_directories PROTO((const char *name)); void make_directory PROTO((const char *name)); extern int mkdir_if_needed PROTO ((char *name)); void rename_file PROTO((const char *from, const char *to)); +char *backup_file PROTO((const char *file, const char *suffix)); /* Expand wildcards in each element of (ARGC,ARGV). This is according to the files which exist in the current directory, and accordingly to OS-specific conventions regarding wildcard syntax. It might be desirable to change the @@ -589,7 +585,7 @@ void Update_Logfile PROTO((char *repository, char *xmessage, FILE * xlogfp, void do_editor PROTO((char *dir, char **messagep, char *repository, List * changes)); -void do_verify PROTO((char *message, char *repository)); +void do_verify PROTO((char **messagep, char *repository)); typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where, char *mwhere, char *mfile, int shorten, int local_specified, @@ -639,8 +635,7 @@ extern int init PROTO ((int argc, char **argv)); int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg, CALLBACKPROC callback_proc, char *where, int shorten, - int local_specified, int run_module_prog, int build_dirs, - char *extra_arg)); + int local_specified, int run_module_prog, char *extra_arg)); void history_write PROTO((int type, char *update_dir, char *revs, char *name, char *repository)); int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, @@ -658,10 +653,7 @@ char *make_message_rcslegal PROTO((char *message)); extern int file_has_markers PROTO ((const struct file_info *)); extern void get_file PROTO ((const char *, const char *, const char *, char **, size_t *, size_t *)); -extern char *shell_escape PROTO((char *buf, const char *str)); -char *backup_file PROTO((const char *file, const char *suffix)); extern void resolve_symlink PROTO ((char **filename)); -void sleep_past PROTO ((time_t desttime)); /* flags for run_exec(), the fast system() for CVS */ #define RUN_NORMAL 0x0000 /* no special behaviour */ @@ -791,7 +783,9 @@ enum classify_type T_REMOVED, /* R (removed file) list */ T_REMOVE_ENTRY, /* W (removed entry) list */ T_UPTODATE, /* File is up-to-date */ +#ifdef SERVER_SUPPORT T_PATCH, /* P Like C, but can patch */ +#endif T_TITLE /* title for node type */ }; typedef enum classify_type Ctype; @@ -881,8 +875,6 @@ char *descramble PROTO ((char *str)); #ifdef AUTH_CLIENT_SUPPORT char *get_cvs_password PROTO((void)); -int get_cvs_port_number PROTO((const cvsroot_t *root)); -char *normalize_cvsroot PROTO((const cvsroot_t *root)); #endif /* AUTH_CLIENT_SUPPORT */ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *)); diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c index 9732f5d..15353e63 100644 --- a/contrib/cvs/src/diff.c +++ b/contrib/cvs/src/diff.c @@ -12,6 +12,8 @@ * * Without any file arguments, runs diff against all the currently modified * files. + * + * $FreeBSD$ */ #include "cvs.h" @@ -117,7 +119,7 @@ static struct option const longopts[] = {"ignore-matching-lines", 1, 0, 'I'}, {"label", 1, 0, 'L'}, {"new-file", 0, 0, 'N'}, - {"initial-tab", 0, 0, 'T'}, + {"initial-tab", 0, 0, 148}, {"width", 1, 0, 'W'}, {"text", 0, 0, 'a'}, {"ignore-space-change", 0, 0, 'b'}, @@ -138,7 +140,7 @@ static struct option const longopts[] = {"report-identical-files", 0, 0, 's'}, {"expand-tabs", 0, 0, 't'}, {"ignore-all-space", 0, 0, 'w'}, - {"side-by-side", 0, 0, 'y'}, + {"side-by-side", 0, 0, 147}, {"unified", 2, 0, 146}, {"left-column", 0, 0, 129}, {"suppress-common-lines", 0, 0, 130}, @@ -186,6 +188,28 @@ static struct option const longopts[] = mostly to ignore -q. Maybe this should be fixed, but I think it's a larger issue than the changes included here. */ +static void strcat_and_allocate PROTO ((char **, size_t *, const char *)); + +/* *STR is a pointer to a malloc'd string. *LENP is its allocated + length. Add SRC to the end of it, reallocating if necessary. */ +static void +strcat_and_allocate (str, lenp, src) + char **str; + size_t *lenp; + const char *src; +{ + size_t new_size; + + new_size = strlen (*str) + strlen (src) + 1; + if (*str == NULL || new_size >= *lenp) + { + while (new_size >= *lenp) + *lenp *= 2; + *str = xrealloc (*str, *lenp); + } + strcat (*str, src); +} + int diff (argc, argv) int argc; @@ -224,19 +248,18 @@ diff (argc, argv) optind = 0; while ((c = getopt_long (argc, argv, - "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:", + "+abcdefhilnpstuw0123456789BHNRC:D:F:I:L:U:V:W:k:r:", longopts, &option_index)) != -1) { switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'i': case 'n': case 'p': case 's': case 't': - case 'u': case 'w': case 'y': - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case 'B': case 'H': case 'T': + case 'u': case 'w': case '0': case '1': case '2': + case '3': case '4': case '5': case '6': case '7': case '8': + case '9': case 'B': case 'H': (void) sprintf (tmp, " -%c", (char) c); - allocate_and_strcat (&opts, &opts_allocated, tmp); + strcat_and_allocate (&opts, &opts_allocated, tmp); break; case 'L': if (have_rev1_label++) @@ -246,31 +269,32 @@ diff (argc, argv) break; } - allocate_and_strcat (&opts, &opts_allocated, " -L"); - allocate_and_strcat (&opts, &opts_allocated, optarg); + strcat_and_allocate (&opts, &opts_allocated, " -L"); + strcat_and_allocate (&opts, &opts_allocated, optarg); break; case 'C': case 'F': case 'I': case 'U': case 'V': case 'W': (void) sprintf (tmp, " -%c", (char) c); - allocate_and_strcat (&opts, &opts_allocated, tmp); - allocate_and_strcat (&opts, &opts_allocated, optarg); + strcat_and_allocate (&opts, &opts_allocated, tmp); + strcat_and_allocate (&opts, &opts_allocated, optarg); break; case 131: /* --ifdef. */ - allocate_and_strcat (&opts, &opts_allocated, " --ifdef="); - allocate_and_strcat (&opts, &opts_allocated, optarg); + strcat_and_allocate (&opts, &opts_allocated, " --ifdef="); + strcat_and_allocate (&opts, &opts_allocated, optarg); break; case 129: case 130: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: - allocate_and_strcat (&opts, &opts_allocated, " --"); - allocate_and_strcat (&opts, &opts_allocated, + case 147: case 148: + strcat_and_allocate (&opts, &opts_allocated, " --"); + strcat_and_allocate (&opts, &opts_allocated, longopts[option_index].name); if (longopts[option_index].has_arg == 1 || (longopts[option_index].has_arg == 2 && optarg != NULL)) { - allocate_and_strcat (&opts, &opts_allocated, "="); - allocate_and_strcat (&opts, &opts_allocated, optarg); + strcat_and_allocate (&opts, &opts_allocated, "="); + strcat_and_allocate (&opts, &opts_allocated, optarg); } break; case 'R': @@ -319,7 +343,7 @@ diff (argc, argv) options = xstrdup (""); #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) { + if (client_active) { /* We're the client side. Fire up the remote server. */ start_server (); @@ -400,8 +424,6 @@ diff_fileproc (callerdat, finfo) char *tmp; char *tocvsPath; char *fname; - char *label1; - char *label2; /* Initialize these solely to avoid warnings from gcc -Wall about variables that might be used uninitialized. */ @@ -437,7 +459,8 @@ diff_fileproc (callerdat, finfo) (vers->vn_rcs == NULL ? NULL : RCS_branch_head (vers->srcfile, vers->vn_rcs)); - exists = head != NULL; + exists = (head != NULL + && !RCS_isdead (vers->srcfile, head)); if (head != NULL) free (head); } @@ -447,7 +470,8 @@ diff_fileproc (callerdat, finfo) xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0); - exists = xvers->vn_rcs != NULL; + exists = (xvers->vn_rcs != NULL + && !RCS_isdead (xvers->srcfile, xvers->vn_rcs)); freevers_ts (&xvers); } if (exists) @@ -612,53 +636,24 @@ diff_fileproc (callerdat, finfo) copy_file (tocvsPath, finfo->file); } - /* Set up file labels appropriate for compatibility with the Larry Wall - * implementation of patch if the user didn't specify. This is irrelevant - * according to the POSIX.2 specification. - */ - label1 = NULL; - label2 = NULL; - if (!have_rev1_label) - { - if (empty_file == DIFF_ADDED) - label1 = - make_file_label (DEVNULL, NULL, NULL); - else - label1 = - make_file_label (finfo->fullname, use_rev1, vers ? vers->srcfile : NULL); - } - - if (!have_rev2_label) - { - if (empty_file == DIFF_REMOVED) - label2 = - make_file_label (DEVNULL, NULL, NULL); - else - label2 = - make_file_label (finfo->fullname, use_rev2, vers ? vers->srcfile : NULL); - } - if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED) { - /* This is fullname, not file, possibly despite the POSIX.2 - * specification, because that's the way all the Larry Wall - * implementations of patch (are there other implementations?) want - * things and the POSIX.2 spec appears to leave room for this. - */ + /* This is file, not fullname, because it is the "Index:" line which + is supposed to contain the directory. */ cvs_output ("\ ===================================================================\n\ RCS file: ", 0); - cvs_output (finfo->fullname, 0); + cvs_output (finfo->file, 0); cvs_output ("\n", 1); cvs_output ("diff -N ", 0); - cvs_output (finfo->fullname, 0); + cvs_output (finfo->file, 0); cvs_output ("\n", 1); if (empty_file == DIFF_ADDED) { if (use_rev2 == NULL) - status = diff_exec (DEVNULL, finfo->file, label1, label2, opts, RUN_TTY); + status = diff_exec (DEVNULL, finfo->file, opts, RUN_TTY); else { int retcode; @@ -677,7 +672,7 @@ RCS file: ", 0); return err; } - status = diff_exec (DEVNULL, tmp, label1, label2, opts, RUN_TTY); + status = diff_exec (DEVNULL, tmp, opts, RUN_TTY); } } else @@ -696,11 +691,22 @@ RCS file: ", 0); return err; } - status = diff_exec (tmp, DEVNULL, label1, label2, opts, RUN_TTY); + status = diff_exec (tmp, DEVNULL, opts, RUN_TTY); } } else { + char *label1 = NULL; + char *label2 = NULL; + + if (!have_rev1_label) + label1 = + make_file_label (finfo->fullname, use_rev1, vers->srcfile); + + if (!have_rev2_label) + label2 = + make_file_label (finfo->fullname, use_rev2, vers->srcfile); + status = RCS_exec_rcsdiff (vers->srcfile, opts, *options ? options : vers->options, use_rev1, use_rev2, diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c index 28575a3..2cccbcd 100644 --- a/contrib/cvs/src/filesubr.c +++ b/contrib/cvs/src/filesubr.c @@ -17,7 +17,10 @@ definitions under operating systems (like, say, Windows NT) with different file system semantics. */ -#include <assert.h> +/* + * $FreeBSD$ + */ + #include "cvs.h" static int deep_remove_dir PROTO((const char *path)); @@ -414,12 +417,12 @@ unlink_file (f) const char *f; { if (trace) - (void) fprintf (stderr, "%s-> unlink_file(%s)\n", + (void) fprintf (stderr, "%s-> unlink(%s)\n", CLIENT_SERVER_STR, f); if (noexec) return (0); - return (CVS_UNLINK (f)); + return (unlink (f)); } /* @@ -465,7 +468,7 @@ unlink_file_dir (f) else if (S_ISDIR (sb.st_mode)) return deep_remove_dir (f); - return CVS_UNLINK (f); + return unlink (f); } /* Remove a directory and everything it contains. Returns 0 for @@ -488,14 +491,14 @@ deep_remove_dir (path) returns 87). */ || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87)) { - if ((dirp = CVS_OPENDIR (path)) == NULL) + if ((dirp = opendir (path)) == NULL) /* If unable to open the directory return * an error */ return -1; errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) + while ((dp = readdir (dirp)) != NULL) { char *buf; @@ -513,16 +516,16 @@ deep_remove_dir (path) { if (deep_remove_dir(buf)) { - CVS_CLOSEDIR(dirp); + closedir(dirp); free (buf); return -1; } } else { - if (CVS_UNLINK (buf) != 0) + if (unlink (buf) != 0) { - CVS_CLOSEDIR(dirp); + closedir(dirp); free (buf); return -1; } @@ -534,11 +537,11 @@ deep_remove_dir (path) if (errno != 0) { int save_errno = errno; - CVS_CLOSEDIR (dirp); + closedir (dirp); errno = save_errno; return -1; } - CVS_CLOSEDIR (dirp); + closedir (dirp); return rmdir (path); } else @@ -685,167 +688,71 @@ xcmp (file1, file2) } /* Generate a unique temporary filename. Returns a pointer to a newly - * malloc'd string containing the name. Returns successfully or not at - * all. - * - * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!! - * - * and yes, I know about the way the rcs commands use temp files. I think - * they should be converted too but I don't have time to look into it right - * now. - */ + malloc'd string containing the name. Returns successfully or not at + all. */ +/* There are at least three functions for generating temporary + filenames. We use tempnam (SVID 3) if possible, else mktemp (BSD + 4.3), and as last resort tmpnam (POSIX). Reason is that tempnam and + mktemp both allow to specify the directory in which the temporary + file will be created. */ +#if 1 char * cvs_temp_name () { - char *fn; - FILE *fp; + char *value; + int retval; - fp = cvs_temp_file (&fn); - if (fp == NULL) - error (1, errno, "Failed to create temporary file"); - if (fclose (fp) == EOF) - error (0, errno, "Failed to close temporary file %s", fn); - return fn; -} + value = xmalloc (strlen (Tmpdir) + 40); + sprintf (value, "%s/%s", Tmpdir, "cvsXXXXXXXXXX"); + retval = mkstemp (value); -/* Generate a unique temporary filename and return an open file stream - * to the truncated file by that name - * - * INPUTS - * filename where to place the pointer to the newly allocated file - * name string - * - * OUTPUTS - * filename dereferenced, will point to the newly allocated file - * name string. This value is undefined if the function - * returns an error. - * - * RETURNS - * An open file pointer to a read/write mode empty temporary file with the - * unique file name or NULL on failure. - * - * ERRORS - * on error, errno will be set to some value either by CVS_FOPEN or - * whatever system function is called to generate the temporary file name - */ -/* There are at least four functions for generating temporary - * filenames. We use mkstemp (BSD 4.3) if possible, else tempnam (SVID 3), - * else mktemp (BSD 4.3), and as last resort tmpnam (POSIX). Reason is that - * mkstemp, tempnam, and mktemp both allow to specify the directory in which - * the temporary file will be created. - * - * And the _correct_ way to use the deprecated functions probably involves - * opening file descriptors using O_EXCL & O_CREAT and even doing the annoying - * NFS locking thing, but until I hear of more problems, I'm not going to - * bother. - */ -FILE *cvs_temp_file (filename) - char **filename; + if (retval == -1) + error (1, errno, "cannot generate temporary filename"); + close (retval); + return value; +} +#else +#ifdef HAVE_TEMPNAM +char * +cvs_temp_name () { - char *fn; - FILE *fp; - - /* FIXME - I'd like to be returning NULL here in noexec mode, but I think - * some of the rcs & diff functions which rely on a temp file run in - * noexec mode too. - */ - - assert (filename != NULL); - -#ifdef HAVE_MKSTEMP - - { - int fd; - - fn = xmalloc (strlen (Tmpdir) + 11); - sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" ); - fd = mkstemp (fn); - - /* a NULL return will be interpreted by callers as an error and - * errno should still be set - */ - if (fd == -1) fp = NULL; - else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL) - { - /* attempt to close and unlink the file since mkstemp returned sucessfully and - * we believe it's been created and opened - */ - int save_errno = errno; - if (close (fd)) - error (0, errno, "Failed to close temporary file %s", fn); - if (CVS_UNLINK (fn)) - error (0, errno, "Failed to unlink temporary file %s", fn); - errno = save_errno; - } - - if (fp == NULL) free (fn); - /* mkstemp is defined to open mode 0600 using glibc 2.0.7+ */ - /* FIXME - configure can probably tell us which version of glibc we are - * linking to and not chmod for 2.0.7+ - */ - else chmod (fn, 0600); - - } - -#elif HAVE_TEMPNAM - - /* tempnam has been deprecated due to under-specification */ - - fn = tempnam (Tmpdir, "cvs"); - if (fn == NULL) fp = NULL; - else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) free (fn); - else chmod (fn, 0600); + char *retval; + retval = tempnam (Tmpdir, "cvs"); + if (retval == NULL) + error (1, errno, "cannot generate temporary filename"); /* tempnam returns a pointer to a newly malloc'd string, so there's - * no need for a xstrdup - */ - -#elif HAVE_MKTEMP - - /* mktemp has been deprecated due to the BSD 4.3 specification specifying - * that XXXXXX will be replaced by a PID and a letter, creating only 26 - * possibilities, a security risk, and a race condition. - */ - - { - char *ifn; - - ifn = xmalloc (strlen (Tmpdir) + 11); - sprintf (ifn, "%s/%s", Tmpdir, "cvsXXXXXX" ); - fn = mktemp (ifn); - - if (fn == NULL) fp = NULL; - else fp = CVS_FOPEN (fn, "w+"); - - if (fp == NULL) free (ifn); - else chmod (fn, 0600); - - } - -#else /* use tmpnam if all else fails */ - - /* tmpnam is deprecated */ - - { - char ifn[L_tmpnam + 1]; - - fn = tmpnam (ifn); - - if (fn == NULL) fp = NULL; - else if ((fp = CVS_FOPEN (ifn, "w+")) != NULL) - { - fn = xstrdup (ifn); - chmod (fn, 0600); - } - - } - -#endif - - *filename = fn; - return fp; + no need for a xstrdup */ + return retval; } - +#else +char * +cvs_temp_name () +{ +# ifdef HAVE_MKTEMP + char *value; + char *retval; + + value = xmalloc (strlen (Tmpdir) + 40); + sprintf (value, "%s/%s", Tmpdir, "cvsXXXXXX" ); + retval = mktemp (value); + + if (retval == NULL) + error (1, errno, "cannot generate temporary filename"); + return value; +# else + char value[L_tmpnam + 1]; + char *retval; + + retval = tmpnam (value); + if (retval == NULL) + error (1, errno, "cannot generate temporary filename"); + return xstrdup (value); +# endif +} +#endif +#endif + /* Return non-zero iff FILENAME is absolute. Trivial under Unix, but more complicated under other systems. */ int @@ -865,8 +772,8 @@ xreadlink (link) { char *file = NULL; char *tfile; - int buflen = 128; - int link_name_len; + int buflen = BUFSIZ; + int linklen; if (!islink (link)) return NULL; @@ -877,15 +784,15 @@ xreadlink (link) do { file = xrealloc (file, buflen); - link_name_len = readlink (link, file, buflen - 1); + errno = 0; + linklen = readlink (link, file, buflen - 1); buflen *= 2; } - while (link_name_len < 0 && errno == ENAMETOOLONG); + while (linklen == -1 && errno == ENAMETOOLONG); - if (link_name_len < 0) + if (linklen == -1) error (1, errno, "cannot readlink %s", link); - - file[link_name_len] = '\0'; + file[linklen] = '\0'; tfile = xstrdup (file); free (file); @@ -934,17 +841,13 @@ char * get_homedir () { static char *home = NULL; - char *env; + char *env = getenv ("HOME"); struct passwd *pw; if (home != NULL) return home; - if ( -#ifdef SERVER_SUPPORT - !server_active && -#endif - (env = getenv ("HOME")) != NULL) + if (env) home = env; else if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir) @@ -1051,7 +954,7 @@ fopen_case (name, mode, fp, pathp) } } errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) + while ((dp = readdir (dirp)) != NULL) { if (cvs_casecmp (dp->d_name, fname) == 0) { @@ -1063,7 +966,7 @@ fopen_case (name, mode, fp, pathp) } if (errno != 0) error (1, errno, "cannot read directory %s", dir); - CVS_CLOSEDIR (dirp); + closedir (dirp); if (found_name == NULL) { diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c index 6bd6abd..3f77dc9 100644 --- a/contrib/cvs/src/import.c +++ b/contrib/cvs/src/import.c @@ -14,6 +14,8 @@ * VendorReleTag Tag for this particular release * * Additional arguments specify more Vendor Release Tags. + * + * $FreeBSD$ */ #include "cvs.h" @@ -171,17 +173,16 @@ import (argc, argv) if (! isabsolute (argv[0]) && pathname_levels (argv[0]) == 0) { - if (current_parsed_root == NULL) + if (CVSroot_directory == NULL) { error (0, 0, "missing CVSROOT environment variable\n"); error (1, 0, "Set it or specify the '-d' option to %s.", program_name); } - repository = xmalloc (strlen (current_parsed_root->directory) - + strlen (argv[0]) - + 2); - (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); - repos_len = strlen (current_parsed_root->directory); + repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) + + 10); + (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); + repos_len = strlen (CVSroot_directory); } else { @@ -208,7 +209,7 @@ import (argc, argv) *cp = '\0'; #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) { /* For rationale behind calling start_server before do_editor, see commit.c */ @@ -221,7 +222,7 @@ import (argc, argv) do_editor ((char *) NULL, &message, repository, (List *) NULL); } - do_verify (message, repository); + do_verify (&message, repository); msglen = message == NULL ? 0 : strlen (message); if (msglen == 0 || message[msglen - 1] != '\n') { @@ -237,7 +238,7 @@ import (argc, argv) } #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) { int err; @@ -291,7 +292,8 @@ import (argc, argv) make_directories (repository); /* Create the logfile that will be logged upon completion */ - if ((logfp = cvs_temp_file (&tmpfile)) == NULL) + tmpfile = cvs_temp_name (); + if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL) error (1, errno, "cannot create temporary file `%s'", tmpfile); /* On systems where we can unlink an open file, do so, so it will go away no matter how we exit. FIXME-maybe: Should be checking for @@ -425,7 +427,7 @@ import_descend (message, vtag, targc, targv) else { errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) + while ((dp = readdir (dirp)) != NULL) { if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) goto one_more_time_boys; @@ -476,7 +478,7 @@ import_descend (message, vtag, targc, targv) else { #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) err += client_process_import_file (message, dp->d_name, vtag, targc, targv, repository, @@ -496,7 +498,7 @@ import_descend (message, vtag, targc, targv) error (0, errno, "cannot read directory"); ++err; } - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); } if (dirlist != NULL) @@ -1567,7 +1569,7 @@ import_descend_dir (message, dir, vtag, targc, targv) } #ifdef CLIENT_SUPPORT - if (!quiet && !current_parsed_root->isremote) + if (!quiet && !client_active) #else if (!quiet) #endif @@ -1582,7 +1584,7 @@ import_descend_dir (message, dir, vtag, targc, targv) goto out; } #ifdef CLIENT_SUPPORT - if (!current_parsed_root->isremote && !isdir (repository)) + if (!client_active && !isdir (repository)) #else if (!isdir (repository)) #endif diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c index c05b83e..30c72f9 100644 --- a/contrib/cvs/src/lock.c +++ b/contrib/cvs/src/lock.c @@ -8,6 +8,8 @@ * Set Lock * * Lock file support for CVS. + * + * $FreeBSD$ */ /* The node Concurrency in doc/cvs.texinfo has a brief introduction to @@ -172,13 +174,12 @@ lock_name (repository, name) /* The interesting part of the repository is the part relative to CVSROOT. */ - assert (current_parsed_root != NULL); - assert (current_parsed_root->directory != NULL); - assert (strncmp (repository, current_parsed_root->directory, - strlen (current_parsed_root->directory)) == 0); - short_repos = repository + strlen (current_parsed_root->directory) + 1; + assert (CVSroot_directory != NULL); + assert (strncmp (repository, CVSroot_directory, + strlen (CVSroot_directory)) == 0); + short_repos = repository + strlen (CVSroot_directory) + 1; - if (strcmp (repository, current_parsed_root->directory) == 0) + if (strcmp (repository, CVSroot_directory) == 0) short_repos = "."; else assert (short_repos[-1] == '/'); @@ -396,7 +397,7 @@ Reader_Lock (xrepository) FILE *fp; char *tmp; - if (noexec) + if (noexec || readonlyfs) return (0); /* we only do one directory at a time for read locks! */ @@ -471,6 +472,11 @@ Writer_Lock (list) if (noexec) return (0); + if (readonlyfs) { + error (0, 0, "write lock failed - read-only repository"); + return (1); + } + /* We only know how to do one list at a time */ if (locklist != (List *) NULL) { @@ -634,7 +640,7 @@ again: error (1, 0, "cannot open directory %s", repository); errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) + while ((dp = readdir (dirp)) != NULL) { if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0) { @@ -655,7 +661,7 @@ again: */ if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1) { - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); free (line); goto again; } @@ -681,7 +687,7 @@ again: if (errno != 0) error (0, errno, "error reading directory %s", repository); - CVS_CLOSEDIR (dirp); + closedir (dirp); return (ret); } @@ -891,11 +897,10 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries) } void -lock_tree_for_write (argc, argv, local, which, aflag) +lock_tree_for_write (argc, argv, local, aflag) int argc; char **argv; int local; - int which; int aflag; { int err; @@ -906,7 +911,7 @@ lock_tree_for_write (argc, argv, local, which, aflag) lock_tree_list = getlist (); err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc, (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc, - argv, local, which, aflag, 0, (char *) NULL, 0); + argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0); sortlist (lock_tree_list, fsortcmp); if (Writer_Lock (lock_tree_list) != 0) error (1, 0, "lock failed - giving up"); diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c index 9289737..cc564c06 100644 --- a/contrib/cvs/src/login.c +++ b/contrib/cvs/src/login.c @@ -5,6 +5,8 @@ * specified in the README file that comes with CVS. * * Allow user to log in for an authenticating server. + * + * $FreeBSD$ */ #include "cvs.h" @@ -85,183 +87,26 @@ construct_cvspass_filename () return passfile; } - - -/* - * static char * - * password_entry_parseline ( - * const char *cvsroot_canonical, - * const unsigned char warn, - * const int linenumber, - * char *linebuf - * ); - * - * Internal function used by password_entry_operation. Parse a single line - * from a ~/.cvsroot password file and return a pointer to the password if the - * line refers to the same cvsroot as cvsroot_canonical - * - * INPUTS - * cvsroot_canonical the root we are looking for - * warn Boolean: print warnings for invalid lines? - * linenumber the line number for error messages - * linebuf the current line - * - * RETURNS - * NULL if the line doesn't match - * char *password as a pointer into linebuf - * - * NOTES - * This function temporarily alters linebuf, so it isn't thread safe when - * called on the same linebuf - */ -static char * -password_entry_parseline (cvsroot_canonical, warn, linenumber, linebuf) - const char *cvsroot_canonical; - const unsigned char warn; - const int linenumber; - char *linebuf; +static const char *const login_usage[] = { - char *password = NULL; - char *p; - - /* look for '^/' */ - if (*linebuf == '/') - { - /* Yes: slurp '^/\d+\D' and parse the rest of the line according to version number */ - char *q; - unsigned long int entry_version; - - if (isspace(*(linebuf + 1))) - /* special case since strtoul ignores leading white space */ - entry_version = 0; - else - entry_version = strtoul (linebuf + 1, &q, 10); - - if (q == linebuf + 1) - /* no valid digits found by strtoul */ - entry_version = 0; - else - /* assume a delimiting seperator */ - q++; - - switch (entry_version) - { - case 1: - /* this means the same normalize_cvsroot we are using was - * used to create this entry. strcmp is good enough for - * us. - */ - p = strchr (q, ' '); - if (p == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", - linenumber); - } - else - { - *p = '\0'; - if (strcmp (cvsroot_canonical, q) == 0) - password = p + 1; - *p = ' '; - } - break; - case ULONG_MAX: - if (warn && !really_quiet) - { - error (0, errno, "warning: unable to convert version number in password file at line %d", - linenumber); - error (0, 0, "skipping entry"); - } - break; - case 0: - if (warn && !really_quiet) - error (0, 0, "warning: skipping entry with invalid version string in password file at line %d", - linenumber); - break; - default: - if (warn && !really_quiet) - error (0, 0, "warning: skipping entry with unknown version (%lu) in password file at line %d", - entry_version, linenumber); - break; - } - } - else - { - /* No: assume: - * - * ^cvsroot Aencoded_password$ - * - * as header comment specifies and parse accordingly - */ - cvsroot_t *tmp_root; - char *tmp_root_canonical; - - p = strchr (linebuf, ' '); - if (p == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); - return NULL;; - } - - *p = '\0'; - if ((tmp_root = parse_cvsroot (linebuf)) == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); - *p = ' '; - return NULL; - } - *p = ' '; - tmp_root_canonical = normalize_cvsroot (tmp_root); - if (strcmp (cvsroot_canonical, tmp_root_canonical) == 0) - password = p + 1; - - free (tmp_root_canonical); - free_cvsroot_t (tmp_root); - } - - return password; -} - - + "Usage: %s %s\n", + "(Specify the --help global option for a list of other help options)\n", + NULL +}; -/* - * static char * - * password_entry_operation ( - * password_entry_operation_t operation, - * cvsroot_t *root, - * char *newpassword - * ); - * - * Search the password file and depending on the value of operation: - * - * Mode Action - * password_entry_lookup Return the password - * password_entry_delete Delete the entry from the file, if it exists - * password_entry_add Replace the line with the new one, else append it +/* Prompt for a password, and store it in the file "CVS/.cvspass". * * Because the user might be accessing multiple repositories, with * different passwords for each one, the format of ~/.cvspass is: * - * [user@]host:[port]/path Aencoded_password - * [user@]host:[port]/path Aencoded_password + * user@host:/path Acleartext_password + * user@host:/path Acleartext_password * ... * - * New entries are always of the form: + * Of course, the "user@" might be left off -- it's just based on the + * value of CVSroot. * - * /1 user@host:port/path Aencoded_password - * - * but the old format is supported for backwards compatibility. - * The entry version string wasn't strictly necessary, but it avoids the - * overhead of parsing some entries since we know it is already in canonical - * form and allows room for expansion later, say, if we want to allow spaces - * and/or other characters to be escaped in the string. Also, the new entries - * would have been ignored by old versions of CVS anyhow since those versions - * didn't know how to parse a port number. - * - * The "A" before "encoded_password" is a literal capital A. It's a + * The "A" before "cleartext_password" is a literal capital A. It's a * version number indicating which form of scrambling we're doing on * the password -- someday we might provide something more secure than * the trivial encoding we do now, and when that day comes, it would @@ -271,318 +116,201 @@ password_entry_parseline (cvsroot_canonical, warn, linenumber, linebuf) * it from being read by others. Unlike .netrc, we will not be * fascist about it, at most issuing a warning, and never refusing to * work. - * - * INPUTS - * operation operation to perform - * root cvsroot_t to look up - * newpassword prescrambled new password, for password_entry_add_mode - * - * RETURNS - * -1 if password_entry_lookup_mode not specified - * NULL on failed lookup - * pointer to a copy of the password string otherwise, which the caller is - * responsible for disposing of */ - -typedef enum password_entry_operation_e { - password_entry_lookup, - password_entry_delete, - password_entry_add -} password_entry_operation_t; - -static char * -password_entry_operation (operation, root, newpassword) - password_entry_operation_t operation; - cvsroot_t *root; - char *newpassword; +int +login (argc, argv) + int argc; + char **argv; { char *passfile; FILE *fp; - char *cvsroot_canonical = NULL; - char *password = NULL; - int line_length; - long line; - char *linebuf = NULL; + char *typed_password, *found_password; + char *linebuf = (char *) NULL; size_t linebuf_len; - char *p; - int save_errno = 0; - - if (root->method != pserver_method) - { - error (0, 0, "internal error: can only call password_entry_operation with pserver method"); - error (1, 0, "CVSROOT: %s", root->original); - } + int root_len, already_entered = 0; + int line_length; - /* Yes, the method below reads the user's password file twice when we have - * to delete an entry. It's inefficient, but we're not talking about a gig of - * data here. - */ + if (argc < 0) + usage (login_usage); - passfile = construct_cvspass_filename (); - fp = CVS_FOPEN (passfile, "r"); - if (fp == NULL) + if (CVSroot_method != pserver_method) { - error (0, errno, "failed to open %s for reading", passfile); - goto error_exit; + error (0, 0, "can only use pserver method with `login' command"); + error (1, 0, "CVSROOT: %s", CVSroot_original); } - cvsroot_canonical = normalize_cvsroot (root); - - /* Check each line to see if we have this entry already. */ - line = 0; - while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - line++; - password = password_entry_parseline(cvsroot_canonical, 1, line, linebuf); - if (password != NULL) - /* this is it! break out and deal with linebuf */ - break; - } - if (line_length < 0 && !feof (fp)) + if (! CVSroot_username) { - error (0, errno, "cannot read %s", passfile); - goto error_exit; + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); } - if (fclose (fp) < 0) - /* not fatal, unless it cascades */ - error (0, errno, "cannot close %s", passfile); - fp = NULL; - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); + printf ("(Logging in to %s@%s)\n", CVSroot_username, CVSroot_hostname); + fflush (stdout); - /* a copy to return or keep around so we can reuse linebuf */ - if (password != NULL) - { - /* chomp the EOL */ - p = strchr (password, '\n'); - if (p != NULL) - *p = '\0'; - password = xstrdup (password); - } + passfile = construct_cvspass_filename (); + typed_password = GETPASS ("CVS password: "); + typed_password = scramble (typed_password); - /* might as well return now */ - if (operation == password_entry_lookup) - goto out; + /* Force get_cvs_password() to use this one (when the client + * confirms the new password with the server), instead of + * consulting the file. We make a new copy because cvs_password + * will get zeroed by connect_to_server(). */ - /* same here */ - if (operation == password_entry_delete && password == NULL) - { - error (0, 0, "Entry not found."); - goto out; - } + cvs_password = xstrdup (typed_password); - /* okay, file errors can simply be fatal from now on since we don't do - * anything else if we're in lookup mode - */ + connect_to_pserver (NULL, NULL, 1, 0); - /* copy the file with the entry deleted unless we're in add - * mode and the line we found contains the same password we're supposed to - * add + /* IF we have a password for this "[user@]host:/path" already + * THEN + * IF it's the same as the password we read from the prompt + * THEN + * do nothing + * ELSE + * replace the old password with the new one + * ELSE + * append new entry to the end of the file. */ - if (!noexec && password != NULL && (operation == password_entry_delete - || (operation == password_entry_add && strcmp (password, newpassword)))) - { - long found_at = line; - char *tmp_name; - FILE *tmp_fp; - /* open the original file again */ - fp = CVS_FOPEN (passfile, "r"); - if (fp == NULL) - error (1, errno, "failed to open %s for reading", passfile); + root_len = strlen (CVSroot_original); - /* create and open a temp file */ - if ((tmp_fp = cvs_temp_file (&tmp_name)) == NULL) - error (1, errno, "unable to open temp file %s", tmp_name); + /* Yes, the method below reads the user's password file twice. It's + inefficient, but we're not talking about a gig of data here. */ - line = 0; + fp = CVS_FOPEN (passfile, "r"); + /* FIXME: should be printing a message if fp == NULL and not + existence_error (errno). */ + if (fp != NULL) + { + /* Check each line to see if we have this entry already. */ while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - line++; - if (line < found_at - || (line != found_at - && !password_entry_parseline(cvsroot_canonical, 0, line, linebuf))) - { - if (fprintf (tmp_fp, "%s", linebuf) == EOF) - { - /* try and clean up anyhow */ - error (0, errno, "fatal error: cannot write %s", tmp_name); - if (fclose (tmp_fp) == EOF) - error (0, errno, "cannot close %s", tmp_name); - /* call CVS_UNLINK instead of unlink_file since the file - * got created in noexec mode - */ - if (CVS_UNLINK (tmp_name) < 0) - error (0, errno, "cannot remove %s", tmp_name); - /* but quit so we don't remove all the entries from a - * user's password file accidentally - */ - error (1, 0, "exiting"); - } - } - } - if (line_length < 0 && !feof (fp)) - { - error (0, errno, "cannot read %s", passfile); - goto error_exit; - } + { + if (strncmp (CVSroot_original, linebuf, root_len) == 0) + { + already_entered = 1; + break; + } + } if (fclose (fp) < 0) - /* not fatal, unless it cascades */ error (0, errno, "cannot close %s", passfile); - if (fclose (tmp_fp) < 0) - /* not fatal, unless it cascades */ - /* FIXME - does copy_file return correct results if the file wasn't - * closed? should this be fatal? - */ - error (0, errno, "cannot close %s", tmp_name); - - /* FIXME: rename_file would make more sense (e.g. almost - * always faster). - * - * I don't think so, unless we change the way rename_file works to - * attempt a cp/rm sequence when rename fails since rename doesn't - * work across file systems and it isn't uncommon to have /tmp - * on its own partition. - * - * For that matter, it's probably not uncommon to have a home - * directory on an NFS mount. - */ - copy_file (tmp_name, passfile); - if (CVS_UNLINK (tmp_name) < 0) - error (0, errno, "cannot remove %s", tmp_name); - free (tmp_name); } + else if (!existence_error (errno)) + error (0, errno, "cannot open %s", passfile); - /* in add mode, if we didn't find an entry or found an entry with a - * different password, append the new line - */ - if (!noexec && operation == password_entry_add - && (password == NULL || strcmp (password, newpassword))) + if (already_entered) + { + /* This user/host has a password in the file already. */ + + strtok (linebuf, " "); + found_password = strtok (NULL, "\n"); + if (strcmp (found_password, typed_password)) + { + /* typed_password and found_password don't match, so we'll + * have to update passfile. We replace the old password + * with the new one by writing a tmp file whose contents are + * exactly the same as passfile except that this one entry + * gets typed_password instead of found_password. Then we + * rename the tmp file on top of passfile. + */ + char *tmp_name; + FILE *tmp_fp; + + tmp_name = cvs_temp_name (); + if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) + { + error (1, errno, "unable to open temp file %s", tmp_name); + return 1; + } + chmod (tmp_name, 0600); + + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + { + error (1, errno, "unable to open %s", passfile); + if (linebuf) + free (linebuf); + return 1; + } + /* I'm not paranoid, they really ARE out to get me: */ + chmod (passfile, 0600); + + while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) + { + if (strncmp (CVSroot_original, linebuf, root_len)) + { + if (fprintf (tmp_fp, "%s", linebuf) == EOF) + error (0, errno, "cannot write %s", tmp_name); + } + else + { + if (fprintf (tmp_fp, "%s %s\n", CVSroot_original, + typed_password) == EOF) + error (0, errno, "cannot write %s", tmp_name); + } + } + if (line_length < 0 && !feof (fp)) + error (0, errno, "cannot read %s", passfile); + if (linebuf) + free (linebuf); + if (fclose (tmp_fp) < 0) + error (0, errno, "cannot close %s", tmp_name); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", passfile); + + /* FIXME: rename_file would make more sense (e.g. almost + always faster). */ + copy_file (tmp_name, passfile); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); + chmod (passfile, 0600); + + free (tmp_name); + } + } + else { + if (linebuf) + free (linebuf); if ((fp = CVS_FOPEN (passfile, "a")) == NULL) - error (1, errno, "could not open %s for writing", passfile); - - if (fprintf (fp, "/1 %s %s\n", cvsroot_canonical, newpassword) == EOF) - error (1, errno, "cannot write %s", passfile); + { + error (1, errno, "could not open %s", passfile); + free (passfile); + return 1; + } + + if (fprintf (fp, "%s %s\n", CVSroot_original, typed_password) == EOF) + error (0, errno, "cannot write %s", passfile); if (fclose (fp) < 0) error (0, errno, "cannot close %s", passfile); } /* Utter, total, raving paranoia, I know. */ chmod (passfile, 0600); - - if (password) - { - free (password); - password = NULL; - } - if (linebuf) - free (linebuf); - -out: - free (cvsroot_canonical); - free (passfile); - return password; - -error_exit: - /* just exit when we're not in lookup mode */ - if (operation != password_entry_lookup) - error (1, 0, "fatal error: exiting"); - /* clean up and exit in lookup mode so we can try a login with a NULL - * password anyhow in case that's what we would have found - */ - save_errno = errno; - if (fp != NULL) - { - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); - if(fclose (fp) < 0) - error (0, errno, "cannot close %s", passfile); - } - if (linebuf) - free (linebuf); - if (cvsroot_canonical) - free (cvsroot_canonical); - free (passfile); - errno = save_errno; - return NULL; -} - - - -/* Prompt for a password, and store it in the file "CVS/.cvspass". - */ - -static const char *const login_usage[] = -{ - "Usage: %s %s\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -login (argc, argv) - int argc; - char **argv; -{ - char *typed_password; - char *cvsroot_canonical; - - if (argc < 0) - usage (login_usage); - - if (current_parsed_root->method != pserver_method) - { - error (0, 0, "can only use `login' command with the 'pserver' method"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); - } - - cvsroot_canonical = normalize_cvsroot(current_parsed_root); - printf ("Logging in to %s\n", cvsroot_canonical); - fflush (stdout); - - if (current_parsed_root->password) - { - typed_password = scramble (current_parsed_root->password); - } - else - { - char *tmp; - tmp = GETPASS ("CVS password: "); - typed_password = scramble (tmp); - memset (tmp, 0, strlen (tmp)); - } - - /* Force get_cvs_password() to use this one (when the client - * confirms the new password with the server), instead of - * consulting the file. We make a new copy because cvs_password - * will get zeroed by connect_to_server(). */ - cvs_password = xstrdup (typed_password); - - connect_to_pserver (NULL, NULL, 1, 0); - - password_entry_operation (password_entry_add, current_parsed_root, typed_password); - memset (typed_password, 0, strlen (typed_password)); free (typed_password); + free (passfile); free (cvs_password); - free (cvsroot_canonical); cvs_password = NULL; - return 0; } /* Returns the _scrambled_ password. The server must descramble before hashing and comparing. If password file not found, or - password not found in the file, just return NULL. */ + password not found in the file, just return NULL. */ char * get_cvs_password () { - if (current_parsed_root->password) - return (scramble(current_parsed_root->password)); - + int found_it = 0; + int root_len; + char *password = NULL; + char *linebuf = NULL; + size_t linebuf_len; + FILE *fp; + char *passfile; + int line_length; + /* If someone (i.e., login()) is calling connect_to_pserver() out of context, then assume they have supplied the correct, scrambled password. */ @@ -592,24 +320,76 @@ get_cvs_password () if (getenv ("CVS_PASSWORD") != NULL) { /* In previous versions of CVS one could specify a password in - * CVS_PASSWORD. This is a bad idea, because in BSD variants - * of unix anyone can see the environment variable with 'ps'. - * But for users who were using that feature we want to at - * least let them know what is going on. After printing this - * warning, we should fall through to the regular error where - * we tell them to run "cvs login" (unless they already ran - * it, of course). - */ - error (0, 0, "CVS_PASSWORD is no longer supported; ignored"); + CVS_PASSWORD. This is a bad idea, because in BSD variants + of unix anyone can see the environment variable with 'ps'. + But for users who were using that feature we want to at + least let them know what is going on. After printing this + warning, we should fall through to the regular error where + we tell them to run "cvs login" (unless they already ran + it, of course). */ + error (0, 0, "CVS_PASSWORD is no longer supported; ignored"); + } + + /* Else get it from the file. First make sure that the CVSROOT + variable has the appropriate fields filled in. */ + + if (CVSroot_method != pserver_method) + { + error (0, 0, "can only call GET_CVS_PASSWORD with pserver method"); + error (1, 0, "CVSROOT: %s", CVSroot_original); + } + + if (! CVSroot_username) + { + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); + } + + passfile = construct_cvspass_filename (); + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + { + free (passfile); + return NULL; + } + + root_len = strlen (CVSroot_original); + + /* Check each line to see if we have this entry already. */ + while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) + { + if (strncmp (CVSroot_original, linebuf, root_len) == 0) + { + /* This is it! So break out and deal with linebuf. */ + found_it = 1; + break; + } } + if (line_length < 0 && !feof (fp)) + error (0, errno, "cannot read %s", passfile); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", passfile); - if (current_parsed_root->method != pserver_method) + if (found_it) { - error (0, 0, "can only call get_cvs_password with pserver method"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); + /* linebuf now contains the line with the password. */ + char *tmp; + + strtok (linebuf, " "); + tmp = strtok (NULL, "\n"); + if (tmp == NULL) + error (1, 0, "bad entry in %s for %s", passfile, CVSroot_original); + + /* Give it permanent storage. */ + password = xstrdup (tmp); + memset (tmp, 0, strlen (password)); } - return password_entry_operation (password_entry_lookup, current_parsed_root, NULL); + if (linebuf) + free (linebuf); + free (passfile); + return password; } static const char *const logout_usage[] = @@ -625,15 +405,29 @@ logout (argc, argv) int argc; char **argv; { - char *cvsroot_canonical; + char *passfile; + FILE *fp; + char *tmp_name = NULL; + FILE *tmp_fp; + char *linebuf = (char *) NULL; + size_t linebuf_len; + int root_len, found = 0; + int line_length; if (argc < 0) usage (logout_usage); - if (current_parsed_root->method != pserver_method) + if (CVSroot_method != pserver_method) { error (0, 0, "can only use pserver method with `logout' command"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); + error (1, 0, "CVSROOT: %s", CVSroot_original); + } + + if (! CVSroot_username) + { + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); } /* Hmm. Do we want a variant of this command which deletes _all_ @@ -644,15 +438,73 @@ logout (argc, argv) of security, in that it wouldn't delete entries from any .cvspass files but the current one. */ - if (!quiet) + printf ("(Logging out of %s@%s)\n", CVSroot_username, CVSroot_hostname); + fflush (stdout); + + /* IF we have a password for this "[user@]host:/path" already + * THEN + * drop the entry + * ELSE + * do nothing + */ + + passfile = construct_cvspass_filename (); + /* FIXME: This should not be in /tmp; that is almost surely a security + hole. Probably should just keep it in memory. */ + tmp_name = cvs_temp_name (); + if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) { - cvsroot_canonical = normalize_cvsroot(current_parsed_root); - printf ("Logging out of %s\n", cvsroot_canonical); - fflush (stdout); - free (cvsroot_canonical); + error (1, errno, "unable to open temp file %s", tmp_name); + return 1; + } + chmod (tmp_name, 0600); + + root_len = strlen (CVSroot_original); + + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + error (1, errno, "Error opening %s", passfile); + + /* Check each line to see if we have this entry. */ + /* Copy only those lines that do not match this entry */ + while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) + { + if (strncmp (CVSroot_original, linebuf, root_len)) + { + if (fprintf (tmp_fp, "%s", linebuf) == EOF) + error (0, errno, "cannot write %s", tmp_name); + } + else + found = 1; + } + if (line_length < 0 && !feof (fp)) + error (0, errno, "cannot read %s", passfile); + + if (linebuf) + free (linebuf); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", passfile); + if (fclose (tmp_fp) < 0) + error (0, errno, "cannot close %s", tmp_name); + + if (! found) + { + printf ("Entry not found for %s\n", CVSroot_original); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); + } + else + { + /* FIXME: rename_file would make more sense (e.g. almost + always faster). */ + copy_file (tmp_name, passfile); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); + chmod (passfile, 0600); } - password_entry_operation (password_entry_delete, current_parsed_root, NULL); + if (tmp_name) + free (tmp_name); return 0; } diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c index d2ef806..a5e16b7 100644 --- a/contrib/cvs/src/logmsg.c +++ b/contrib/cvs/src/logmsg.c @@ -4,6 +4,8 @@ * * You may distribute under the terms of the GNU General Public License as * specified in the README file that comes with the CVS source distribution. + * + * $FreeBSD$ */ #include "cvs.h" @@ -190,10 +192,8 @@ do_editor (dir, messagep, repository, changes) if (strcmp (Editor, "") == 0 && !editinfo_editor) error(1, 0, "no editor defined, must use -e or -m"); + /* Create a temporary file */ - /* FIXME - It's possible we should be relying on cvs_temp_file to open - * the file here - we get race conditions otherwise. - */ fname = cvs_temp_name (); again: if ((fp = CVS_FOPEN (fname, "w+")) == NULL) @@ -207,6 +207,8 @@ do_editor (dir, messagep, repository, changes) (*messagep)[strlen (*messagep) - 1] != '\n') (void) fprintf (fp, "\n"); } + else + (void) fprintf (fp, "\n"); if (repository != NULL) /* tack templates on if necessary */ @@ -272,7 +274,7 @@ do_editor (dir, messagep, repository, changes) free (editinfo_editor); editinfo_editor = (char *) NULL; #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) ; /* nothing, leave editinfo_editor NULL */ else #endif @@ -387,16 +389,22 @@ do_editor (dir, messagep, repository, changes) independant of the running of an editor for getting a message. */ void -do_verify (message, repository) - char *message; +do_verify (messagep, repository) + char **messagep; char *repository; { FILE *fp; char *fname; int retcode = 0; + char *line; + int line_length; + size_t line_chars_allocated; + char *p; + struct stat stbuf; + #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) /* The verification will happen on the server. */ return; #endif @@ -408,22 +416,25 @@ do_verify (message, repository) /* If there's no message, then we have nothing to verify. Can this case happen? And if so why would we print a message? */ - if (message == NULL) + if (*messagep == NULL) { cvs_output ("No message to verify\n", 0); return; } - /* open a temporary file, write the message to the + /* Get a temp filename, open a temporary file, write the message to the temp file, and close the file. */ - if ((fp = cvs_temp_file (&fname)) == NULL) + fname = cvs_temp_name (); + + fp = fopen (fname, "w"); + if (fp == NULL) error (1, errno, "cannot create temporary file %s", fname); else { - fprintf (fp, "%s", message); - if ((message)[0] == '\0' || - (message)[strlen (message) - 1] != '\n') + fprintf (fp, "%s", *messagep); + if ((*messagep)[0] == '\0' || + (*messagep)[strlen (*messagep) - 1] != '\n') (void) fprintf (fp, "%s", "\n"); if (fclose (fp) == EOF) error (1, errno, "%s", fname); @@ -453,6 +464,55 @@ do_verify (message, repository) } } + /* put the entire message back into the *messagep variable */ + + fp = open_file (fname, "r"); + if (fp == NULL) + { + error (1, errno, "cannot open temporary file %s", fname); + return; + } + + if (*messagep) + free (*messagep); + + if ( CVS_STAT (fname, &stbuf) != 0) + error (1, errno, "cannot find size of temp file %s", fname); + + if (stbuf.st_size == 0) + *messagep = NULL; + else + { + /* On NT, we might read less than st_size bytes, but we won't + read more. So this works. */ + *messagep = (char *) xmalloc (stbuf.st_size + 1); + *messagep[0] = '\0'; + } + + line = NULL; + line_chars_allocated = 0; + + if (*messagep) + { + p = *messagep; + while (1) + { + line_length = getline (&line, &line_chars_allocated, fp); + if (line_length == -1) + { + if (ferror (fp)) + error (0, errno, "warning: cannot read %s", fname); + break; + } + if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) + continue; + (void) strcpy (p, line); + p += line_length; + } + } + if (fclose (fp) < 0) + error (0, errno, "warning: cannot close %s", fname); + /* Delete the temp file */ if (unlink_file (fname) < 0) @@ -789,16 +849,16 @@ logfile_write (repository, filter, message, logfp, changes) srepos = Short_Repository (repository); - prog = cp = xmalloc ((fmt_percent - filter) + 2 * strlen (srepos) - + 2 * strlen (str_list) + strlen (fmt_continue) + prog = xmalloc ((fmt_percent - filter) + strlen (srepos) + + strlen (str_list) + strlen (fmt_continue) + 10); - (void) memcpy (cp, filter, fmt_percent - filter); - cp += fmt_percent - filter; - *cp++ = '"'; - cp = shell_escape (cp, srepos); - cp = shell_escape (cp, str_list); - *cp++ = '"'; - (void) strcpy (cp, fmt_continue); + (void) strncpy (prog, filter, fmt_percent - filter); + prog[fmt_percent - filter] = '\0'; + (void) strcat (prog, "'"); + (void) strcat (prog, srepos); + (void) strcat (prog, str_list); + (void) strcat (prog, "'"); + (void) strcat (prog, fmt_continue); /* To be nice, free up some memory. */ diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c index 3a21916..cad210b 100644 --- a/contrib/cvs/src/main.c +++ b/contrib/cvs/src/main.c @@ -10,10 +10,12 @@ * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing * the shell-script CVS system that this is based on. * + * $FreeBSD$ */ #include <assert.h> #include "cvs.h" +#include "prepend_args.h" #ifdef HAVE_WINSOCK_H #include <winsock.h> @@ -41,6 +43,8 @@ int really_quiet = 0; int quiet = 0; int trace = 0; int noexec = 0; +int readonlyfs = 0; +int require_real_user = 0; int logoff = 0; /* Set if we should be writing CVSADM directories at top level. At @@ -64,12 +68,8 @@ char *Editor = EDITOR_DFLT; List *root_directories = NULL; /* We step through the above values. This variable is set to reflect - * the currently active value. - * - * Now static. FIXME - this variable should be removable (well, localizable) - * with a little more work. - */ -static char *current_root = NULL; + the currently active value. */ +char *current_root = NULL; static const struct cmd @@ -100,50 +100,47 @@ static const struct cmd char *nick2; int (*func) (); /* Function takes (argc, argv) arguments. */ - unsigned long attr; /* Attributes. */ } cmds[] = { - { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "annotate", "ann", NULL, annotate, CVS_CMD_USES_WORK_DIR }, - { "checkout", "co", "get", checkout, 0 }, - { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR }, - { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR }, - { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR }, - { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR }, - { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT}, - { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY }, + { "add", "ad", "new", add }, + { "admin", "adm", "rcs", admin }, + { "annotate", "ann", NULL, annotate }, + { "checkout", "co", "get", checkout }, + { "commit", "ci", "com", commit }, + { "diff", "di", "dif", diff }, + { "edit", NULL, NULL, edit }, + { "editors", NULL, NULL, editors }, + { "export", "exp", "ex", checkout }, + { "history", "hi", "his", history }, + { "import", "im", "imp", import }, + { "init", NULL, NULL, init }, #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) - { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ + { "kserver", NULL, NULL, server }, /* placeholder */ #endif - { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR }, + { "log", "lo", "rlog", cvslog }, #ifdef AUTH_CLIENT_SUPPORT - { "login", "logon", "lgn", login, 0 }, - { "logout", NULL, NULL, logout, 0 }, + { "login", "logon", "lgn", login }, + { "logout", NULL, NULL, logout }, #endif /* AUTH_CLIENT_SUPPORT */ #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) - { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ + { "pserver", NULL, NULL, server }, /* placeholder */ #endif - { "rannotate","rann", "ra", annotate, 0 }, - { "rdiff", "patch", "pa", patch, 0 }, - { "release", "re", "rel", release, 0 }, - { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "rlog", "rl", NULL, cvslog, 0 }, - { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY }, + { "rdiff", "patch", "pa", patch }, + { "release", "re", "rel", release }, + { "remove", "rm", "delete", cvsremove }, + { "rtag", "rt", "rfreeze", rtag }, #ifdef SERVER_SUPPORT - { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "server", NULL, NULL, server }, #endif - { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR }, - { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR }, - { "version", "ve", "ver", version, 0 }, - { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR }, - { NULL, NULL, NULL, NULL, 0 }, + { "status", "st", "stat", cvsstatus }, + { "tag", "ta", "freeze", cvstag }, + { "unedit", NULL, NULL, unedit }, + { "update", "up", "upd", update }, + { "version", "ve", "ver", version }, + { "watch", NULL, NULL, watch }, + { "watchers", NULL, NULL, watchers }, + { NULL, NULL, NULL, NULL }, }; static const char *const usg[] = @@ -218,11 +215,9 @@ static const char *const cmd_usage[] = #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) " pserver Password server mode\n", #endif - " rannotate Show last revision where each line of module was modified\n", " rdiff Create 'patch' format diffs between releases\n", " release Indicate that a Module is no longer in use\n", " remove Remove an entry from the repository\n", - " rlog Print out history information for a module\n", " rtag Add a symbolic tag to a module\n", #ifdef SERVER_SUPPORT " server Server mode\n", @@ -231,7 +226,6 @@ static const char *const cmd_usage[] = " tag Add a symbolic tag to checked out version of files\n", " unedit Undo an edit command\n", " update Bring work tree in sync with repository\n", - " version Show current CVS version(s)\n", " watch Set watches\n", " watchers See who is watching a file\n", "(Specify the --help option for a list of other help options)\n", @@ -247,9 +241,11 @@ static const char *const opt_usage[] = " -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", + " -g Force group-write perms on checked-out files.\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", + " -R Assume repository is read-only, such as CDROM\n", " -v CVS version and copyright.\n", " -T tmpdir Use 'tmpdir' for temporary files.\n", " -e editor Use 'editor' for editing log information.\n", @@ -325,14 +321,51 @@ unsigned long int lookup_command_attribute (cmd_name) char *cmd_name; { - const struct cmd *cm; + unsigned long int ret = 0; - for (cm = cmds; cm->fullname; cm++) + if (strcmp (cmd_name, "import") != 0) { - if (strcmp (cmd_name, cm->fullname) == 0) - break; + ret |= CVS_CMD_IGNORE_ADMROOT; + } + + + /* The following commands do not use a checked-out working + directory. We conservatively assume that everything else does. + Feel free to add to this list if you are _certain_ something + something doesn't use the WD. */ + if ((strcmp (cmd_name, "checkout") != 0) && + (strcmp (cmd_name, "init") != 0) && + (strcmp (cmd_name, "login") != 0) && + (strcmp (cmd_name, "logout") != 0) && + (strcmp (cmd_name, "rdiff") != 0) && + (strcmp (cmd_name, "release") != 0) && + (strcmp (cmd_name, "rtag") != 0)) + { + ret |= CVS_CMD_USES_WORK_DIR; } - return cm->attr; + + + /* The following commands do not modify the repository; we + conservatively assume that everything else does. Feel free to + add to this list if you are _certain_ something is safe. */ + if ((strcmp (cmd_name, "annotate") != 0) && + (strcmp (cmd_name, "checkout") != 0) && + (strcmp (cmd_name, "diff") != 0) && + (strcmp (cmd_name, "rdiff") != 0) && + (strcmp (cmd_name, "update") != 0) && + (strcmp (cmd_name, "editors") != 0) && + (strcmp (cmd_name, "export") != 0) && + (strcmp (cmd_name, "history") != 0) && + (strcmp (cmd_name, "log") != 0) && + (strcmp (cmd_name, "noop") != 0) && + (strcmp (cmd_name, "watchers") != 0) && + (strcmp (cmd_name, "release") != 0) && + (strcmp (cmd_name, "status") != 0)) + { + ret |= CVS_CMD_MODIFIES_REPOSITORY; + } + + return ret; } @@ -405,7 +438,7 @@ main (argc, argv) int help = 0; /* Has the user asked for help? This lets us support the `cvs -H cmd' convention to give help for cmd. */ - static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa"; + static const char short_options[] = "+QqgrwtnRlvb:T:e:d:Hfz:s:xaU"; static struct option long_options[] = { {"help", 0, NULL, 'H'}, @@ -468,6 +501,12 @@ main (argc, argv) } if (getenv (CVSREAD_ENV) != NULL) cvswrite = 0; + if (getenv (CVSREADONLYFS_ENV) != NULL) { + readonlyfs = 1; + logoff = 1; + } + + prepend_default_options (getenv ("CVS_OPTIONS"), &argc, &argv); /* Set this to 0 to force getopt initialization. getopt() sets this to 1 internally. */ @@ -530,9 +569,20 @@ main (argc, argv) case 'w': cvswrite = 1; break; + case 'g': + /* + * force full group write perms (used for shared checked-out + * source trees, see manual page) + */ + umask(umask(077) & 007); + break; case 't': trace = 1; break; + case 'R': + readonlyfs = 1; + logoff = 1; + break; case 'n': noexec = 1; case 'l': /* Fall through */ @@ -543,7 +593,7 @@ main (argc, argv) version (0, (char **) NULL); (void) fputs ("\n", stdout); (void) fputs ("\ -Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ +Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ Jeff Polk, and other authors\n", stdout); (void) fputs ("\n", stdout); (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); @@ -574,8 +624,6 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ if (CVSroot_cmdline != NULL) free (CVSroot_cmdline); CVSroot_cmdline = xstrdup (optarg); - if (free_CVSroot) - free (CVSroot); CVSroot = xstrdup (optarg); free_CVSroot = 1; cvs_update_env = 1; /* need to update environment */ @@ -618,6 +666,11 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ We will issue an error later if stream authentication is not supported. */ break; + case 'U': +#ifdef SERVER_SUPPORT + require_real_user = 1; +#endif + break; case '?': default: usage (usg); @@ -651,6 +704,15 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ else command_name = cm->fullname; /* Global pointer for later use */ + /* This should probably remain a warning, rather than an error, + for quite a while. For one thing the version of VC distributed + with GNU emacs 19.34 invokes 'cvs rlog' instead of 'cvs log'. */ + if (strcmp (argv[0], "rlog") == 0) + { + error (0, 0, "warning: the rlog command is deprecated"); + error (0, 0, "use the synonymous log command instead"); + } + if (help) { argc = -1; /* some functions only check for this */ @@ -742,6 +804,12 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ (void) putenv (env); /* do not free env, as putenv has control of it */ } + { + char *env; + env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */ + (void) sprintf (env, "CVS_PID=%ld", (long) getpid ()); + (void) putenv (env); + } #endif #ifndef DONT_USE_SIGNALS @@ -799,7 +867,8 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ specify a different repository than the one we are importing to. */ - if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT) + 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. */ @@ -891,29 +960,25 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ variable. Parse it to see if we're supposed to do remote accesses or use a special access method. */ - if (current_parsed_root != NULL) - free_cvsroot_t (current_parsed_root); - if ((current_parsed_root = parse_cvsroot (current_root)) == NULL) + if (parse_cvsroot (current_root)) error (1, 0, "Bad CVSROOT."); if (trace) - fprintf (stderr, "%s-> main loop with CVSROOT=%s\n", - CLIENT_SERVER_STR, current_root); + error (0, 0, "notice: main loop with CVSROOT=%s", + current_root); /* * Check to see if the repository exists. */ -#ifdef CLIENT_SUPPORT - if (!current_parsed_root->isremote) -#endif /* CLIENT_SUPPORT */ + if (!client_active) { char *path; int save_errno; - path = xmalloc (strlen (current_parsed_root->directory) + path = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) - + 2); - (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); + + 20); + (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); if (!isaccessible (path, R_OK | X_OK)) { save_errno = errno; @@ -958,7 +1023,7 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ && !server_active #endif #ifdef CLIENT_SUPPORT - && !current_parsed_root->isremote + && !client_active #endif ) { @@ -966,15 +1031,14 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\ 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 (current_parsed_root->directory); + parse_config (CVSroot_directory); + + /* Now is a convenient time to read CVSROOT/options */ + parseopts(CVSroot_directory); } #ifdef CLIENT_SUPPORT - /* Need to check for current_parsed_root != NULL here since - * we could still be in server mode before the server function - * gets called below and sets the root - */ - if (current_parsed_root != NULL && current_parsed_root->isremote) + if (client_active) { /* Create a new list for directory names that we've sent to the server. */ @@ -1092,55 +1156,31 @@ date_from_time_t (unixtime) void date_to_internet (dest, source) char *dest; - const char *source; + char *source; { - struct tm date; + int year, month, day, hour, minute, second; - date_to_tm (&date, source); - tm_to_internet (dest, &date); -} + /* 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"}; -void -date_to_tm (dest, source) - struct tm *dest; - const char *source; -{ if (sscanf (source, SDATEFORM, - &dest->tm_year, &dest->tm_mon, &dest->tm_mday, - &dest->tm_hour, &dest->tm_min, &dest->tm_sec) - != 6) + &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); - if (dest->tm_year > 100) - dest->tm_year -= 1900; - - dest->tm_mon -= 1; -} - -/* 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. + /* Always send a four digit year. */ + if (year < 100) + year += 1900; - The SOURCE date is a pointer to a struct tm. DEST should point to - storage managed by the caller, at least MAXDATELEN characters. */ -void -tm_to_internet (dest, source) - char *dest; - const struct tm *source; -{ - /* 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"}; - - sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday, - source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon], - source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); + sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", day, + month < 1 || month > 12 ? "???" : month_names[month - 1], + year, hour, minute, second); } void @@ -1152,3 +1192,61 @@ usage (cpp) (void) fprintf (stderr, *cpp); error_exit (); } + +void +parseopts(root) + const char *root; +{ + char path[PATH_MAX]; + int save_errno; + char buf[1024]; + const char *p; + char *q; + FILE *fp; + + if (root == NULL) { + printf("no CVSROOT in parseopts\n"); + return; + } + p = strchr (root, ':'); + if (p) + p++; + else + p = root; + if (p == NULL) { + printf("mangled CVSROOT in parseopts\n"); + return; + } + (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS); + if ((fp = fopen(path, "r")) != NULL) { + while (fgets(buf, sizeof buf, fp) != NULL) { + if (buf[0] == '#') + continue; + q = strrchr(buf, '\n'); + if (q) + *q = '\0'; + + if (!strncmp(buf, "tag=", 4)) { + char *what; + char *rcs_localid; + + rcs_localid = buf + 4; + RCS_setlocalid(rcs_localid); + } + if (!strncmp(buf, "tagexpand=", 10)) { + char *what; + char *rcs_incexc; + + rcs_incexc = buf + 10; + RCS_setincexc(rcs_incexc); + } + /* + * OpenBSD has a "umask=" and "dlimit=" command, we silently + * ignore them here since they are not much use to us. cvsumask + * defaults to 002 already, and the dlimit (data size limit) + * should really be handled elsewhere (eg: login.conf). + */ + } + fclose(fp); + } +} diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c index d1f7ac7..49cda18 100644 --- a/contrib/cvs/src/mkmodules.c +++ b/contrib/cvs/src/mkmodules.c @@ -3,7 +3,10 @@ * 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 kit. */ + * specified in the README file that comes with the CVS kit. + * + * $FreeBSD$ + */ #include "cvs.h" #include "savecwd.h" @@ -848,7 +851,7 @@ init (argc, argv) usage (init_usage); #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) { start_server (); @@ -862,10 +865,12 @@ init (argc, argv) old cvsinit.sh script did. Few utilities do that, and a non-existent parent directory is as likely to be a typo as something which needs to be created. */ - mkdir_if_needed (current_parsed_root->directory); + mkdir_if_needed (CVSroot_directory); - adm = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2); - sprintf (adm, "%s/%s", current_parsed_root->directory, CVSROOTADM); + adm = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + 10); + strcpy (adm, CVSroot_directory); + strcat (adm, "/"); + strcat (adm, CVSROOTADM); mkdir_if_needed (adm); /* This is needed because we pass "fileptr->filename" not "info" diff --git a/contrib/cvs/src/prepend_args.c b/contrib/cvs/src/prepend_args.c new file mode 100644 index 0000000..12322ce --- /dev/null +++ b/contrib/cvs/src/prepend_args.c @@ -0,0 +1,86 @@ +/* prepend_args.c - utilility programs for manpiulating argv[] + Copyright (C) 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* $FreeBSD$ */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "cvs.h" +#include "prepend_args.h" + + +/* Find the white-space-separated options specified by OPTIONS, and + using BUF to store copies of these options, set ARGV[0], ARGV[1], + etc. to the option copies. Return the number N of options found. + Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] + etc. Backslash can be used to escape whitespace (and backslashes). */ +static int +prepend_args (options, buf, argv) + char const *options; + char *buf; + char **argv; +{ + char const *o = options; + char *b = buf; + int n = 0; + + for (;;) + { + while (isspace ((unsigned char) *o)) + o++; + if (!*o) + return n; + if (argv) + argv[n] = b; + n++; + + do + if ((*b++ = *o++) == '\\' && *o) + b[-1] = *o++; + while (*o && ! isspace ((unsigned char) *o)); + + *b++ = '\0'; + } +} + +/* Prepend the whitespace-separated options in OPTIONS to the argument + vector of a main program with argument count *PARGC and argument + vector *PARGV. */ +void +prepend_default_options (options, pargc, pargv) + char const *options; + int *pargc; + char ***pargv; +{ + if (options) + { + char *buf = xmalloc (strlen (options) + 1); + int prepended = prepend_args (options, buf, (char **) NULL); + int argc = *pargc; + char * const *argv = *pargv; + char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); + *pargc = prepended + argc; + *pargv = pp; + *pp++ = *argv++; + pp += prepend_args (options, buf, pp); + while ((*pp++ = *argv++)) + continue; + } +} diff --git a/contrib/cvs/src/prepend_args.h b/contrib/cvs/src/prepend_args.h new file mode 100644 index 0000000..6708442 --- /dev/null +++ b/contrib/cvs/src/prepend_args.h @@ -0,0 +1,26 @@ +/* prepend_args.h - utilility programs for manpiulating argv[] + Copyright (C) 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* $FreeBSD$ */ + +/* This code, taken from GNU Grep, originally used the "PARAM" macro, as the + current GNU coding standards requires. Older GNU code used the "PROTO" + macro, before the GNU coding standards replaced it. We use the older + form here to keep from having to include another file in cvs/src/main.c. */ + +void prepend_default_options PROTO ((char const *, int *, char ***)); diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c index 385eaf2..1e9edce 100644 --- a/contrib/cvs/src/rcs.c +++ b/contrib/cvs/src/rcs.c @@ -6,6 +6,8 @@ * * The routines contained in this file do all the rcs file parsing and * manipulation + * + * $FreeBSD$ */ #include <assert.h> @@ -92,6 +94,11 @@ static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *, size_t, char **, size_t *)); static void cmp_file_buffer PROTO((void *, const char *, size_t)); +enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH}; +static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *, + enum rcs_delta_op, char **, size_t *, + char **, size_t *)); + /* Routines for reading, parsing and writing RCS files. */ static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **, char **)); @@ -120,6 +127,8 @@ static char *rcs_lockfilename PROTO ((char *)); evaluates its arguments multiple times. */ #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0) +static char * getfullCVSname PROTO ((char *, char **)); + /* * We don't want to use isspace() from the C library because: * @@ -2121,7 +2130,7 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag) * -- If tag is a branch tag, returns the branch number, not * the revision of the head of the branch. * If tag or revision is not valid or does not exist in file, - * return NULL. + * exit with error. */ char * RCS_tag2rev (rcs, tag) @@ -2200,8 +2209,9 @@ RCS_tag2rev (rcs, tag) if (rev) return rev; - /* Trust the caller to print warnings. */ - return NULL; + error (1, 0, "tag `%s' does not exist", tag); + /* NOT REACHED -- error (1 ... ) does not return here */ + return 0; } /* @@ -2383,13 +2393,25 @@ RCS_magicrev (rcs, rev) char *rev; { int rev_num; - char *xrev, *test_branch; + char *xrev, *test_branch, *local_branch_num; xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */ check_rev = xrev; + local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM"); + if (local_branch_num) + { + rev_num = atoi(local_branch_num); + if (rev_num < 2) + rev_num = 2; + else + rev_num &= ~1; + } + else + rev_num = 2; + /* only look at even numbered branches */ - for (rev_num = 2; ; rev_num += 2) + for ( ; ; rev_num += 2) { /* see if the physical branch exists */ (void) sprintf (xrev, "%s.%d", rev, rev_num); @@ -2878,8 +2900,10 @@ RCS_getdate (rcs, date, force_tag_match) p = findnode (rcs->versions, "1.1.1.1"); if (p) { + char *date_1_1 = vers->date; + vers = (RCSVers *) p->data; - if (RCS_datecmp (vers->date, date) != 0) + if (RCS_datecmp (vers->date, date_1_1) != 0) return xstrdup ("1.1"); } } @@ -3340,27 +3364,31 @@ struct rcs_keyword { const char *string; size_t len; + int expandit; }; #define KEYWORD_INIT(s) (s), sizeof (s) - 1 -static const struct rcs_keyword keywords[] = +static struct rcs_keyword keywords[] = { - { KEYWORD_INIT ("Author") }, - { KEYWORD_INIT ("Date") }, - { KEYWORD_INIT ("Header") }, - { KEYWORD_INIT ("Id") }, - { KEYWORD_INIT ("Locker") }, - { KEYWORD_INIT ("Log") }, - { KEYWORD_INIT ("Name") }, - { KEYWORD_INIT ("RCSfile") }, - { KEYWORD_INIT ("Revision") }, - { KEYWORD_INIT ("Source") }, - { KEYWORD_INIT ("State") }, - { NULL, 0 } + { KEYWORD_INIT ("Author"), 1 }, + { KEYWORD_INIT ("Date"), 1 }, + { KEYWORD_INIT ("CVSHeader"), 1 }, + { KEYWORD_INIT ("Header"), 1 }, + { KEYWORD_INIT ("Id"), 1 }, + { KEYWORD_INIT ("Locker"), 1 }, + { KEYWORD_INIT ("Log"), 1 }, + { KEYWORD_INIT ("Name"), 1 }, + { KEYWORD_INIT ("RCSfile"), 1 }, + { KEYWORD_INIT ("Revision"), 1 }, + { KEYWORD_INIT ("Source"), 1 }, + { KEYWORD_INIT ("State"), 1 }, + { NULL, 0, 0 }, + { NULL, 0, 0 } }; enum keyword { KEYWORD_AUTHOR = 0, KEYWORD_DATE, + KEYWORD_CVSHEADER, KEYWORD_HEADER, KEYWORD_ID, KEYWORD_LOCKER, @@ -3369,8 +3397,10 @@ enum keyword KEYWORD_RCSFILE, KEYWORD_REVISION, KEYWORD_SOURCE, - KEYWORD_STATE + KEYWORD_STATE, + KEYWORD_LOCALID }; +enum keyword keyword_local = KEYWORD_ID; /* Convert an RCS date string into a readable string. This is like the RCS date2str function. */ @@ -3548,7 +3578,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) slen = s - srch; for (keyword = keywords; keyword->string != NULL; keyword++) { - if (keyword->len == slen + if (keyword->expandit + && keyword->len == slen && strncmp (keyword->string, srch, slen) == 0) { break; @@ -3595,15 +3626,25 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) free_value = 1; break; + case KEYWORD_CVSHEADER: case KEYWORD_HEADER: case KEYWORD_ID: + case KEYWORD_LOCALID: { char *path; int free_path; char *date; + char *old_path; - if (kw == KEYWORD_HEADER) + old_path = NULL; + if (kw == KEYWORD_HEADER || + (kw == KEYWORD_LOCALID && + keyword_local == KEYWORD_HEADER)) path = rcs->path; + else if (kw == KEYWORD_CVSHEADER || + (kw == KEYWORD_LOCALID && + keyword_local == KEYWORD_CVSHEADER)) + path = getfullCVSname(rcs->path, &old_path); else path = last_component (rcs->path); path = escape_keyword_value (path, &free_path); @@ -3623,6 +3664,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) locker != NULL ? locker : ""); if (free_path) free (path); + if (old_path) + free (old_path); free (date); free_value = 1; } @@ -4141,7 +4184,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) whether it should be considered an error for `dest' to exist at this point. If so, the unlink call should be removed and `symlink' should signal the error. -twp) */ - if (CVS_UNLINK (dest) < 0 && !existence_error (errno)) + if (unlink (dest) < 0 && !existence_error (errno)) error (1, errno, "cannot remove %s", dest); if (symlink (info->data, dest) < 0) error (1, errno, "cannot create symbolic link from %s to %s", @@ -4311,7 +4354,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) /* Unlink `dest', just in case. It's okay if this provokes a ENOENT error. */ - if (CVS_UNLINK (dest) < 0 && existence_error (errno)) + if (unlink (dest) < 0 && existence_error (errno)) error (1, errno, "cannot remove %s", dest); if (mknod (dest, special_file, devnum) < 0) error (1, errno, "could not create special file %s", @@ -5254,7 +5297,7 @@ workfile); memset (commitpt->text, 0, sizeof (Deltatext)); bufsize = 0; - switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile)) + switch (diff_exec (workfile, tmpfile, diffopts, changefile)) { case 0: case 1: @@ -5302,7 +5345,7 @@ workfile); /* This file is not being inserted at the head, but on a side branch somewhere. Make a diff from the previous revision to the working file. */ - switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile)) + switch (diff_exec (tmpfile, workfile, diffopts, changefile)) { case 0: case 1: @@ -5682,7 +5725,7 @@ RCS_setbranch (rcs, rev) int RCS_lock (rcs, rev, lock_quiet) RCSNode *rcs; - char *rev; + const char *rev; int lock_quiet; { List *locks; @@ -5701,16 +5744,32 @@ RCS_lock (rcs, rev, lock_quiet) /* A revision number of NULL means lock the head or default branch. */ if (rev == NULL) xrev = RCS_head (rcs); - else - xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); + + /* If rev is a branch number, lock the latest revision on that + branch. I think that if the branch doesn't exist, it's + okay to return 0 -- that just means that the branch is new, + so we don't need to lock it anyway. -twp */ + else if (RCS_nodeisbranch (rcs, rev)) + { + xrev = RCS_getbranch (rcs, (char *) rev, 1); + if (xrev == NULL) + { + if (!lock_quiet) + error (0, 0, "%s: branch %s absent", rcs->path, rev); + return 1; + } + } + + if (xrev == NULL) + xrev = xstrdup (rev); /* Make sure that the desired revision exists. Technically, we can update the locks list without even checking this, but RCS 5.7 did this. And it can't hurt. */ - if (xrev == NULL || findnode (rcs->versions, xrev) == NULL) + if (findnode (rcs->versions, xrev) == NULL) { if (!lock_quiet) - error (0, 0, "%s: revision %s absent", rcs->path, rev); + error (0, 0, "%s: revision %s absent", rcs->path, xrev); free (xrev); return 1; } @@ -5776,7 +5835,7 @@ RCS_lock (rcs, rev, lock_quiet) int RCS_unlock (rcs, rev, unlock_quiet) RCSNode *rcs; - char *rev; + const char *rev; int unlock_quiet; { Node *lock; @@ -5826,15 +5885,20 @@ RCS_unlock (rcs, rev, unlock_quiet) return 0; /* no lock found, ergo nothing to do */ xrev = xstrdup (lock->key); } - else + else if (RCS_nodeisbranch (rcs, rev)) { - xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); + /* If rev is a branch number, unlock the latest revision on that + branch. */ + xrev = RCS_getbranch (rcs, (char *) rev, 1); if (xrev == NULL) { - error (0, 0, "%s: revision %s absent", rcs->path, rev); + error (0, 0, "%s: branch %s absent", rcs->path, rev); return 1; } } + else + /* REV is an exact revision number. */ + xrev = xstrdup (rev); lock = findnode (RCS_getlocks (rcs), xrev); if (lock == NULL) @@ -6356,7 +6420,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive) goto delrev_done; outfile = cvs_temp_name(); - status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile); + status = diff_exec (beforefile, afterfile, "-an", outfile); if (status == 2) { @@ -6995,7 +7059,7 @@ rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen) On error, give a fatal error. */ -void +static void RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen) RCSNode *rcs; FILE *fp; @@ -8354,6 +8418,138 @@ RCS_abandon (rcs) rcs->flags |= PARTIAL; } + +/* Annotate command. In rcs.c for historical reasons (from back when + what is now RCS_deltas was part of annotate_fileproc). */ + +/* Options from the command line. */ + +static int force_tag_match = 1; +static char *tag = NULL; +static char *date = NULL; + +static int annotate_fileproc PROTO ((void *callerdat, struct file_info *)); + +static int +annotate_fileproc (callerdat, finfo) + void *callerdat; + struct file_info *finfo; +{ + FILE *fp = NULL; + struct rcsbuffer *rcsbufp = NULL; + struct rcsbuffer rcsbuf; + char *version; + + if (finfo->rcs == NULL) + return (1); + + if (finfo->rcs->flags & PARTIAL) + { + RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf); + rcsbufp = &rcsbuf; + } + + version = RCS_getversion (finfo->rcs, tag, date, force_tag_match, + (int *) NULL); + if (version == NULL) + return 0; + + /* Distinguish output for various files if we are processing + several files. */ + cvs_outerr ("Annotations for ", 0); + cvs_outerr (finfo->fullname, 0); + cvs_outerr ("\n***************\n", 0); + + RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL, + NULL, NULL, NULL); + free (version); + return 0; +} + +static const char *const annotate_usage[] = +{ + "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n", + "\t-l\tLocal directory only, no recursion.\n", + "\t-R\tProcess directories recursively.\n", + "\t-f\tUse head revision if tag/date not found.\n", + "\t-r rev\tAnnotate file as of specified revision/tag.\n", + "\t-D date\tAnnotate file as of specified date.\n", + "(Specify the --help global option for a list of other help options)\n", + NULL +}; + +/* Command to show the revision, date, and author where each line of a + file was modified. */ + +int +annotate (argc, argv) + int argc; + char **argv; +{ + int local = 0; + int c; + + if (argc == -1) + usage (annotate_usage); + + optind = 0; + while ((c = getopt (argc, argv, "+lr:D:fR")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case 'R': + local = 0; + break; + case 'r': + tag = optarg; + break; + case 'D': + date = Make_Date (optarg); + break; + case 'f': + force_tag_match = 0; + break; + case '?': + default: + usage (annotate_usage); + break; + } + } + argc -= optind; + argv += optind; + +#ifdef CLIENT_SUPPORT + if (client_active) + { + start_server (); + ign_setup (); + + if (local) + send_arg ("-l"); + if (!force_tag_match) + send_arg ("-f"); + option_with_arg ("-r", tag); + if (date) + client_senddate (date); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); + send_to_server ("annotate\012", 0); + return get_responses_and_close (); + } +#endif /* CLIENT_SUPPORT */ + + if (tag != NULL) + tag_check_valid (tag, argc, argv, local, 0, ""); + + return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, + argc, argv, local, W_LOCAL, 0, 1, (char *)NULL, + 1); +} + /* * For a given file with full pathname PATH and revision number REV, * produce a file label suitable for passing to diff. The default @@ -8363,11 +8559,6 @@ RCS_abandon (rcs) * * The date and time used are the revision's last checkin date and time. * If REV is NULL, use the working copy's mtime instead. - * - * /dev/null is not statted but assumed to have been created on the Epoch. - * At least using the POSIX.2 definition of patch, this should cause creation - * of files on platforms such as Windoze where the null IO device isn't named - * /dev/null to be parsed by patch properly. */ char * make_file_label (path, rev, rcs) @@ -8375,47 +8566,141 @@ make_file_label (path, rev, rcs) char *rev; RCSNode *rcs; { - char datebuf[MAXDATELEN + 1]; + char datebuf[MAXDATELEN]; char *label; + char *file; + file = last_component (path); label = (char *) xmalloc (strlen (path) - + (rev == NULL ? 0 : strlen (rev) + 1) - + MAXDATELEN - + 2); + + (rev == NULL ? 0 : strlen (rev)) + + 50); if (rev) { - char date[MAXDATELEN + 1]; - /* revs cannot be attached to /dev/null ... duh. */ - assert (strcmp(DEVNULL, path)); + char *date; RCS_getrevtime (rcs, rev, datebuf, 0); - (void) date_to_internet (date, datebuf); + date = printable_date (datebuf); (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev); + free (date); } else { struct stat sb; - struct tm *wm = NULL; + struct tm *wm; - if (strcmp(DEVNULL, path)) + if (CVS_STAT (file, &sb) < 0) + error (0, 1, "could not get info for `%s'", path); + else { - char *file = last_component (path); - if (CVS_STAT (file, &sb) < 0) - error (0, 1, "could not get info for `%s'", path); - else - wm = gmtime (&sb.st_mtime); + wm = gmtime (&sb.st_mtime); + (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d", + wm->tm_year + 1900, wm->tm_mon + 1, + wm->tm_mday, wm->tm_hour, + wm->tm_min, wm->tm_sec); + (void) sprintf (label, "-L%s\t%s", path, datebuf); } + } + return label; +} + +void +RCS_setlocalid (arg) + const char *arg; +{ + char *copy, *next, *key; + + copy = xstrdup(arg); + next = copy; + key = strtok(next, "="); + + keywords[KEYWORD_LOCALID].string = xstrdup(key); + keywords[KEYWORD_LOCALID].len = strlen(key); + keywords[KEYWORD_LOCALID].expandit = 1; + + /* options? */ + while (key = strtok(NULL, ",")) { + if (!strcmp(key, keywords[KEYWORD_ID].string)) + keyword_local = KEYWORD_ID; + else if (!strcmp(key, keywords[KEYWORD_HEADER].string)) + keyword_local = KEYWORD_HEADER; + else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string)) + keyword_local = KEYWORD_CVSHEADER; else + error(1, 0, "Unknown LocalId mode: %s", key); + } + free(copy); +} + +void +RCS_setincexc (arg) + const char *arg; +{ + char *key; + char *copy, *next; + int include = 0; + struct rcs_keyword *keyword; + + copy = xstrdup(arg); + next = copy; + switch (*next++) { + case 'e': + include = 0; + break; + case 'i': + include = 1; + break; + default: + free(copy); + return; + } + + if (include) + for (keyword = keywords; keyword->string != NULL; keyword++) { - time_t t = 0; - wm = gmtime(&t); + keyword->expandit = 0; } - if (wm) - { - (void) tm_to_internet (datebuf, wm); - (void) sprintf (label, "-L%s\t%s", path, datebuf); + key = strtok(next, ","); + while (key) { + for (keyword = keywords; keyword->string != NULL; keyword++) { + if (strcmp (keyword->string, key) == 0) + keyword->expandit = include; } + key = strtok(NULL, ","); } - return label; + free(copy); + return; +} + +#define ATTIC "/" CVSATTIC +static char * +getfullCVSname(CVSname, pathstore) + char *CVSname, **pathstore; +{ + if (CVSroot_directory) { + int rootlen; + char *c = NULL; + int alen = sizeof(ATTIC) - 1; + + *pathstore = xstrdup(CVSname); + if ((c = strrchr(*pathstore, '/')) != NULL) { + if (c - *pathstore >= alen) { + if (!strncmp(c - alen, ATTIC, alen)) { + while (*c != '\0') { + *(c - alen) = *c; + c++; + } + *(c - alen) = '\0'; + } + } + } + + rootlen = strlen(CVSroot_directory); + if (!strncmp(*pathstore, CVSroot_directory, rootlen) && + (*pathstore)[rootlen] == '/') + CVSname = (*pathstore + rootlen + 1); + else + CVSname = (*pathstore); + } + return CVSname; } diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h index 55eed95..397488e 100644 --- a/contrib/cvs/src/rcs.h +++ b/contrib/cvs/src/rcs.h @@ -6,6 +6,8 @@ * specified in the README file that comes with the CVS source distribution. * * RCS source control definitions needed by rcs.c and friends + * + * $FreeBSD$ */ /* Strings which indicate a conflict if they occur at the start of a line. */ @@ -179,9 +181,6 @@ typedef void (*RCSCHECKOUTPROC) PROTO ((void *, const char *, size_t)); struct rcsbuffer; #endif -/* What RCS_deltas is supposed to do. */ -enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH}; - /* * exported interfaces */ @@ -226,8 +225,8 @@ int RCS_cmp_file PROTO ((RCSNode *, char *, char *, const char *)); int RCS_settag PROTO ((RCSNode *, const char *, const char *)); int RCS_deltag PROTO ((RCSNode *, const char *)); int RCS_setbranch PROTO((RCSNode *, const char *)); -int RCS_lock PROTO ((RCSNode *, char *, int)); -int RCS_unlock PROTO ((RCSNode *, char *, int)); +int RCS_lock PROTO ((RCSNode *, const char *, int)); +int RCS_unlock PROTO ((RCSNode *, const char *, int)); int RCS_delete_revs PROTO ((RCSNode *, char *, char *, int)); void RCS_addaccess PROTO ((RCSNode *, char *)); void RCS_delaccess PROTO ((RCSNode *, char *)); @@ -237,9 +236,9 @@ void RCS_rewrite PROTO ((RCSNode *, Deltatext *, char *)); void RCS_abandon PROTO ((RCSNode *)); int rcs_change_text PROTO ((const char *, char *, size_t, const char *, size_t, char **, size_t *)); -void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *, - enum rcs_delta_op, char **, size_t *, - char **, size_t *)); +void RCS_setincexc PROTO ((const char *arg)); + +void RCS_setlocalid PROTO ((const char *arg)); char *make_file_label PROTO ((char *, char *, RCSNode *)); extern int preserve_perms; diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c index 43be168..bcdffd5 100644 --- a/contrib/cvs/src/rcscmds.c +++ b/contrib/cvs/src/rcscmds.c @@ -7,6 +7,8 @@ * * The functions in this file provide an interface for performing * operations directly on RCS files. + * + * $FreeBSD$ */ #include "cvs.h" @@ -530,11 +532,9 @@ RCS file: ", 0); message on stderr. */ int -diff_exec (file1, file2, label1, label2, options, out) +diff_exec (file1, file2, options, out) char *file1; char *file2; - char *label1; - char *label2; char *options; char *out; { @@ -577,10 +577,6 @@ diff_exec (file1, file2, label1, label2, options, out) /* The first word in this string is used only for error reporting. */ sprintf (args, "diff %s", options); call_diff_setup (args); - if (label1) - call_diff_arg (label1); - if (label2) - call_diff_arg (label2); call_diff_arg (file1); call_diff_arg (file2); free (args); diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c index 2235193..09e1cad 100644 --- a/contrib/cvs/src/recurse.c +++ b/contrib/cvs/src/recurse.c @@ -6,6 +6,7 @@ * * General recursion handler * + * $FreeBSD$ */ #include "cvs.h" @@ -157,10 +158,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, #ifdef CLIENT_SUPPORT if (!just_subdirs && CVSroot_cmdline == NULL - && current_parsed_root->isremote) + && client_active) { char *root = Name_Root (NULL, update_dir); - if (root && strcmp (root, current_parsed_root->original) != 0) + if (root && strcmp (root, current_root) != 0) /* We're skipping this directory because it is for a different root. Therefore, we just want to do the subdirectories only. Processing files would @@ -204,7 +205,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, program_name); } #ifdef CLIENT_SUPPORT - else if (current_parsed_root->isremote && server_started) + else if (client_active && server_started) { /* In the the case "cvs update foo bar baz", a call to send_file_names in update.c will have sent the @@ -290,7 +291,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, { if ((which & W_LOCAL) && isdir (CVSADM) #ifdef CLIENT_SUPPORT - && !current_parsed_root->isremote + && !client_active #endif ) { @@ -363,8 +364,8 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, /* FIXME (njc): in the multiroot case, we don't want to send argument commands for those top-level directories which do not contain any subdirectories which have files checked out - from current_parsed_root->original. If we do, and two repositories - have a module with the same name, nasty things could happen. + from current_root. If we do, and two repositories have a + module with the same name, nasty things could happen. This is hard. Perhaps we should send the Argument commands later in this procedure, after we've had a chance to notice @@ -440,7 +441,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, "Directory xxx" command, which forces the server to descend and serve the files there. client.c (send_file_names) has also been modified to send only those arguments which are - appropriate to current_parsed_root->original. + appropriate to current_root. */ @@ -599,9 +600,8 @@ do_recursion (frame) } - process_this_directory = - (strcmp (current_parsed_root->original, this_root) == 0); - + process_this_directory = (strcmp (current_root, this_root) == 0); + free (this_root); } } @@ -711,7 +711,7 @@ do_recursion (frame) place (server_notify). For local, we can't do them here--we don't have writelocks in place, and there is no way to get writelocks here. */ - if (current_parsed_root->isremote) + if (client_active) notify_check (repository, update_dir); #endif /* CLIENT_SUPPORT */ @@ -1025,8 +1025,7 @@ but CVS uses %s for its own purposes; skipping %s directory", } - process_this_directory = (strcmp (current_parsed_root->original, this_root) == 0); - + process_this_directory = (strcmp (current_root, this_root) == 0); free (this_root); } } diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c index bb38f4d..a53dc79 100644 --- a/contrib/cvs/src/server.c +++ b/contrib/cvs/src/server.c @@ -8,6 +8,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +/* + * $FreeBSD$ + */ + #include <assert.h> #include "cvs.h" #include "watch.h" @@ -16,19 +20,50 @@ #include "getline.h" #include "buffer.h" -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -# ifdef HAVE_GSSAPI -/* This stuff isn't included solely with SERVER_SUPPORT since some of these - * functions (encryption & the like) get compiled with or without server - * support. - * - * FIXME - They should be in a different file. - */ -# include <netdb.h> -# include "xgssapi.h" +#ifdef SERVER_SUPPORT + +#ifdef HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) +#include <sys/socket.h> +#endif + +#ifdef HAVE_KERBEROS +# include <netinet/in.h> +# include <krb.h> +# ifndef HAVE_KRB_GET_ERR_TEXT +# define krb_get_err_text(status) krb_err_txt[status] +# endif + +/* Information we need if we are going to use Kerberos encryption. */ +static C_Block kblock; +static Key_schedule sched; + +#endif + +#ifdef HAVE_GSSAPI + +#include <netdb.h> + +#ifdef HAVE_GSSAPI_H +#include <gssapi.h> +#endif +#ifdef HAVE_GSSAPI_GSSAPI_H +#include <gssapi/gssapi.h> +#endif +#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +#include <gssapi/gssapi_generic.h> +#endif + +#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif + /* We use Kerberos 5 routines to map the GSSAPI credential to a user name. */ -# include <krb5.h> +#include <krb5.h> /* We need this to wrap data. */ static gss_ctx_id_t gcontext; @@ -38,45 +73,36 @@ static void gserver_authenticate_connection PROTO((void)); /* Whether we are already wrapping GSSAPI communication. */ static int cvs_gssapi_wrapping; -# ifdef ENCRYPTION +# ifdef ENCRYPTION /* Whether to encrypt GSSAPI communication. We use a global variable like this because we use the same buffer type (gssapi_wrap) to handle both authentication and encryption, and we don't want multiple instances of that buffer in the communication stream. */ int cvs_gssapi_encrypt; -# endif -# endif /* HAVE_GSSAPI */ -#endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */ - -#ifdef SERVER_SUPPORT - -#ifdef HAVE_WINSOCK_H -#include <winsock.h> -#endif +# endif -#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) -#include <sys/socket.h> #endif -#ifdef HAVE_SYSLOG_H -#include <syslog.h> +/* for select */ +#include <sys/types.h> +#ifdef HAVE_SYS_BSDTYPES_H +#include <sys/bsdtypes.h> #endif -#ifdef HAVE_KERBEROS -# include <netinet/in.h> -# include <krb.h> -# ifndef HAVE_KRB_GET_ERR_TEXT -# define krb_get_err_text(status) krb_err_txt[status] +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> # endif - -/* Information we need if we are going to use Kerberos encryption. */ -static C_Block kblock; -static Key_schedule sched; - #endif -/* for select */ -#include "xselect.h" +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY @@ -90,16 +116,18 @@ static Key_schedule sched; #define blocking_error(err) ((err) == EAGAIN) #endif +#ifdef AUTH_SERVER_SUPPORT +#ifdef HAVE_GETSPNAM +#include <shadow.h> +#endif +#endif /* AUTH_SERVER_SUPPORT */ + /* For initgroups(). */ #if HAVE_INITGROUPS #include <grp.h> #endif /* HAVE_INITGROUPS */ - -# ifdef AUTH_SERVER_SUPPORT - -# ifdef HAVE_GETSPNAM -# include <shadow.h> -# endif + +#ifdef AUTH_SERVER_SUPPORT /* The cvs username sent by the client, which might or might not be the same as the system username the server eventually switches to @@ -115,7 +143,7 @@ static char *Pserver_Repos = NULL; CVSROOT/config. */ int system_auth = 1; -# endif /* AUTH_SERVER_SUPPORT */ +#endif /* AUTH_SERVER_SUPPORT */ /* While processing requests, this buffer accumulates data to be sent to @@ -396,10 +424,10 @@ create_adm_p (base_dir, dir) differently. */ char *empty; - empty = malloc (strlen (current_parsed_root->directory) + empty = malloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + sizeof (CVSNULLREPOS) - + 3); + + 10); if (! empty) { retval = ENOMEM; @@ -407,7 +435,7 @@ create_adm_p (base_dir, dir) } /* Create the directory name. */ - (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory, + (void) sprintf (empty, "%s/%s/%s", CVSroot_directory, CVSROOTADM, CVSNULLREPOS); /* Create the directory if it doesn't exist. */ @@ -573,16 +601,10 @@ print_error (status) int status; { char *msg; - char tmpstr[80]; - buf_output0 (buf_to_net, "error "); msg = strerror (status); - if (msg == NULL) - { - sprintf (tmpstr, "unknown error %d", status); - msg = tmpstr; - } - buf_output0 (buf_to_net, msg); + if (msg) + buf_output0 (buf_to_net, msg); buf_append_char (buf_to_net, '\n'); buf_flush (buf_to_net, 0); @@ -749,7 +771,7 @@ serve_root (arg) new connection. Doing this would cause interoperability headaches, so it should be a different request, if there is any reason why such a feature is needed. */ - if (current_parsed_root != NULL) + if (CVSroot_directory != NULL) { if (alloc_pending (80 + strlen (arg))) sprintf (pending_error_text, @@ -772,24 +794,24 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", } } #endif - - if (current_parsed_root != NULL) - free_cvsroot_t (current_parsed_root); - current_parsed_root = local_cvsroot (arg); + set_local_cvsroot (arg); /* For pserver, this will already have happened, and the call will do nothing. But for rsh, we need to do it now. */ - parse_config (current_parsed_root->directory); + parse_config (CVSroot_directory); - path = malloc (strlen (current_parsed_root->directory) + /* Now is a good time to read CVSROOT/options too. */ + parseopts(CVSroot_directory); + + path = malloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) - + 2); + + 10); if (path == NULL) { pending_error = ENOMEM; return; } - (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); + (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); if (!isaccessible (path, R_OK | X_OK)) { int save_errno = errno; @@ -800,13 +822,13 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", free (path); #ifdef HAVE_PUTENV - env = malloc (strlen (CVSROOT_ENV) + strlen (current_parsed_root->directory) + 2); + env = malloc (strlen (CVSROOT_ENV) + strlen (CVSroot_directory) + 1 + 1); if (env == NULL) { pending_error = ENOMEM; return; } - (void) sprintf (env, "%s=%s", CVSROOT_ENV, current_parsed_root->directory); + (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot_directory); (void) putenv (env); /* do not free env, as putenv has control of it */ #endif @@ -849,14 +871,14 @@ server_pathname_check (path) static int outside_root PROTO ((char *)); /* Is file or directory REPOS an absolute pathname within the - current_parsed_root->directory? If yes, return 0. If no, set pending_error + CVSroot_directory? If yes, return 0. If no, set pending_error and return 1. */ static int outside_root (repos) char *repos; { size_t repos_len = strlen (repos); - size_t root_len = strlen (current_parsed_root->directory); + size_t root_len = strlen (CVSroot_directory); /* I think isabsolute (repos) should always be true, and that any RELATIVE_REPOS stuff should only be in CVS/Repository @@ -871,15 +893,15 @@ E protocol error: %s is not absolute", repos); } if (repos_len < root_len - || strncmp (current_parsed_root->directory, repos, root_len) != 0) + || strncmp (CVSroot_directory, repos, root_len) != 0) { not_within: - if (alloc_pending (strlen (current_parsed_root->directory) + if (alloc_pending (strlen (CVSroot_directory) + strlen (repos) + 80)) sprintf (pending_error_text, "\ E protocol error: directory '%s' not within root '%s'", - repos, current_parsed_root->directory); + repos, CVSroot_directory); return 1; } if (repos_len > root_len) @@ -1082,9 +1104,8 @@ dirswitch (dir, repos) (e.g., an entry like ``world -a .'') by putting /. at the end of the Repository file, so we do the same. */ if (strcmp (dir, ".") == 0 - && current_parsed_root != NULL - && current_parsed_root->directory != NULL - && strcmp (current_parsed_root->directory, repos) == 0) + && CVSroot_directory != NULL + && strcmp (CVSroot_directory, repos) == 0) { if (fprintf (f, "/.") < 0) { @@ -2414,9 +2435,6 @@ error ENOMEM Virtual memory exhausted.\n"; /* If this gives an error, not much we could do. syslog() it? */ write (STDOUT_FILENO, msg, sizeof (msg) - 1); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted"); -#endif error_exit (); } @@ -2474,13 +2492,13 @@ check_command_legal_p (cmd_name) int found_it = 0; /* else */ - flen = strlen (current_parsed_root->directory) + flen = strlen (CVSroot_directory) + strlen (CVSROOTADM) + strlen (CVSROOTADM_READERS) + 3; fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, + (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, CVSROOTADM, CVSROOTADM_READERS); fp = fopen (fname, "r"); @@ -2526,13 +2544,13 @@ check_command_legal_p (cmd_name) /* Now check the writers file. */ - flen = strlen (current_parsed_root->directory) + flen = strlen (CVSroot_directory) + strlen (CVSROOTADM) + strlen (CVSROOTADM_WRITERS) + 3; fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, + (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, CVSROOTADM, CVSROOTADM_WRITERS); fp = fopen (fname, "r"); @@ -2774,9 +2792,7 @@ error \n"); close (stderr_pipe[0]); close (stderr_pipe[1]); close (protocol_pipe[0]); - close_on_exec (protocol_pipe[1]); #ifdef SERVER_FLOWCONTROL - close_on_exec (flowcontrol_pipe[0]); close (flowcontrol_pipe[1]); #endif /* SERVER_FLOWCONTROL */ @@ -2793,11 +2809,11 @@ error \n"); exitstatus = (*command) (argument_count, argument_vector); /* Output any partial lines. If the client doesn't support - "MT", we go ahead and just tack on a newline since the - protocol doesn't support anything better. */ - if (! buf_empty_p (saved_output)) + "MT", we just throw out the partial line, like old versions + of CVS did, since the protocol can't support this. */ + if (supported_response ("MT") && ! buf_empty_p (saved_output)) { - buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M "); + buf_output0 (protocol, "MT text "); buf_append_buffer (protocol, saved_output); buf_output (protocol, "\n", 1); buf_send_counted (protocol); @@ -2820,7 +2836,7 @@ error \n"); struct buffer *protocol_inbuf; /* Number of file descriptors to check in select (). */ int num_to_check; - int count_needed = 1; + int count_needed = 0; #ifdef SERVER_FLOWCONTROL int have_flowcontrolled = 0; #endif /* SERVER_FLOWCONTROL */ @@ -2908,16 +2924,13 @@ error \n"); while (stdout_pipe[0] >= 0 || stderr_pipe[0] >= 0 - || protocol_pipe[0] >= 0 - || count_needed <= 0) + || protocol_pipe[0] >= 0) { fd_set readfds; fd_set writefds; int numfds; #ifdef SERVER_FLOWCONTROL int bufmemsize; - struct timeval *timeout_ptr; - struct timeval timeout; /* * See if we are swamping the remote client and filling our VM. @@ -2938,24 +2951,8 @@ error \n"); FD_ZERO (&readfds); FD_ZERO (&writefds); - - if (count_needed <= 0) - { - /* there is data pending which was read from the protocol pipe - * so don't block if we don't find any data - */ - timeout.tv_sec = 0; - timeout.tv_usec = 0; - timeout_ptr = &timeout; - } - else - { - /* block indefinately */ - timeout_ptr = NULL; - } - if (! buf_empty_p (buf_to_net)) - FD_SET (STDOUT_FILENO, &writefds); + FD_SET (STDOUT_FILENO, &writefds); if (stdout_pipe[0] >= 0) { @@ -2971,34 +2968,28 @@ error \n"); } /* This process of selecting on the three pipes means that - we might not get output in the same order in which it - was written, thus producing the well-known - "out-of-order" bug. If the child process uses - cvs_output and cvs_outerr, it will send everything on - the protocol_pipe and avoid this problem, so the - solution is to use cvs_output and cvs_outerr in the - child process. */ + we might not get output in the same order in which it + was written, thus producing the well-known + "out-of-order" bug. If the child process uses + cvs_output and cvs_outerr, it will send everything on + the protocol_pipe and avoid this problem, so the + solution is to use cvs_output and cvs_outerr in the + child process. */ do { /* This used to select on exceptions too, but as far as I know there was never any reason to do that and SCO doesn't let you select on exceptions on pipes. */ numfds = select (num_to_check, &readfds, &writefds, - (fd_set *)0, timeout_ptr); + (fd_set *)0, (struct timeval *)NULL); if (numfds < 0 - && errno != EINTR) + && errno != EINTR) { buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); goto error_exit; } } while (numfds < 0); - - if (numfds == 0) - { - FD_ZERO (&readfds); - FD_ZERO (&writefds); - } - + if (FD_ISSET (STDOUT_FILENO, &writefds)) { /* What should we do with errors? syslog() them? */ @@ -3010,6 +3001,7 @@ error \n"); { int status; int count_read; + int special; status = buf_input_data (protocol_inbuf, &count_read); @@ -3032,49 +3024,29 @@ error \n"); * have. */ count_needed -= count_read; - } - /* this is still part of the protocol pipe procedure, but it is - * outside the above conditional so that unprocessed data can be - * left in the buffer and stderr/stdout can be read when a flush - * signal is received and control can return here without passing - * through the select code and maybe blocking - */ - while (count_needed <= 0) - { - int special = 0; - - count_needed = buf_copy_counted (buf_to_net, + while (count_needed <= 0) + { + count_needed = buf_copy_counted (buf_to_net, protocol_inbuf, &special); - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); - /* If SPECIAL got set to <0, it means that the child - * wants us to flush the pipe & maybe stderr or stdout. - * - * After that we break to read stderr & stdout again before - * going back to the protocol pipe - * - * Upon breaking, count_needed = 0, so the next pass will only - * perform a non-blocking select before returning here to finish - * processing data we already read from the protocol buffer - */ - if (special == -1) - { - cvs_flushout(); - break; - } - if (special == -2) - { - /* If the client supports the 'F' command, we send it. */ - if (supported_response ("F")) + /* If SPECIAL got set to -1, it means that the child + wants us to flush the pipe. We don't want to block + on the network, but we flush what we can. If the + client supports the 'F' command, we send it. */ + if (special == -1) { - buf_append_char (buf_to_net, 'F'); - buf_append_char (buf_to_net, '\n'); + if (supported_response ("F")) + { + buf_append_char (buf_to_net, 'F'); + buf_append_char (buf_to_net, '\n'); + } + + cvs_flusherr (); } - cvs_flusherr (); - break; } } @@ -3461,11 +3433,6 @@ server_scratch (fname) * two different cases. Using the last one which happens is almost * surely correct; I haven't tracked down why they both happen (or * even verified that they are for the same file). - * - * Don't know if this is what whoever wrote the above comment was - * talking about, but this can happen in the case where a join - * removes a file - the call to Register puts the '-vers' into the - * Entries file after the file is removed */ if (entries_line != NULL) { @@ -3625,15 +3592,6 @@ serve_log (arg) } static void -serve_rlog (arg) - char *arg; -{ - /* Tell cvslog() to behave like rlog not log. */ - command_name = "rlog"; - do_cvs_command ("rlog", cvslog); -} - -static void serve_add (arg) char *arg; { @@ -3672,9 +3630,7 @@ static void serve_rtag (arg) char *arg; { - /* Tell cvstag() to behave like rtag not tag. */ - command_name = "rtag"; - do_cvs_command ("rtag", cvstag); + do_cvs_command ("rtag", rtag); } static void @@ -3798,10 +3754,7 @@ serve_init (arg) /* Fall through to do_cvs_command which will return the actual error. */ } - - if (current_parsed_root != NULL) - free_cvsroot_t (current_parsed_root); - current_parsed_root = local_cvsroot (arg); + set_local_cvsroot (arg); do_cvs_command ("init", init); } @@ -3814,17 +3767,6 @@ serve_annotate (arg) { do_cvs_command ("annotate", annotate); } - -static void serve_rannotate PROTO ((char *)); - -static void -serve_rannotate (arg) - char *arg; -{ - /* Tell annotate() to behave like rannotate not annotate. */ - command_name = "rannotate"; - do_cvs_command ("rannotate", annotate); -} static void serve_co (arg) @@ -4222,23 +4164,6 @@ CVS server internal error: unhandled case in server_updated"); output_dir (finfo->update_dir, finfo->repository); buf_output0 (protocol, finfo->file); buf_output (protocol, "\n", 1); - /* keep the vers structure up to date in case we do a join - * - if there isn't a file, it can't very well have a version number, can it? - * - * we do it here on the assumption that since we just told the client - * to remove the file/entry, it will, and we want to remember that. - * If it fails, that's the client's problem, not ours - */ - if (vers && vers->vn_user != NULL) - { - free (vers->vn_user); - vers->vn_user = NULL; - } - if (vers && vers->ts_user != NULL) - { - free (vers->ts_user); - vers->ts_user = NULL; - } } else if (scratched_file == NULL && entries_line == NULL) { @@ -4572,7 +4497,7 @@ serve_expand_modules (arg) for (i = 1; i < argument_count; i++) err += do_module (db, argument_vector[i], CHECKOUT, "Updating", expand_proc, - NULL, 0, 0, 0, 0, + NULL, 0, 0, 0, (char *) NULL); close_module (db); server_expanding = 0; @@ -4773,7 +4698,6 @@ struct request requests[] = REQ_LINE("update", serve_update, RQ_ESSENTIAL), REQ_LINE("diff", serve_diff, 0), REQ_LINE("log", serve_log, 0), - REQ_LINE("rlog", serve_rlog, 0), REQ_LINE("add", serve_add, 0), REQ_LINE("remove", serve_remove, 0), REQ_LINE("update-patches", serve_ignore, 0), @@ -4795,7 +4719,6 @@ struct request requests[] = REQ_LINE("editors", serve_editors, 0), REQ_LINE("init", serve_init, RQ_ROOTLESS), REQ_LINE("annotate", serve_annotate, 0), - REQ_LINE("rannotate", serve_rannotate, 0), REQ_LINE("noop", serve_noop, RQ_ROOTLESS), REQ_LINE("version", serve_version, RQ_ROOTLESS), REQ_LINE(NULL, NULL, 0) @@ -4829,7 +4752,7 @@ serve_valid_requests (arg) buf_flush (buf_to_net, 1); } -#ifdef SUNOS_KLUDGE +#ifdef sun /* * Delete temporary files. SIG is the signal making this happen, or * 0 if not called as a result of a signal. @@ -4843,7 +4766,7 @@ static void wait_sig (sig) if (r == command_pid) command_pid_is_dead++; } -#endif /* SUNOS_KLUDGE */ +#endif void server_cleanup (sig) @@ -4887,7 +4810,7 @@ server_cleanup (sig) /* What a bogus kludge. This disgusting code makes all kinds of assumptions about SunOS, and is only for a bug in that system. So only enable it on Suns. */ -#ifdef SUNOS_KLUDGE +#ifdef sun if (command_pid > 0) { /* To avoid crashes on SunOS due to bugs in SunOS tmpfs @@ -4960,7 +4883,7 @@ server_cleanup (sig) } } } -#endif /* SUNOS_KLUDGE */ +#endif CVS_CHDIR (Tmpdir); /* Temporarily clear noexec, so that we clean up our temp directory @@ -5098,25 +5021,19 @@ error ENOMEM Virtual memory exhausted.\n"); pending_error = status; } #ifndef CHMOD_BROKEN - else if (chmod (server_temp_dir, S_IRWXU) < 0) + else { - int save_errno = errno; - if (alloc_pending (80 + strlen (server_temp_dir))) - sprintf (pending_error_text, + if (chmod (server_temp_dir, S_IRWXU) < 0) + { + int save_errno = errno; + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, "E cannot change permissions on temporary directory %s", - server_temp_dir); - pending_error = save_errno; + server_temp_dir); + pending_error = save_errno; + } } #endif - else if (CVS_CHDIR (server_temp_dir) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (server_temp_dir))) - sprintf (pending_error_text, -"E cannot change to temporary directory %s", - server_temp_dir); - pending_error = save_errno; - } } } @@ -5212,7 +5129,7 @@ error ENOMEM Virtual memory exhausted.\n"); continue; if (!(rq->flags & RQ_ROOTLESS) - && current_parsed_root == NULL) + && CVSroot_directory == NULL) { /* For commands which change the way in which data is sent and received, for example Gzip-stream, @@ -5346,10 +5263,10 @@ error 0 %s: no such user\n", username); #endif #if HAVE_PUTENV - /* Set LOGNAME, USER and CVS_USER in the environment, in case they - are already set to something else. */ + /* Set LOGNAME and USER in the environment, in case they are + already set to something else. */ { - char *env, *cvs_user; + char *env; env = xmalloc (sizeof "LOGNAME=" + strlen (username)); (void) sprintf (env, "LOGNAME=%s", username); @@ -5358,11 +5275,6 @@ error 0 %s: no such user\n", username); env = xmalloc (sizeof "USER=" + strlen (username)); (void) sprintf (env, "USER=%s", username); (void) putenv (env); - - cvs_user = NULL != CVS_Username ? CVS_Username : ""; - env = xmalloc (sizeof "CVS_USER=" + strlen (cvs_user)); - (void) sprintf (env, "CVS_USER=%s", cvs_user); - (void) putenv (env); } #endif /* HAVE_PUTENV */ } @@ -5397,7 +5309,7 @@ check_repository_password (username, password, repository, host_user_ptr) int found_it = 0; int namelen; - /* We don't use current_parsed_root->directory because it hasn't been set yet + /* We don't use CVSroot_directory because it hasn't been set yet * -- our `repository' argument came from the authentication * protocol, not the regular CVS protocol. */ @@ -5539,7 +5451,10 @@ check_password (username, password, repository) password file. If so, that's enough to authenticate with. If not, we'll check /etc/passwd. */ - rc = check_repository_password (username, password, repository, + if (require_real_user) + rc = 0; /* "not found" */ + else + rc = check_repository_password (username, password, repository, &host_user); if (rc == 2) @@ -5727,13 +5642,8 @@ pserver_authenticate_connection () { int on = 1; - if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on) < 0) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); -#endif - } + (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof on); } #endif @@ -5789,13 +5699,13 @@ pserver_authenticate_connection () error (1, 0, "bad auth protocol end: %s", tmp); } if (!root_allow_ok (repository)) - { - printf ("error 0 %s: no such repository\n", repository); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository); -#endif + /* Just give a generic I HATE YOU. This is because CVS 1.9.10 + and older clients do not support "error". Once more recent + clients are more widespread, probably want to fix this (it is + a real pain to track down why it isn't letting you in if it + won't say why, and I am not convinced that the potential + information disclosure to an attacker outweighs this). */ goto i_hate_you; - } /* OK, now parse the config file, so we can use it to control how to check passwords. If there was an error parsing the config @@ -5811,13 +5721,6 @@ pserver_authenticate_connection () free (descrambled_password); if (host_user == NULL) { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository); -#ifdef LOG_AUTHPRIV - syslog (LOG_AUTHPRIV | LOG_NOTICE, "login failure by %s / %s (for %s)", - username, descrambled_password, repository); -#endif -#endif i_hate_you: printf ("I HATE YOU\n"); fflush (stdout); @@ -5899,13 +5802,8 @@ error %s getpeername or getsockname failed\n", strerror (errno)); { int on = 1; - if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on) < 0) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); -#endif - } + (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof on); } #endif @@ -6501,20 +6399,13 @@ cvs_flusherr () #ifdef SERVER_SUPPORT if (error_use_protocol) { - /* skip the actual stderr flush in this case since the parent process - * on the server should only be writing to stdout anyhow - */ /* Flush what we can to the network, but don't block. */ buf_flush (buf_to_net, 0); } else if (server_active) { - /* make sure stderr is flushed before we send the flush count on the - * protocol pipe - */ - fflush (stderr); /* Send a special count to tell the parent to flush. */ - buf_send_special_count (protocol, -2); + buf_send_special_count (protocol, -1); } else #endif @@ -6540,13 +6431,7 @@ cvs_flushout () cvs_flushout replaces, setting stdout to line buffering in main.c, didn't get called in the server child process. But in the future it is quite plausible that we'll want to make - this case work analogously to cvs_flusherr. - - FIXME - DRP - I tried to implement this and triggered the following - error: "Protocol error: uncounted data discarded". I don't need - this feature right now, so I'm not going to bother with it yet. - */ - buf_send_special_count (protocol, -1); + this case work analogously to cvs_flusherr. */ } else #endif diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c index f4b919f..bec2397 100644 --- a/contrib/cvs/src/update.c +++ b/contrib/cvs/src/update.c @@ -31,6 +31,8 @@ * versions, these are updated too. If the -d option was specified, new * directories added to the repository are automatically created and updated * as well. + * + * $FreeBSD$ */ #include "cvs.h" @@ -58,7 +60,7 @@ static int patch_file PROTO ((struct file_info *finfo, static void patch_file_write PROTO ((void *, const char *, size_t)); #endif static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers)); -static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers)); +static int scratch_file PROTO((struct file_info *finfo)); static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir, char *repository, char *update_dir, List *entries)); @@ -99,7 +101,6 @@ static int force_tag_match = 1; static int update_build_dirs = 0; static int update_prune_dirs = 0; static int pipeout = 0; -static int dotemplate = 0; #ifdef SERVER_SUPPORT static int patches = 0; static int rcs_diff_patches = 0; @@ -108,7 +109,7 @@ static List *ignlist = (List *) NULL; static time_t last_register_time; static const char *const update_usage[] = { - "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n", + "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n", " [-I ign] [-W spec] [files...]\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-P\tPrune empty directories.\n", @@ -118,7 +119,7 @@ static const char *const update_usage[] = "\t-l\tLocal directory only, no recursion.\n", "\t-R\tProcess directories recursively.\n", "\t-p\tSend updates to standard output (avoids stickiness).\n", - "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", + "\t-k kopt\tUse RCS kopt -k option on checkout.\n", "\t-r rev\tUpdate using specified revision/tag (is sticky).\n", "\t-D date\tSet date to update from (is sticky).\n", "\t-j rev\tMerge in changes made between current revision and rev.\n", @@ -234,7 +235,7 @@ update (argc, argv) argv += optind; #ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) + if (client_active) { int pass; @@ -410,7 +411,7 @@ update (argc, argv) /* call the command line interface */ err = do_update (argc, argv, options, tag, date, force_tag_match, local, update_build_dirs, aflag, update_prune_dirs, - pipeout, which, join_rev1, join_rev2, (char *) NULL, 1); + pipeout, which, join_rev1, join_rev2, (char *) NULL); /* free the space Make_Date allocated if necessary */ if (date != NULL) @@ -424,8 +425,7 @@ update (argc, argv) */ int do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, - xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir, - xdotemplate) + xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir) int argc; char **argv; char *xoptions; @@ -441,7 +441,6 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, char *xjoin_rev1; char *xjoin_rev2; char *preload_update_dir; - int xdotemplate; { int err = 0; char *cp; @@ -455,7 +454,6 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, aflag = xaflag; update_prune_dirs = xprune; pipeout = xpipeout; - dotemplate = xdotemplate; /* setup the join support */ join_rev1 = xjoin_rev1; @@ -507,15 +505,11 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, argc, argv, local, which, aflag, 1, preload_update_dir, 1); -#ifdef SERVER_SUPPORT - if (server_active) - return err; -#endif - /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - sleep_past (last_register_time); + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return (err); @@ -583,6 +577,9 @@ update_fileproc (callerdat, finfo) int retval; Ctype status; Vers_TS *vers; + int resurrecting; + + resurrecting = 0; status = Classify_File (finfo, tag, date, options, force_tag_match, aflag, &vers, pipeout); @@ -595,7 +592,7 @@ update_fileproc (callerdat, finfo) && tag != NULL && finfo->rcs != NULL) { - char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL); + char *rev = RCS_getversion (finfo->rcs, tag, date, 1, NULL); if (rev != NULL && !RCS_nodeisbranch (finfo->rcs, tag)) nonbranch = 1; @@ -628,7 +625,9 @@ update_fileproc (callerdat, finfo) case T_MODIFIED: /* locally modified */ case T_REMOVED: /* removed but not committed */ case T_CHECKOUT: /* needs checkout */ +#ifdef SERVER_SUPPORT case T_PATCH: /* needs patch */ +#endif retval = checkout_file (finfo, vers, 0, 0, 0); break; @@ -653,12 +652,8 @@ update_fileproc (callerdat, finfo) write_letter (finfo, 'C'); break; case T_NEEDS_MERGE: /* needs merging */ - if (! toss_local_changes) - { - retval = merge_file (finfo, vers); - break; - } - /* else FALL THROUGH */ + retval = merge_file (finfo, vers); + break; case T_MODIFIED: /* locally modified */ retval = 0; if (toss_local_changes) @@ -738,8 +733,8 @@ update_fileproc (callerdat, finfo) } } break; - case T_PATCH: /* needs patch */ #ifdef SERVER_SUPPORT + case T_PATCH: /* needs patch */ if (patches) { int docheckout; @@ -761,11 +756,11 @@ update_fileproc (callerdat, finfo) break; } } -#endif /* If we're not running as a server, just check the file out. It's simpler and faster than producing and applying patches. */ /* Fall through. */ +#endif case T_CHECKOUT: /* needs checkout */ retval = checkout_file (finfo, vers, 0, 0, 1); break; @@ -778,7 +773,18 @@ update_fileproc (callerdat, finfo) retval = 0; break; case T_REMOVE_ENTRY: /* needs to be un-registered */ - retval = scratch_file (finfo, vers); + retval = scratch_file (finfo); +#ifdef SERVER_SUPPORT + if (server_active && retval == 0) + { + if (vers->ts_user == NULL) + server_scratch_entry_only (); + server_updated (finfo, vers, + SERVER_UPDATED, (mode_t) -1, + (unsigned char *) NULL, + (struct buffer *) NULL); + } +#endif break; default: /* can't ever happen :-) */ error (0, 0, @@ -793,7 +799,7 @@ update_fileproc (callerdat, finfo) join_file (finfo, vers); /* if this directory has an ignore list, add this file to it */ - if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL)) + if (ignlist) { Node *p; @@ -873,7 +879,7 @@ update_filesdone_proc (callerdat, err, repository, update_dir, entries) { /* If there is no CVS/Root file, add one */ if (!isfile (CVSADM_ROOT)) - Create_Root ((char *) NULL, current_parsed_root->original); + Create_Root ((char *) NULL, CVSroot_original); } return (err); @@ -966,7 +972,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries) via WriteTag. */ 0, 0, - dotemplate); + 1); rewrite_tag = 1; nonbranch = 0; Subdir_Register (entries, (char *) NULL, dir); @@ -1169,7 +1175,7 @@ isemptydir (dir, might_not_exist) return (0); } errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) + while ((dp = readdir (dirp)) != NULL) { if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0) @@ -1178,7 +1184,7 @@ isemptydir (dir, might_not_exist) { /* An entry other than the CVS directory. The directory is certainly not empty. */ - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); return (0); } else @@ -1209,7 +1215,7 @@ isemptydir (dir, might_not_exist) { /* There are files that have been removed, but not committed! Do not consider the directory empty. */ - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); return (0); } } @@ -1219,10 +1225,10 @@ isemptydir (dir, might_not_exist) if (errno != 0) { error (0, errno, "cannot read directory %s", dir); - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); return (0); } - (void) CVS_CLOSEDIR (dirp); + (void) closedir (dirp); return (1); } @@ -1230,46 +1236,13 @@ isemptydir (dir, might_not_exist) * scratch the Entries file entry associated with a file */ static int -scratch_file (finfo, vers) +scratch_file (finfo) struct file_info *finfo; - Vers_TS *vers; { history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository); Scratch_Entry (finfo->entries, finfo->file); -#ifdef SERVER_SUPPORT - if (server_active) - { - if (vers->ts_user == NULL) - server_scratch_entry_only (); - server_updated (finfo, vers, - SERVER_UPDATED, (mode_t) -1, - (unsigned char *) NULL, - (struct buffer *) NULL); - } -#endif if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) error (0, errno, "unable to remove %s", finfo->fullname); - else -#ifdef SERVER_SUPPORT - /* skip this step when the server is running since - * server_updated should have handled it */ - if (!server_active) -#endif - { - /* keep the vers structure up to date in case we do a join - * - if there isn't a file, it can't very well have a version number, can it? - */ - if (vers->vn_user != NULL) - { - free (vers->vn_user); - vers->vn_user = NULL; - } - if (vers->ts_user != NULL) - { - free (vers->ts_user); - vers->ts_user = NULL; - } - } return (0); } @@ -1769,7 +1742,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum) diff_options = "-n"; } - retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file); + retcode = diff_exec (file1, file2, diff_options, finfo->file); /* A retcode of 0 means no differences. 1 means some differences. */ if (retcode != 0 @@ -2135,17 +2108,6 @@ join_file (finfo, vers) char *jdate1; char *jdate2; - if (trace) - fprintf (stderr, "%s-> join_file(%s, %s%s%s%s, %s, %s)\n", - CLIENT_SERVER_STR, - finfo->file, - vers->tag ? vers->tag : "", - vers->tag ? " (" : "", - vers->vn_rcs ? vers->vn_rcs : "", - vers->tag ? ")" : "", - join_rev1 ? join_rev1 : "", - join_rev2 ? join_rev2 : ""); - jrev1 = join_rev1; jrev2 = join_rev2; jdate1 = date_rev1; @@ -2314,14 +2276,7 @@ join_file (finfo, vers) for removal. FIXME: If we are doing a checkout, this has the effect of first checking out the file, and then removing it. It would be better to just register the - removal. - - The same goes for a removal then an add. e.g. - cvs up -rbr -jbr2 could remove and readd the same file - */ - /* save the rev since server_updated might invalidate it */ - mrev = xmalloc (strlen (vers->vn_user) + 2); - sprintf (mrev, "-%s", vers->vn_user); + removal. */ #ifdef SERVER_SUPPORT if (server_active) { @@ -2330,6 +2285,8 @@ join_file (finfo, vers) (unsigned char *) NULL, (struct buffer *) NULL); } #endif + mrev = xmalloc (strlen (vers->vn_user) + 2); + sprintf (mrev, "-%s", vers->vn_user); Register (finfo->entries, finfo->file, mrev, vers->ts_rcs, vers->options, vers->tag, vers->date, vers->ts_conflict); free (mrev); @@ -2372,7 +2329,6 @@ join_file (finfo, vers) addition. */ if (vers->vn_user == NULL) { - char *saved_options = options; Vers_TS *xvers; xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); @@ -2387,7 +2343,6 @@ join_file (finfo, vers) /* FIXME: If checkout_file fails, we should arrange to return a non-zero exit status. */ status = checkout_file (finfo, xvers, 1, 0, 1); - options = saved_options; freevers_ts (&xvers); |