summaryrefslogtreecommitdiffstats
path: root/contrib/cvs
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2001-08-10 09:53:06 +0000
committerpeter <peter@FreeBSD.org>2001-08-10 09:53:06 +0000
commit75f7ac20d05fc07bd23bbbaa37a5066b87ca87bb (patch)
tree9d465dbd69e6033ab4d69e284056926039b7890c /contrib/cvs
parentc132709d1892a50d7915da8685face38ada32e4f (diff)
downloadFreeBSD-src-75f7ac20d05fc07bd23bbbaa37a5066b87ca87bb.zip
FreeBSD-src-75f7ac20d05fc07bd23bbbaa37a5066b87ca87bb.tar.gz
Initial merge of cvs-1.11 -> 1.11.1p1 changes onto mainline. There is
still some suspicious and/or broken stuff to fix yet.
Diffstat (limited to 'contrib/cvs')
-rw-r--r--contrib/cvs/diff/diff3.c67
-rw-r--r--contrib/cvs/src/client.c343
-rw-r--r--contrib/cvs/src/commit.c84
-rw-r--r--contrib/cvs/src/cvs.h56
-rw-r--r--contrib/cvs/src/diff.c116
-rw-r--r--contrib/cvs/src/filesubr.c241
-rw-r--r--contrib/cvs/src/import.c28
-rw-r--r--contrib/cvs/src/lock.c22
-rw-r--r--contrib/cvs/src/login.c758
-rw-r--r--contrib/cvs/src/logmsg.c35
-rw-r--r--contrib/cvs/src/main.c221
-rw-r--r--contrib/cvs/src/mkmodules.c10
-rw-r--r--contrib/cvs/src/rcs.c246
-rw-r--r--contrib/cvs/src/rcs.h11
-rw-r--r--contrib/cvs/src/rcscmds.c8
-rw-r--r--contrib/cvs/src/recurse.c24
-rw-r--r--contrib/cvs/src/server.c447
-rw-r--r--contrib/cvs/src/update.c131
18 files changed, 1624 insertions, 1224 deletions
diff --git a/contrib/cvs/diff/diff3.c b/contrib/cvs/diff/diff3.c
index ab68eaf..dc89606 100644
--- a/contrib/cvs/diff/diff3.c
+++ b/contrib/cvs/diff/diff3.c
@@ -174,7 +174,7 @@ static int edscript;
static int flagging;
/* Number of lines to keep in identical prefix and suffix. */
-static int horizon_lines = 10;
+static int const horizon_lines = 10;
/* Use a tab to align output lines (-T). */
static int tab_align_flag;
@@ -373,28 +373,44 @@ diff3_run (argc, argv, out, callbacks_arg)
file0-file1 diffs didn't line up with the file0-file2 diffs
(which is entirely possible since we don't use diff's -n option),
diff3 might report phantom changes from file1 to file2. */
+ /* Also try to compare file0 to file1 because this is the where
+ changes are expected to come from. Diffing between these pairs
+ of files is is most likely to return the intended changes. There
+ can also be the same problem with phantom changes from file0 to
+ file1. */
+ /* Historically, the default common file was file2. Ediff for emacs
+ and possibly other applications, have therefore made file2 the
+ ancestor. So, for compatibility, if this is simply a three
+ way diff (not a merge or edscript) then use the old way with
+ file2 as the common file. */
+
+ {
+ int common;
+ if (edscript || merge )
+ {
+ common = 1;
+ }
+ else
+ {
+ common = 2;
+ }
+ if (strcmp (file[common], "-") == 0)
+ {
+ /* Sigh. We've got standard input as the arg corresponding to
+ the desired common file. We can't call diff twice on
+ stdin. Use another arg as the common file instead. */
+ common = 3 - common;
+ if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
+ {
+ diff_error ("%s", "`-' specified for more than one input file", 0);
+ return 2;
+ }
+ }
- if (strcmp (file[2], "-") == 0)
- {
- /* Sigh. We've got standard input as the last arg. We can't
- call diff twice on stdin. Use the middle arg as the common
- file instead. */
- if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0)
- {
- diff_error ("%s", "`-' specified for more than one input file", 0);
- return 2;
- }
- mapping[0] = 0;
- mapping[1] = 2;
- mapping[2] = 1;
- }
- else
- {
- /* Normal, what you'd expect */
- mapping[0] = 0;
- mapping[1] = 1;
- mapping[2] = 2;
- }
+ mapping[0] = 0;
+ mapping[1] = 3 - common;
+ mapping[2] = common;
+ }
for (i = 0; i < 3; i++)
rev_mapping[mapping[i]] = i;
@@ -447,12 +463,18 @@ diff3_run (argc, argv, out, callbacks_arg)
commonname = file[rev_mapping[FILEC]];
thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block,
&content1);
+ /* What is the intention behind determining horizon_lines from first
+ diff? I think it is better to use the same parameters for each
+ diff so that equal differences in each diff will appear the
+ same. */
+ /*
if (thread1)
for (i = 0; i < 2; i++)
{
horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
}
+ */
thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block,
&content0);
diff3 = make_3way_diff (thread0, thread1);
@@ -1858,7 +1880,6 @@ initialize_main (argcp, argvp)
always_text = 0;
edscript = 0;
flagging = 0;
- horizon_lines = 10;
tab_align_flag = 0;
simple_only = 0;
overlap_only = 0;
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index 525cb79..d166c60 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -36,6 +36,7 @@
# else /* No winsock.h */
# include <sys/socket.h>
# include <netinet/in.h>
+# include <arpa/inet.h>
# include <netdb.h>
# endif /* No winsock.h */
#endif
@@ -81,19 +82,7 @@ static Key_schedule sched;
#ifdef HAVE_GSSAPI
-#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
+# include "xgssapi.h"
/* This is needed for GSSAPI encryption. */
static gss_ctx_id_t gcontext;
@@ -101,7 +90,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. */
@@ -202,7 +191,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 */
@@ -267,8 +256,8 @@ arg_should_not_be_sent_to_server (arg)
}
/* Now check the value for root. */
- if (CVSroot_cmdline == NULL && this_root && current_root
- && (strcmp (this_root, current_root) != 0))
+ if (CVSroot_cmdline == NULL && this_root && current_parsed_root
+ && (strcmp (this_root, current_parsed_root->original) != 0))
{
/* Don't send this, since the CVSROOTs don't match. */
free (this_root);
@@ -1281,6 +1270,32 @@ 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)
{
@@ -2286,7 +2301,7 @@ static int
is_cvsroot_level (pathname)
char *pathname;
{
- if (strcmp (toplevel_repos, CVSroot_directory) != 0)
+ if (strcmp (toplevel_repos, current_parsed_root->directory) != 0)
return 0;
return strchr (pathname, '/') == NULL;
@@ -2926,14 +2941,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"
- CVSroot_directory, set toplevel_repos to
- CVSroot_directory. */
+ current_parsed_root->directory, set toplevel_repos to
+ current_parsed_root->directory. */
if ((repository_len > update_dir_len)
&& (strcmp (repository + repository_len - update_dir_len,
update_dir) == 0)
- /* TOPLEVEL_REPOS shouldn't be above CVSroot_directory */
+ /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */
&& ((repository_len - update_dir_len)
- > strlen (CVSroot_directory)))
+ > strlen (current_parsed_root->directory)))
{
/* The repository name contains UPDATE_DIR. Set
toplevel_repos to the repository name without
@@ -2947,7 +2962,7 @@ send_a_repository (dir, repository, update_dir)
}
else
{
- toplevel_repos = xstrdup (CVSroot_directory);
+ toplevel_repos = xstrdup (current_parsed_root->directory);
}
}
}
@@ -3005,7 +3020,7 @@ client_expand_modules (argc, argv, local)
for (i = 0; i < argc; ++i)
send_arg (argv[i]);
- send_a_repository ("", CVSroot_directory, "");
+ send_a_repository ("", current_parsed_root->directory, "");
send_to_server ("expand-modules\012", 0);
@@ -3043,13 +3058,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 ("", CVSroot_directory, "");
+ send_a_repository ("", current_parsed_root->directory, "");
}
void
client_nonexpanded_setup ()
{
- send_a_repository ("", CVSroot_directory, "");
+ send_a_repository ("", current_parsed_root->directory, "");
}
/* Receive a cvswrappers line from the server; it must be a line
@@ -3564,7 +3579,8 @@ get_responses_and_close ()
{
if (shutdown (server_fd, 1) < 0)
error (1, 0, "shutting down connection to %s: %s",
- CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO));
+ current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+ server_fd = -1;
/*
* This test will always be true because we dup the descriptor
*/
@@ -3573,7 +3589,7 @@ get_responses_and_close ()
if (fclose (to_server_fp) != 0)
error (1, errno,
"closing down connection to %s",
- CVSroot_hostname);
+ current_parsed_root->hostname);
}
}
else
@@ -3591,15 +3607,15 @@ get_responses_and_close ()
#endif /* START_RSH_WITH_POPEN_RW */
{
error (1, errno, "closing connection to %s",
- CVSroot_hostname);
+ current_parsed_root->hostname);
}
}
if (! buf_empty_p (from_server)
|| getc (from_server_fp) != EOF)
- error (0, 0, "dying gasps from %s unexpected", CVSroot_hostname);
+ error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
else if (ferror (from_server_fp))
- error (0, errno, "reading from %s", CVSroot_hostname);
+ error (0, errno, "reading from %s", current_parsed_root->hostname);
fclose (from_server_fp);
#endif /* SHUTDOWN_SERVER */
@@ -3616,8 +3632,7 @@ get_responses_and_close ()
/* see if we need to sleep before returning to avoid time-stamp races */
if (last_register_time)
{
- while (time ((time_t *) NULL) == last_register_time)
- sleep (1);
+ sleep_past (last_register_time);
}
return errs;
@@ -3641,7 +3656,8 @@ 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));
@@ -3670,22 +3686,86 @@ init_sockaddr (name, hostname, port)
#endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) */
-#ifdef AUTH_CLIENT_SUPPORT
-static int auth_server_port_number PROTO ((void));
+#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 ()
+get_port_number (envname, portname, defaultport)
+ const char *envname;
+ const char *portname;
+ int defaultport;
{
- struct servent *s = getservbyname ("cvspserver", "tcp");
+ struct servent *s;
+ char *port_s;
- if (s)
+ 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")))
return ntohs (s->s_port);
else
- return CVS_AUTH_PORT;
+ return defaultport;
+}
+
+
+
+/* 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.
@@ -3713,7 +3793,7 @@ recv_line (sock, resultp)
int n;
n = recv (sock, &ch, 1, 0);
if (n <= 0)
- error (1, 0, "recv() from server %s: %s", CVSroot_hostname,
+ error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname,
n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
if (ch == '\012')
@@ -3751,11 +3831,15 @@ connect_to_forked_server (tofdp, fromfdp)
command[0] = getenv ("CVS_SERVER");
if (! command[0])
- command[0] = "cvs";
+ command[0] = program_path;
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");
}
@@ -3783,20 +3867,29 @@ 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 = auth_server_port_number ();
- hostinfo = init_sockaddr (&client_sai, CVSroot_hostname, port_number);
+ 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);
+ }
if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai))
< 0)
- error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname,
+ error (1, 0, "connect to %s(%s):%d failed: %s",
+ current_parsed_root->hostname,
+ inet_ntoa (client_sai.sin_addr),
port_number, SOCK_STRERROR (SOCK_ERRNO));
/* Run the authorization mini-protocol before anything else. */
@@ -3804,7 +3897,12 @@ 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
@@ -3812,11 +3910,9 @@ 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";
@@ -3830,7 +3926,8 @@ 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)
@@ -3844,7 +3941,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, repository, strlen (repository), 0) < 0)
+ if (send (sock, current_parsed_root->directory, strlen (current_parsed_root->directory), 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));
@@ -3875,7 +3972,29 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
if (strcmp (read_buf, "I HATE YOU") == 0)
{
- /* Authorization not granted. */
+ /* 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");
+ }
goto rejected;
}
else if (strncmp (read_buf, "E ", 2) == 0)
@@ -3913,15 +4032,15 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
{
error (0, 0,
"unrecognized auth response from %s: %s",
- CVSroot_hostname, read_buf);
+ current_parsed_root->hostname, read_buf);
error (1, 0,
"shutdown() failed, server %s: %s",
- CVSroot_hostname,
+ current_parsed_root->hostname,
SOCK_STRERROR (SOCK_ERRNO));
}
error (1, 0,
"unrecognized auth response from %s: %s",
- CVSroot_hostname, read_buf);
+ current_parsed_root->hostname, read_buf);
}
free (read_buf);
}
@@ -3930,7 +4049,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", CVSroot_hostname,
+ error (0, 0, "shutdown() failed, server %s: %s", current_parsed_root->hostname,
SOCK_STRERROR (SOCK_ERRNO));
return;
}
@@ -3955,24 +4074,11 @@ 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",
- CVSroot_hostname,
+ current_parsed_root->hostname,
SOCK_STRERROR (SOCK_ERRNO));
}
@@ -3980,8 +4086,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
}
#endif /* AUTH_CLIENT_SUPPORT */
-
-#if HAVE_KERBEROS
+
+
+#ifdef 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
@@ -4003,42 +4110,26 @@ start_tcp_server (tofdp, fromfdp)
if (s < 0)
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
- /* 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);
- }
+ port = get_cvs_port_number (current_parsed_root);
- hp = init_sockaddr (&sin, CVSroot_hostname, port);
+ hp = init_sockaddr (&sin, current_parsed_root->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:%d failed: %s", CVSroot_hostname,
+ error (1, 0, "connect to %s(%s):%d failed: %s",
+ current_parsed_root->hostname,
+ inet_ntoa (client_sai.sin_addr),
port, SOCK_STRERROR (SOCK_ERRNO));
-#ifdef HAVE_KERBEROS
{
const char *realm;
struct sockaddr_in laddr;
@@ -4063,7 +4154,6 @@ 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);
@@ -4092,9 +4182,10 @@ recv_bytes (sock, buf, need)
int got;
got = recv (sock, buf, need, 0);
- if (got < 0)
- error (1, 0, "recv() from server %s: %s", CVSroot_hostname,
- SOCK_STRERROR (SOCK_ERRNO));
+ if (got <= 0)
+ error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname,
+ got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
+
buf += got;
need -= got;
}
@@ -4187,11 +4278,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",
- CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO));
+ current_parsed_root->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", CVSroot_hostname,
+ error (1, 0, "error from server %s: %s", current_parsed_root->hostname,
buf);
}
@@ -4243,7 +4334,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 (CVSroot_method)
+ switch (current_parsed_root->method)
{
#ifdef AUTH_CLIENT_SUPPORT
@@ -4260,7 +4351,7 @@ start_server ()
break;
#endif
-#if HAVE_GSSAPI
+#ifdef HAVE_GSSAPI
case gserver_method:
/* GSSAPI authentication is handled by the pserver. */
connect_to_pserver (&tofd, &fromfd, 0, 1);
@@ -4279,8 +4370,8 @@ start_server ()
case server_method:
#if defined(START_SERVER)
START_SERVER (&tofd, &fromfd, getcaller (),
- CVSroot_username, CVSroot_hostname,
- CVSroot_directory);
+ current_parsed_root->username, current_parsed_root->hostname,
+ current_parsed_root->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
@@ -4411,7 +4502,7 @@ the :server: access method is not supported by this port of CVS");
if (!rootless)
{
send_to_server ("Root ", 0);
- send_to_server (CVSroot_directory, 0);
+ send_to_server (current_parsed_root->directory, 0);
send_to_server ("\012", 1);
}
@@ -4541,7 +4632,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 (CVSroot_method == kserver_method)
+ if (current_parsed_root->method == kserver_method)
{
if (! supported_request ("Kerberos-encrypt"))
error (1, 0, "This server does not support encryption");
@@ -4556,7 +4647,7 @@ the :server: access method is not supported by this port of CVS");
else
#endif /* HAVE_KERBEROS */
#ifdef HAVE_GSSAPI
- if (CVSroot_method == gserver_method)
+ if (current_parsed_root->method == gserver_method)
{
if (! supported_request ("Gssapi-encrypt"))
error (1, 0, "This server does not support encryption");
@@ -4629,7 +4720,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 (CVSroot_method == gserver_method)
+ if (current_parsed_root->method == gserver_method)
{
if (! supported_request ("Gssapi-authenticate"))
error (1, 0,
@@ -4733,13 +4824,13 @@ start_rsh_server (tofdp, fromfdp)
#endif /* RSH_NEEDS_BINARY_FLAG */
/* Then we strcat more things on the end one by one. */
- if (CVSroot_username != NULL)
+ if (current_parsed_root->username != NULL)
{
rsh_argv[i++] = "-l";
- rsh_argv[i++] = CVSroot_username;
+ rsh_argv[i++] = current_parsed_root->username;
}
- rsh_argv[i++] = CVSroot_hostname;
+ rsh_argv[i++] = current_parsed_root->hostname;
rsh_argv[i++] = cvs_server;
rsh_argv[i++] = "server";
@@ -4749,6 +4840,8 @@ 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);
}
@@ -4786,7 +4879,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 (CVSroot_directory)
+ + strlen (current_parsed_root->directory)
+ 50);
/* If you are running a very old (Nov 3, 1994, before 1.5)
@@ -4800,15 +4893,15 @@ start_rsh_server (tofdp, fromfdp)
char **p = argv;
*p++ = cvs_rsh;
- *p++ = CVSroot_hostname;
+ *p++ = current_parsed_root->hostname;
/* If the login names differ between client and server
* pass it on to rsh.
*/
- if (CVSroot_username != NULL)
+ if (current_parsed_root->username != NULL)
{
*p++ = "-l";
- *p++ = CVSroot_username;
+ *p++ = current_parsed_root->username;
}
*p++ = command;
@@ -5535,7 +5628,7 @@ send_files (argc, argv, local, aflag, flags)
* latter case; I don't think toplevel_repos matters for the
* former.
*/
- toplevel_repos = xstrdup (CVSroot_directory);
+ toplevel_repos = xstrdup (current_parsed_root->directory);
send_repository ("", toplevel_repos, ".");
}
@@ -5654,7 +5747,7 @@ client_import_done ()
*/
/* FIXME: "can't happen" now that we call client_import_setup
at the beginning. */
- toplevel_repos = xstrdup (CVSroot_directory);
+ toplevel_repos = xstrdup (current_parsed_root->directory);
send_repository ("", toplevel_repos, ".");
}
@@ -5834,9 +5927,9 @@ client_senddate (date)
void
send_init_command ()
{
- /* This is here because we need the CVSroot_directory variable. */
+ /* This is here because we need the current_parsed_root->directory variable. */
send_to_server ("init ", 0);
- send_to_server (CVSroot_directory, 0);
+ send_to_server (current_parsed_root->directory, 0);
send_to_server ("\012", 0);
}
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 3d46e25..226b09b 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -86,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",
- "\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",
+ " -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",
"(Specify the --help global option for a list of other help options)\n",
NULL
};
@@ -345,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. */
- && !client_active
+ && !current_parsed_root->isremote
# endif
)
{
@@ -433,7 +433,7 @@ commit (argc, argv)
}
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
struct find_data find_args;
@@ -592,8 +592,7 @@ commit (argc, argv)
char *fname;
FILE *fp;
- fname = cvs_temp_name ();
- fp = CVS_FOPEN (fname, "w+");
+ fp = cvs_temp_file (&fname);
if (fp == NULL)
error (1, 0, "cannot create temporary file %s", fname);
if (fwrite (saved_message, 1, strlen (saved_message), fp)
@@ -602,6 +601,7 @@ 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;
}
@@ -616,7 +616,7 @@ commit (argc, argv)
wrap_setup ();
- lock_tree_for_write (argc, argv, local, aflag);
+ lock_tree_for_write (argc, argv, local, W_LOCAL, aflag);
/*
* Set up the master update list and hard link list
@@ -664,11 +664,15 @@ 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)
{
- while (time ((time_t *) NULL) == last_register_time)
- sleep (1);
+ sleep_past (last_register_time);
}
return (err);
@@ -779,7 +783,7 @@ check_fileproc (callerdat, finfo)
struct commit_info *ci;
struct logfile_info *li;
- size_t cvsroot_len = strlen (CVSroot_directory);
+ size_t cvsroot_len = strlen (current_parsed_root->directory);
if (!finfo->repository)
{
@@ -787,7 +791,7 @@ check_fileproc (callerdat, finfo)
return (1);
}
- if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0
+ if (strncmp (finfo->repository, current_parsed_root->directory, cvsroot_len) == 0
&& ISDIRSEP (finfo->repository[cvsroot_len])
&& strncmp (finfo->repository + cvsroot_len + 1,
CVSROOTADM,
@@ -811,9 +815,7 @@ 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:
@@ -830,7 +832,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
+ * a branch or head is dead
* - 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
@@ -927,29 +929,17 @@ warning: file `%s' seems to still contain conflict indicators",
{
if (vers->tag == NULL)
{
- 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))
+ if (finfo->rcs != NULL &&
+ !RCS_isdead (finfo->rcs, finfo->rcs->head))
{
error (0, 0,
"cannot add file `%s' when RCS file `%s' already exists",
- finfo->fullname, rcs);
+ finfo->fullname, finfo->rcs->path);
freevers_ts (&vers);
- free (rcs);
return (1);
}
- free (rcs);
}
- if (vers->tag && isdigit ((unsigned char) *vers->tag) &&
+ else if (isdigit ((unsigned char) *vers->tag) &&
numdots (vers->tag) > 1)
{
error (0, 0,
@@ -1312,6 +1302,12 @@ 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);
@@ -1431,12 +1427,12 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
{
char *p;
- if (strncmp (CVSroot_directory, repository,
- strlen (CVSroot_directory)) != 0)
+ if (strncmp (current_parsed_root->directory, repository,
+ strlen (current_parsed_root->directory)) != 0)
error (0, 0,
"internal error: repository (%s) doesn't begin with root (%s)",
- repository, CVSroot_directory);
- p = repository + strlen (CVSroot_directory);
+ repository, current_parsed_root->directory);
+ p = repository + strlen (current_parsed_root->directory);
if (*p == '/')
++p;
if (strcmp ("CVSROOT", p) == 0
@@ -1597,19 +1593,13 @@ 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);
@@ -1957,10 +1947,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
Attic. */
if (!(rcsfile->flags & INATTIC))
{
- error (0, 0, "internal error: confused about attic for %s",
+ error (0, 0, "warning: expected %s to be in Attic",
rcsfile->path);
- retval = 1;
- goto out;
}
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index 6489f07..8ce1cef 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -318,7 +318,7 @@ typedef struct entnode Entnode;
/* The type of request that is being done in do_module() */
enum mtype
{
- CHECKOUT, TAG, PATCH, EXPORT
+ CHECKOUT, TAG, PATCH, EXPORT, MISC
};
/*
@@ -371,28 +371,34 @@ extern char *RCS_citag;
/* Access method specified in CVSroot. */
typedef enum {
- local_method, server_method, pserver_method, kserver_method, gserver_method,
+ null_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 char *current_root;
+extern cvsroot_t *current_parsed_root;
extern char *emptydir_name PROTO ((void));
extern int safe_location PROTO ((void));
@@ -429,8 +435,9 @@ 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 *options,
- char *out));
+extern int diff_exec PROTO ((char *file1, char *file2,
+ char *label1, char *label2,
+ char *options, char *out));
extern int diff_execv PROTO ((char *file1, char *file2,
char *label1, char *label2,
char *options, char *out));
@@ -450,15 +457,18 @@ 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 *, char *));
+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 *));
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));
-int parse_cvsroot PROTO((char *CVSroot));
-void set_local_cvsroot PROTO((char *dir));
+void free_cvsroot_t PROTO((cvsroot_t *root_in));
+cvsroot_t *parse_cvsroot PROTO((char *root));
+cvsroot_t *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));
@@ -472,6 +482,7 @@ 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));
@@ -494,6 +505,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));
@@ -518,7 +530,8 @@ 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 aflag));
+void lock_tree_for_write PROTO ((int argc, char **argv, int local, int which,
+ int aflag));
/* See lock.c for description. */
extern void lock_dir_for_write PROTO ((char *));
@@ -555,7 +568,6 @@ 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
@@ -635,7 +647,8 @@ 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, char *extra_arg));
+ int local_specified, int run_module_prog, int build_dirs,
+ 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,
@@ -653,7 +666,10 @@ 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 */
@@ -783,9 +799,7 @@ 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;
@@ -875,6 +889,8 @@ 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 15353e63..f24101b 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -119,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, 148},
+ {"initial-tab", 0, 0, 'T'},
{"width", 1, 0, 'W'},
{"text", 0, 0, 'a'},
{"ignore-space-change", 0, 0, 'b'},
@@ -140,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, 147},
+ {"side-by-side", 0, 0, 'y'},
{"unified", 2, 0, 146},
{"left-column", 0, 0, 129},
{"suppress-common-lines", 0, 0, 130},
@@ -188,28 +188,6 @@ 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;
@@ -248,18 +226,19 @@ diff (argc, argv)
optind = 0;
while ((c = getopt_long (argc, argv,
- "+abcdefhilnpstuw0123456789BHNRC:D:F:I:L:U:V:W:k:r:",
+ "+abcdefhilnpstuwy0123456789BHNRTC: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 '0': case '1': case '2':
- case '3': case '4': case '5': case '6': case '7': case '8':
- case '9': case 'B': case 'H':
+ 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':
(void) sprintf (tmp, " -%c", (char) c);
- strcat_and_allocate (&opts, &opts_allocated, tmp);
+ allocate_and_strcat (&opts, &opts_allocated, tmp);
break;
case 'L':
if (have_rev1_label++)
@@ -269,32 +248,31 @@ diff (argc, argv)
break;
}
- strcat_and_allocate (&opts, &opts_allocated, " -L");
- strcat_and_allocate (&opts, &opts_allocated, optarg);
+ allocate_and_strcat (&opts, &opts_allocated, " -L");
+ allocate_and_strcat (&opts, &opts_allocated, optarg);
break;
case 'C': case 'F': case 'I': case 'U': case 'V': case 'W':
(void) sprintf (tmp, " -%c", (char) c);
- strcat_and_allocate (&opts, &opts_allocated, tmp);
- strcat_and_allocate (&opts, &opts_allocated, optarg);
+ allocate_and_strcat (&opts, &opts_allocated, tmp);
+ allocate_and_strcat (&opts, &opts_allocated, optarg);
break;
case 131:
/* --ifdef. */
- strcat_and_allocate (&opts, &opts_allocated, " --ifdef=");
- strcat_and_allocate (&opts, &opts_allocated, optarg);
+ allocate_and_strcat (&opts, &opts_allocated, " --ifdef=");
+ allocate_and_strcat (&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:
- case 147: case 148:
- strcat_and_allocate (&opts, &opts_allocated, " --");
- strcat_and_allocate (&opts, &opts_allocated,
+ allocate_and_strcat (&opts, &opts_allocated, " --");
+ allocate_and_strcat (&opts, &opts_allocated,
longopts[option_index].name);
if (longopts[option_index].has_arg == 1
|| (longopts[option_index].has_arg == 2
&& optarg != NULL))
{
- strcat_and_allocate (&opts, &opts_allocated, "=");
- strcat_and_allocate (&opts, &opts_allocated, optarg);
+ allocate_and_strcat (&opts, &opts_allocated, "=");
+ allocate_and_strcat (&opts, &opts_allocated, optarg);
}
break;
case 'R':
@@ -343,7 +321,7 @@ diff (argc, argv)
options = xstrdup ("");
#ifdef CLIENT_SUPPORT
- if (client_active) {
+ if (current_parsed_root->isremote) {
/* We're the client side. Fire up the remote server. */
start_server ();
@@ -424,6 +402,8 @@ 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. */
@@ -636,24 +616,53 @@ 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 file, not fullname, because it is the "Index:" line which
- is supposed to contain the directory. */
+ /* 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.
+ */
cvs_output ("\
===================================================================\n\
RCS file: ", 0);
- cvs_output (finfo->file, 0);
+ cvs_output (finfo->fullname, 0);
cvs_output ("\n", 1);
cvs_output ("diff -N ", 0);
- cvs_output (finfo->file, 0);
+ cvs_output (finfo->fullname, 0);
cvs_output ("\n", 1);
if (empty_file == DIFF_ADDED)
{
if (use_rev2 == NULL)
- status = diff_exec (DEVNULL, finfo->file, opts, RUN_TTY);
+ status = diff_exec (DEVNULL, finfo->file, label1, label2, opts, RUN_TTY);
else
{
int retcode;
@@ -672,7 +681,7 @@ RCS file: ", 0);
return err;
}
- status = diff_exec (DEVNULL, tmp, opts, RUN_TTY);
+ status = diff_exec (DEVNULL, tmp, label1, label2, opts, RUN_TTY);
}
}
else
@@ -691,22 +700,11 @@ RCS file: ", 0);
return err;
}
- status = diff_exec (tmp, DEVNULL, opts, RUN_TTY);
+ status = diff_exec (tmp, DEVNULL, label1, label2, 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 2cccbcd..0282005 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -21,6 +21,7 @@
* $FreeBSD$
*/
+#include <assert.h>
#include "cvs.h"
static int deep_remove_dir PROTO((const char *path));
@@ -417,12 +418,12 @@ unlink_file (f)
const char *f;
{
if (trace)
- (void) fprintf (stderr, "%s-> unlink(%s)\n",
+ (void) fprintf (stderr, "%s-> unlink_file(%s)\n",
CLIENT_SERVER_STR, f);
if (noexec)
return (0);
- return (unlink (f));
+ return (CVS_UNLINK (f));
}
/*
@@ -468,7 +469,7 @@ unlink_file_dir (f)
else if (S_ISDIR (sb.st_mode))
return deep_remove_dir (f);
- return unlink (f);
+ return CVS_UNLINK (f);
}
/* Remove a directory and everything it contains. Returns 0 for
@@ -491,14 +492,14 @@ deep_remove_dir (path)
returns 87). */
|| (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
{
- if ((dirp = opendir (path)) == NULL)
+ if ((dirp = CVS_OPENDIR (path)) == NULL)
/* If unable to open the directory return
* an error
*/
return -1;
errno = 0;
- while ((dp = readdir (dirp)) != NULL)
+ while ((dp = CVS_READDIR (dirp)) != NULL)
{
char *buf;
@@ -516,16 +517,16 @@ deep_remove_dir (path)
{
if (deep_remove_dir(buf))
{
- closedir(dirp);
+ CVS_CLOSEDIR(dirp);
free (buf);
return -1;
}
}
else
{
- if (unlink (buf) != 0)
+ if (CVS_UNLINK (buf) != 0)
{
- closedir(dirp);
+ CVS_CLOSEDIR(dirp);
free (buf);
return -1;
}
@@ -537,11 +538,11 @@ deep_remove_dir (path)
if (errno != 0)
{
int save_errno = errno;
- closedir (dirp);
+ CVS_CLOSEDIR (dirp);
errno = save_errno;
return -1;
}
- closedir (dirp);
+ CVS_CLOSEDIR (dirp);
return rmdir (path);
}
else
@@ -688,71 +689,167 @@ 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. */
-/* 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
+ * 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.
+ */
char *
cvs_temp_name ()
{
- char *value;
- int retval;
-
- value = xmalloc (strlen (Tmpdir) + 40);
- sprintf (value, "%s/%s", Tmpdir, "cvsXXXXXXXXXX");
- retval = mkstemp (value);
+ char *fn;
+ FILE *fp;
- if (retval == -1)
- error (1, errno, "cannot generate temporary filename");
- close (retval);
- return value;
+ 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;
}
-#else
-#ifdef HAVE_TEMPNAM
-char *
-cvs_temp_name ()
+
+/* 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;
{
- char *retval;
+ 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);
- 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 */
- 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
+ * 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;
+}
+
/* Return non-zero iff FILENAME is absolute.
Trivial under Unix, but more complicated under other systems. */
int
@@ -841,13 +938,17 @@ char *
get_homedir ()
{
static char *home = NULL;
- char *env = getenv ("HOME");
+ char *env;
struct passwd *pw;
if (home != NULL)
return home;
- if (env)
+ if (
+#ifdef SERVER_SUPPORT
+ !server_active &&
+#endif
+ (env = getenv ("HOME")) != NULL)
home = env;
else if ((pw = (struct passwd *) getpwuid (getuid ()))
&& pw->pw_dir)
@@ -954,7 +1055,7 @@ fopen_case (name, mode, fp, pathp)
}
}
errno = 0;
- while ((dp = readdir (dirp)) != NULL)
+ while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (cvs_casecmp (dp->d_name, fname) == 0)
{
@@ -966,7 +1067,7 @@ fopen_case (name, mode, fp, pathp)
}
if (errno != 0)
error (1, errno, "cannot read directory %s", dir);
- closedir (dirp);
+ CVS_CLOSEDIR (dirp);
if (found_name == NULL)
{
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 3f77dc9..9065cdd 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -173,16 +173,17 @@ import (argc, argv)
if (! isabsolute (argv[0])
&& pathname_levels (argv[0]) == 0)
{
- if (CVSroot_directory == NULL)
+ if (current_parsed_root == 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 (CVSroot_directory) + strlen (argv[0])
- + 10);
- (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
- repos_len = strlen (CVSroot_directory);
+ 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);
}
else
{
@@ -209,7 +210,7 @@ import (argc, argv)
*cp = '\0';
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
/* For rationale behind calling start_server before do_editor, see
commit.c */
@@ -238,7 +239,7 @@ import (argc, argv)
}
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
int err;
@@ -292,8 +293,7 @@ import (argc, argv)
make_directories (repository);
/* Create the logfile that will be logged upon completion */
- tmpfile = cvs_temp_name ();
- if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL)
+ if ((logfp = cvs_temp_file (&tmpfile)) == 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
@@ -427,7 +427,7 @@ import_descend (message, vtag, targc, targv)
else
{
errno = 0;
- while ((dp = readdir (dirp)) != NULL)
+ while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
goto one_more_time_boys;
@@ -478,7 +478,7 @@ import_descend (message, vtag, targc, targv)
else
{
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
err += client_process_import_file (message, dp->d_name,
vtag, targc, targv,
repository,
@@ -498,7 +498,7 @@ import_descend (message, vtag, targc, targv)
error (0, errno, "cannot read directory");
++err;
}
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
}
if (dirlist != NULL)
@@ -1569,7 +1569,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
}
#ifdef CLIENT_SUPPORT
- if (!quiet && !client_active)
+ if (!quiet && !current_parsed_root->isremote)
#else
if (!quiet)
#endif
@@ -1584,7 +1584,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
goto out;
}
#ifdef CLIENT_SUPPORT
- if (!client_active && !isdir (repository))
+ if (!current_parsed_root->isremote && !isdir (repository))
#else
if (!isdir (repository))
#endif
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 30c72f9..7fe92c9 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -174,12 +174,13 @@ lock_name (repository, name)
/* The interesting part of the repository is the part relative
to CVSROOT. */
- assert (CVSroot_directory != NULL);
- assert (strncmp (repository, CVSroot_directory,
- strlen (CVSroot_directory)) == 0);
- short_repos = repository + strlen (CVSroot_directory) + 1;
+ 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;
- if (strcmp (repository, CVSroot_directory) == 0)
+ if (strcmp (repository, current_parsed_root->directory) == 0)
short_repos = ".";
else
assert (short_repos[-1] == '/');
@@ -640,7 +641,7 @@ again:
error (1, 0, "cannot open directory %s", repository);
errno = 0;
- while ((dp = readdir (dirp)) != NULL)
+ while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0)
{
@@ -661,7 +662,7 @@ again:
*/
if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1)
{
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
free (line);
goto again;
}
@@ -687,7 +688,7 @@ again:
if (errno != 0)
error (0, errno, "error reading directory %s", repository);
- closedir (dirp);
+ CVS_CLOSEDIR (dirp);
return (ret);
}
@@ -897,10 +898,11 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
}
void
-lock_tree_for_write (argc, argv, local, aflag)
+lock_tree_for_write (argc, argv, local, which, aflag)
int argc;
char **argv;
int local;
+ int which;
int aflag;
{
int err;
@@ -911,7 +913,7 @@ lock_tree_for_write (argc, argv, local, aflag)
lock_tree_list = getlist ();
err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
- argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0);
+ argv, local, which, 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 cc564c06..df6abe1 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -87,26 +87,183 @@ construct_cvspass_filename ()
return passfile;
}
-static const char *const login_usage[] =
+
+
+/*
+ * 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;
{
- "Usage: %s %s\n",
- "(Specify the --help global option for a list of other help options)\n",
- NULL
-};
+ char *password = NULL;
+ char *p;
-/* Prompt for a password, and store it in the file "CVS/.cvspass".
+ /* 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;
+}
+
+
+
+/*
+ * 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
*
* Because the user might be accessing multiple repositories, with
* different passwords for each one, the format of ~/.cvspass is:
*
- * user@host:/path Acleartext_password
- * user@host:/path Acleartext_password
+ * [user@]host:[port]/path Aencoded_password
+ * [user@]host:[port]/path Aencoded_password
* ...
*
- * Of course, the "user@" might be left off -- it's just based on the
- * value of CVSroot.
+ * New entries are always of the form:
+ *
+ * /1 user@host:port/path Aencoded_password
*
- * The "A" before "cleartext_password" is a literal capital A. It's a
+ * 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
* 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
@@ -116,201 +273,318 @@ static const char *const login_usage[] =
* 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
*/
-int
-login (argc, argv)
- int argc;
- char **argv;
+
+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;
{
char *passfile;
FILE *fp;
- char *typed_password, *found_password;
- char *linebuf = (char *) NULL;
- size_t linebuf_len;
- int root_len, already_entered = 0;
+ char *cvsroot_canonical = NULL;
+ char *password = NULL;
int line_length;
+ long line;
+ char *linebuf = NULL;
+ size_t linebuf_len;
+ char *p;
+ int save_errno = 0;
- if (argc < 0)
- usage (login_usage);
+ 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);
+ }
+
+ /* 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 (CVSroot_method != pserver_method)
+ passfile = construct_cvspass_filename ();
+ fp = CVS_FOPEN (passfile, "r");
+ if (fp == NULL)
{
- error (0, 0, "can only use pserver method with `login' command");
- error (1, 0, "CVSROOT: %s", CVSroot_original);
+ error (0, errno, "failed to open %s for reading", passfile);
+ goto error_exit;
}
- if (! CVSroot_username)
+ 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))
{
- error (0, 0, "CVSROOT \"%s\" is not fully-qualified.",
- CVSroot_original);
- error (1, 0, "Please make sure to specify \"user@host\"!");
+ error (0, errno, "cannot read %s", passfile);
+ goto error_exit;
}
+ if (fclose (fp) < 0)
+ /* not fatal, unless it cascades */
+ error (0, errno, "cannot close %s", passfile);
+ fp = NULL;
- printf ("(Logging in to %s@%s)\n", CVSroot_username, CVSroot_hostname);
- fflush (stdout);
+ /* Utter, total, raving paranoia, I know. */
+ chmod (passfile, 0600);
- passfile = construct_cvspass_filename ();
- typed_password = GETPASS ("CVS password: ");
- typed_password = scramble (typed_password);
+ /* 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);
+ }
- /* 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(). */
+ /* might as well return now */
+ if (operation == password_entry_lookup)
+ goto out;
- cvs_password = xstrdup (typed_password);
+ /* same here */
+ if (operation == password_entry_delete && password == NULL)
+ {
+ error (0, 0, "Entry not found.");
+ goto out;
+ }
- connect_to_pserver (NULL, NULL, 1, 0);
+ /* okay, file errors can simply be fatal from now on since we don't do
+ * anything else if we're in lookup mode
+ */
- /* 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.
+ /* 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 (!noexec && password != NULL && (operation == password_entry_delete
+ || (operation == password_entry_add && strcmp (password, newpassword))))
+ {
+ long found_at = line;
+ char *tmp_name;
+ FILE *tmp_fp;
- root_len = strlen (CVSroot_original);
+ /* open the original file again */
+ fp = CVS_FOPEN (passfile, "r");
+ if (fp == NULL)
+ error (1, errno, "failed to open %s for reading", passfile);
- /* 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. */
+ /* 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);
- 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. */
+ line = 0;
while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
- {
- if (strncmp (CVSroot_original, linebuf, root_len) == 0)
- {
- already_entered = 1;
- break;
- }
- }
+ {
+ 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 (fclose (fp) < 0)
+ /* not fatal, unless it cascades */
error (0, errno, "cannot close %s", passfile);
- }
- else if (!existence_error (errno))
- error (0, errno, "cannot open %s", passfile);
-
- 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.
+ 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?
*/
- 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);
- }
+ 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
+
+ /* 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 (linebuf)
- free (linebuf);
if ((fp = CVS_FOPEN (passfile, "a")) == NULL)
- {
- 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);
+ 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);
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 ()
{
- 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 (current_parsed_root->password)
+ return (scramble(current_parsed_root->password));
+
/* If someone (i.e., login()) is calling connect_to_pserver() out of
context, then assume they have supplied the correct, scrambled
password. */
@@ -320,76 +594,24 @@ 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)
+ if (current_parsed_root->method != pserver_method)
{
- error (0, 0, "can only call GET_CVS_PASSWORD with pserver method");
- error (1, 0, "CVSROOT: %s", CVSroot_original);
+ error (0, 0, "can only call get_cvs_password with pserver method");
+ error (1, 0, "CVSROOT: %s", current_parsed_root->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 (found_it)
- {
- /* 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));
- }
-
- if (linebuf)
- free (linebuf);
- free (passfile);
- return password;
+ return password_entry_operation (password_entry_lookup, current_parsed_root, NULL);
}
static const char *const logout_usage[] =
@@ -405,29 +627,15 @@ logout (argc, argv)
int argc;
char **argv;
{
- 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;
+ char *cvsroot_canonical;
if (argc < 0)
usage (logout_usage);
- if (CVSroot_method != pserver_method)
+ if (current_parsed_root->method != pserver_method)
{
error (0, 0, "can only use pserver method with `logout' command");
- 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\"!");
+ error (1, 0, "CVSROOT: %s", current_parsed_root->original);
}
/* Hmm. Do we want a variant of this command which deletes _all_
@@ -438,73 +646,15 @@ logout (argc, argv)
of security, in that it wouldn't delete entries from any
.cvspass files but the current one. */
- 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)
+ if (!quiet)
{
- 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);
+ cvsroot_canonical = normalize_cvsroot(current_parsed_root);
+ printf ("Logging out of %s\n", cvsroot_canonical);
+ fflush (stdout);
+ free (cvsroot_canonical);
}
- if (tmp_name)
- free (tmp_name);
+ password_entry_operation (password_entry_delete, current_parsed_root, NULL);
return 0;
}
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index a5e16b7..54b3b4d 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -192,8 +192,10 @@ 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,8 +209,6 @@ 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 */
@@ -274,7 +274,7 @@ do_editor (dir, messagep, repository, changes)
free (editinfo_editor);
editinfo_editor = (char *) NULL;
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
; /* nothing, leave editinfo_editor NULL */
else
#endif
@@ -404,7 +404,7 @@ do_verify (messagep, repository)
struct stat stbuf;
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
/* The verification will happen on the server. */
return;
#endif
@@ -422,13 +422,10 @@ do_verify (messagep, repository)
return;
}
- /* Get a temp filename, open a temporary file, write the message to the
+ /* open a temporary file, write the message to the
temp file, and close the file. */
- fname = cvs_temp_name ();
-
- fp = fopen (fname, "w");
- if (fp == NULL)
+ if ((fp = cvs_temp_file (&fname)) == NULL)
error (1, errno, "cannot create temporary file %s", fname);
else
{
@@ -849,16 +846,16 @@ logfile_write (repository, filter, message, logfp, changes)
srepos = Short_Repository (repository);
- prog = xmalloc ((fmt_percent - filter) + strlen (srepos)
- + strlen (str_list) + strlen (fmt_continue)
+ prog = cp = xmalloc ((fmt_percent - filter) + 2 * strlen (srepos)
+ + 2 * strlen (str_list) + strlen (fmt_continue)
+ 10);
- (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);
+ (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);
/* To be nice, free up some memory. */
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index cad210b..855d2ae 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -68,8 +68,12 @@ char *Editor = EDITOR_DFLT;
List *root_directories = NULL;
/* We step through the above values. This variable is set to reflect
- the currently active value. */
-char *current_root = NULL;
+ * the currently active value.
+ *
+ * Now static. FIXME - this variable should be removable (well, localizable)
+ * with a little more work.
+ */
+static char *current_root = NULL;
static const struct cmd
@@ -100,47 +104,50 @@ static const struct cmd
char *nick2;
int (*func) (); /* Function takes (argc, argv) arguments. */
+ unsigned long attr; /* Attributes. */
} cmds[] =
{
- { "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 },
+ { "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 },
#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
- { "kserver", NULL, NULL, server }, /* placeholder */
+ { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
#endif
- { "log", "lo", "rlog", cvslog },
+ { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR },
#ifdef AUTH_CLIENT_SUPPORT
- { "login", "logon", "lgn", login },
- { "logout", NULL, NULL, logout },
+ { "login", "logon", "lgn", login, 0 },
+ { "logout", NULL, NULL, logout, 0 },
#endif /* AUTH_CLIENT_SUPPORT */
#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
- { "pserver", NULL, NULL, server }, /* placeholder */
+ { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
#endif
- { "rdiff", "patch", "pa", patch },
- { "release", "re", "rel", release },
- { "remove", "rm", "delete", cvsremove },
- { "rtag", "rt", "rfreeze", rtag },
+ { "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 },
#ifdef SERVER_SUPPORT
- { "server", NULL, NULL, server },
+ { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
#endif
- { "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 },
+ { "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 },
};
static const char *const usg[] =
@@ -215,9 +222,11 @@ 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",
@@ -226,6 +235,7 @@ 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",
@@ -321,51 +331,14 @@ unsigned long int
lookup_command_attribute (cmd_name)
char *cmd_name;
{
- unsigned long int ret = 0;
-
- if (strcmp (cmd_name, "import") != 0)
- {
- 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;
- }
-
+ const struct cmd *cm;
- /* 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))
+ for (cm = cmds; cm->fullname; cm++)
{
- ret |= CVS_CMD_MODIFIES_REPOSITORY;
+ if (strcmp (cmd_name, cm->fullname) == 0)
+ break;
}
-
- return ret;
+ return cm->attr;
}
@@ -593,7 +566,7 @@ main (argc, argv)
version (0, (char **) NULL);
(void) fputs ("\n", stdout);
(void) fputs ("\
-Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\
+Copyright (c) 1989-2001 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);
@@ -624,6 +597,8 @@ Copyright (c) 1989-2000 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 */
@@ -704,15 +679,6 @@ Copyright (c) 1989-2000 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 */
@@ -867,8 +833,7 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\
specify a different repository than the one we are
importing to. */
- if ((lookup_command_attribute (command_name)
- & CVS_CMD_IGNORE_ADMROOT)
+ if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT)
/* -d overrides CVS/Root, so don't give an error if the
latter points to a nonexistent repository. */
@@ -960,25 +925,29 @@ Copyright (c) 1989-2000 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 (parse_cvsroot (current_root))
+ if (current_parsed_root != NULL)
+ free_cvsroot_t (current_parsed_root);
+ if ((current_parsed_root = parse_cvsroot (current_root)) == NULL)
error (1, 0, "Bad CVSROOT.");
if (trace)
- error (0, 0, "notice: main loop with CVSROOT=%s",
- current_root);
+ fprintf (stderr, "%s-> main loop with CVSROOT=%s\n",
+ CLIENT_SERVER_STR, current_root);
/*
* Check to see if the repository exists.
*/
- if (!client_active)
+#ifdef CLIENT_SUPPORT
+ if (!current_parsed_root->isremote)
+#endif /* CLIENT_SUPPORT */
{
char *path;
int save_errno;
- path = xmalloc (strlen (CVSroot_directory)
+ path = xmalloc (strlen (current_parsed_root->directory)
+ sizeof (CVSROOTADM)
- + 20);
- (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
+ + 2);
+ (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
save_errno = errno;
@@ -1023,7 +992,7 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\
&& !server_active
#endif
#ifdef CLIENT_SUPPORT
- && !client_active
+ && !current_parsed_root->isremote
#endif
)
{
@@ -1031,14 +1000,18 @@ Copyright (c) 1989-2000 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 (CVSroot_directory);
+ parse_config (current_parsed_root->directory);
/* Now is a convenient time to read CVSROOT/options */
- parseopts(CVSroot_directory);
+ parseopts(current_parsed_root->directory);
}
#ifdef CLIENT_SUPPORT
- if (client_active)
+ /* 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)
{
/* Create a new list for directory names that we've
sent to the server. */
@@ -1156,31 +1129,55 @@ date_from_time_t (unixtime)
void
date_to_internet (dest, source)
char *dest;
- char *source;
+ const char *source;
{
- int year, month, day, hour, minute, second;
+ struct tm 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"};
+ date_to_tm (&date, source);
+ tm_to_internet (dest, &date);
+}
+void
+date_to_tm (dest, source)
+ struct tm *dest;
+ const char *source;
+{
if (sscanf (source, SDATEFORM,
- &year, &month, &day, &hour, &minute, &second)
- != 6)
+ &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
+ &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
+ != 6)
/* Is there a better way to handle errors here? I made this
non-fatal in case we are called from the code which can't
deal with fatal errors. */
error (0, 0, "internal error: bad date %s", source);
- /* Always send a four digit year. */
- if (year < 100)
- year += 1900;
+ 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.
- sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", day,
- month < 1 || month > 12 ? "???" : month_names[month - 1],
- year, hour, minute, second);
+ 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);
}
void
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index 49cda18..3082f7d 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -851,7 +851,7 @@ init (argc, argv)
usage (init_usage);
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
start_server ();
@@ -865,12 +865,10 @@ 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 (CVSroot_directory);
+ mkdir_if_needed (current_parsed_root->directory);
- adm = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + 10);
- strcpy (adm, CVSroot_directory);
- strcat (adm, "/");
- strcat (adm, CVSROOTADM);
+ adm = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2);
+ sprintf (adm, "%s/%s", current_parsed_root->directory, CVSROOTADM);
mkdir_if_needed (adm);
/* This is needed because we pass "fileptr->filename" not "info"
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 1e9edce..c7963b415 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -94,11 +94,6 @@ 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 **));
@@ -2130,7 +2125,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,
- * exit with error.
+ * return NULL.
*/
char *
RCS_tag2rev (rcs, tag)
@@ -2209,9 +2204,8 @@ RCS_tag2rev (rcs, tag)
if (rev)
return rev;
- error (1, 0, "tag `%s' does not exist", tag);
- /* NOT REACHED -- error (1 ... ) does not return here */
- return 0;
+ /* Trust the caller to print warnings. */
+ return NULL;
}
/*
@@ -4184,7 +4178,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 (unlink (dest) < 0 && !existence_error (errno))
+ if (CVS_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",
@@ -4354,7 +4348,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 (unlink (dest) < 0 && existence_error (errno))
+ if (CVS_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",
@@ -5297,7 +5291,7 @@ workfile);
memset (commitpt->text, 0, sizeof (Deltatext));
bufsize = 0;
- switch (diff_exec (workfile, tmpfile, diffopts, changefile))
+ switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile))
{
case 0:
case 1:
@@ -5345,7 +5339,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, diffopts, changefile))
+ switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile))
{
case 0:
case 1:
@@ -5725,7 +5719,7 @@ RCS_setbranch (rcs, rev)
int
RCS_lock (rcs, rev, lock_quiet)
RCSNode *rcs;
- const char *rev;
+ char *rev;
int lock_quiet;
{
List *locks;
@@ -5744,32 +5738,16 @@ 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);
-
- /* 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);
+ else
+ xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
/* 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 (findnode (rcs->versions, xrev) == NULL)
+ if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
{
if (!lock_quiet)
- error (0, 0, "%s: revision %s absent", rcs->path, xrev);
+ error (0, 0, "%s: revision %s absent", rcs->path, rev);
free (xrev);
return 1;
}
@@ -5835,7 +5813,7 @@ RCS_lock (rcs, rev, lock_quiet)
int
RCS_unlock (rcs, rev, unlock_quiet)
RCSNode *rcs;
- const char *rev;
+ char *rev;
int unlock_quiet;
{
Node *lock;
@@ -5885,20 +5863,15 @@ RCS_unlock (rcs, rev, unlock_quiet)
return 0; /* no lock found, ergo nothing to do */
xrev = xstrdup (lock->key);
}
- else if (RCS_nodeisbranch (rcs, rev))
+ else
{
- /* If rev is a branch number, unlock the latest revision on that
- branch. */
- xrev = RCS_getbranch (rcs, (char *) rev, 1);
+ xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
if (xrev == NULL)
{
- error (0, 0, "%s: branch %s absent", rcs->path, rev);
+ error (0, 0, "%s: revision %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)
@@ -6420,7 +6393,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
goto delrev_done;
outfile = cvs_temp_name();
- status = diff_exec (beforefile, afterfile, "-an", outfile);
+ status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile);
if (status == 2)
{
@@ -7059,7 +7032,7 @@ rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
On error, give a fatal error. */
-static void
+void
RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
RCSNode *rcs;
FILE *fp;
@@ -8418,138 +8391,6 @@ 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
@@ -8559,6 +8400,11 @@ annotate (argc, argv)
*
* 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)
@@ -8566,37 +8412,45 @@ make_file_label (path, rev, rcs)
char *rev;
RCSNode *rcs;
{
- char datebuf[MAXDATELEN];
+ char datebuf[MAXDATELEN + 1];
char *label;
- char *file;
- file = last_component (path);
label = (char *) xmalloc (strlen (path)
- + (rev == NULL ? 0 : strlen (rev))
- + 50);
+ + (rev == NULL ? 0 : strlen (rev) + 1)
+ + MAXDATELEN
+ + 2);
if (rev)
{
- char *date;
+ char date[MAXDATELEN + 1];
+ /* revs cannot be attached to /dev/null ... duh. */
+ assert (strcmp(DEVNULL, path));
RCS_getrevtime (rcs, rev, datebuf, 0);
- date = printable_date (datebuf);
+ (void) date_to_internet (date, datebuf);
(void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
- free (date);
}
else
{
struct stat sb;
- struct tm *wm;
+ struct tm *wm = NULL;
- if (CVS_STAT (file, &sb) < 0)
- error (0, 1, "could not get info for `%s'", path);
+ if (strcmp(DEVNULL, path))
+ {
+ 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);
+ }
else
{
- 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);
+ time_t t = 0;
+ wm = gmtime(&t);
+ }
+
+ if (wm)
+ {
+ (void) tm_to_internet (datebuf, wm);
(void) sprintf (label, "-L%s\t%s", path, datebuf);
}
}
@@ -8677,7 +8531,7 @@ static char *
getfullCVSname(CVSname, pathstore)
char *CVSname, **pathstore;
{
- if (CVSroot_directory) {
+ if (current_parsed_root->directory) {
int rootlen;
char *c = NULL;
int alen = sizeof(ATTIC) - 1;
@@ -8695,8 +8549,8 @@ getfullCVSname(CVSname, pathstore)
}
}
- rootlen = strlen(CVSroot_directory);
- if (!strncmp(*pathstore, CVSroot_directory, rootlen) &&
+ rootlen = strlen(current_parsed_root->directory);
+ if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
(*pathstore)[rootlen] == '/')
CVSname = (*pathstore + rootlen + 1);
else
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index 397488e..e44a45c 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -181,6 +181,9 @@ 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
*/
@@ -225,8 +228,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 *, const char *, int));
-int RCS_unlock PROTO ((RCSNode *, const char *, int));
+int RCS_lock PROTO ((RCSNode *, char *, int));
+int RCS_unlock PROTO ((RCSNode *, char *, int));
int RCS_delete_revs PROTO ((RCSNode *, char *, char *, int));
void RCS_addaccess PROTO ((RCSNode *, char *));
void RCS_delaccess PROTO ((RCSNode *, char *));
@@ -236,8 +239,10 @@ 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 *));
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index bcdffd5..b233b76 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -532,9 +532,11 @@ RCS file: ", 0);
message on stderr. */
int
-diff_exec (file1, file2, options, out)
+diff_exec (file1, file2, label1, label2, options, out)
char *file1;
char *file2;
+ char *label1;
+ char *label2;
char *options;
char *out;
{
@@ -577,6 +579,10 @@ diff_exec (file1, file2, 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 09e1cad..0af0d56 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -158,10 +158,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
#ifdef CLIENT_SUPPORT
if (!just_subdirs
&& CVSroot_cmdline == NULL
- && client_active)
+ && current_parsed_root->isremote)
{
char *root = Name_Root (NULL, update_dir);
- if (root && strcmp (root, current_root) != 0)
+ if (root && strcmp (root, current_parsed_root->original) != 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
@@ -205,7 +205,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
program_name);
}
#ifdef CLIENT_SUPPORT
- else if (client_active && server_started)
+ else if (current_parsed_root->isremote && server_started)
{
/* In the the case "cvs update foo bar baz", a call to
send_file_names in update.c will have sent the
@@ -291,7 +291,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
{
if ((which & W_LOCAL) && isdir (CVSADM)
#ifdef CLIENT_SUPPORT
- && !client_active
+ && !current_parsed_root->isremote
#endif
)
{
@@ -364,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_root. If we do, and two repositories have a
- module with the same name, nasty things could happen.
+ from current_parsed_root->original. 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
@@ -441,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_root.
+ appropriate to current_parsed_root->original.
*/
@@ -600,8 +600,9 @@ do_recursion (frame)
}
- process_this_directory = (strcmp (current_root, this_root) == 0);
-
+ process_this_directory =
+ (strcmp (current_parsed_root->original, this_root) == 0);
+
free (this_root);
}
}
@@ -711,7 +712,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 (client_active)
+ if (current_parsed_root->isremote)
notify_check (repository, update_dir);
#endif /* CLIENT_SUPPORT */
@@ -1025,7 +1026,8 @@ but CVS uses %s for its own purposes; skipping %s directory",
}
- process_this_directory = (strcmp (current_root, this_root) == 0);
+ process_this_directory = (strcmp (current_parsed_root->original, this_root) == 0);
+
free (this_root);
}
}
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index a53dc79..525d1ce 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -20,50 +20,19 @@
#include "getline.h"
#include "buffer.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
-
+#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"
/* 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;
@@ -73,37 +42,46 @@ 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
+# endif /* HAVE_GSSAPI */
+#endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */
+#ifdef SERVER_SUPPORT
+
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>
#endif
-/* for select */
-#include <sys/types.h>
-#ifdef HAVE_SYS_BSDTYPES_H
-#include <sys/bsdtypes.h>
+#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
+#include <sys/socket.h>
#endif
-#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
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
+#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
+/* for select */
+#include "xselect.h"
+
#ifndef O_NONBLOCK
#define O_NONBLOCK O_NDELAY
#endif
@@ -116,18 +94,16 @@ int cvs_gssapi_encrypt;
#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 AUTH_SERVER_SUPPORT
+
+# ifdef HAVE_GETSPNAM
+# include <shadow.h>
+# endif
/* The cvs username sent by the client, which might or might not be
the same as the system username the server eventually switches to
@@ -143,7 +119,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
@@ -424,10 +400,10 @@ create_adm_p (base_dir, dir)
differently. */
char *empty;
- empty = malloc (strlen (CVSroot_directory)
+ empty = malloc (strlen (current_parsed_root->directory)
+ sizeof (CVSROOTADM)
+ sizeof (CVSNULLREPOS)
- + 10);
+ + 3);
if (! empty)
{
retval = ENOMEM;
@@ -435,7 +411,7 @@ create_adm_p (base_dir, dir)
}
/* Create the directory name. */
- (void) sprintf (empty, "%s/%s/%s", CVSroot_directory,
+ (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSNULLREPOS);
/* Create the directory if it doesn't exist. */
@@ -601,10 +577,16 @@ print_error (status)
int status;
{
char *msg;
+ char tmpstr[80];
+
buf_output0 (buf_to_net, "error ");
msg = strerror (status);
- if (msg)
- buf_output0 (buf_to_net, msg);
+ if (msg == NULL)
+ {
+ sprintf (tmpstr, "unknown error %d", status);
+ msg = tmpstr;
+ }
+ buf_output0 (buf_to_net, msg);
buf_append_char (buf_to_net, '\n');
buf_flush (buf_to_net, 0);
@@ -771,7 +753,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 (CVSroot_directory != NULL)
+ if (current_parsed_root != NULL)
{
if (alloc_pending (80 + strlen (arg)))
sprintf (pending_error_text,
@@ -794,24 +776,27 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
}
}
#endif
- set_local_cvsroot (arg);
+
+ if (current_parsed_root != NULL)
+ free_cvsroot_t (current_parsed_root);
+ current_parsed_root = 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 (CVSroot_directory);
+ parse_config (current_parsed_root->directory);
/* Now is a good time to read CVSROOT/options too. */
- parseopts(CVSroot_directory);
+ parseopts(current_parsed_root->directory);
- path = malloc (strlen (CVSroot_directory)
+ path = malloc (strlen (current_parsed_root->directory)
+ sizeof (CVSROOTADM)
- + 10);
+ + 2);
if (path == NULL)
{
pending_error = ENOMEM;
return;
}
- (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
+ (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
int save_errno = errno;
@@ -822,13 +807,13 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
free (path);
#ifdef HAVE_PUTENV
- env = malloc (strlen (CVSROOT_ENV) + strlen (CVSroot_directory) + 1 + 1);
+ env = malloc (strlen (CVSROOT_ENV) + strlen (current_parsed_root->directory) + 2);
if (env == NULL)
{
pending_error = ENOMEM;
return;
}
- (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot_directory);
+ (void) sprintf (env, "%s=%s", CVSROOT_ENV, current_parsed_root->directory);
(void) putenv (env);
/* do not free env, as putenv has control of it */
#endif
@@ -871,14 +856,14 @@ server_pathname_check (path)
static int outside_root PROTO ((char *));
/* Is file or directory REPOS an absolute pathname within the
- CVSroot_directory? If yes, return 0. If no, set pending_error
+ current_parsed_root->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 (CVSroot_directory);
+ size_t root_len = strlen (current_parsed_root->directory);
/* I think isabsolute (repos) should always be true, and that
any RELATIVE_REPOS stuff should only be in CVS/Repository
@@ -893,15 +878,15 @@ E protocol error: %s is not absolute", repos);
}
if (repos_len < root_len
- || strncmp (CVSroot_directory, repos, root_len) != 0)
+ || strncmp (current_parsed_root->directory, repos, root_len) != 0)
{
not_within:
- if (alloc_pending (strlen (CVSroot_directory)
+ if (alloc_pending (strlen (current_parsed_root->directory)
+ strlen (repos)
+ 80))
sprintf (pending_error_text, "\
E protocol error: directory '%s' not within root '%s'",
- repos, CVSroot_directory);
+ repos, current_parsed_root->directory);
return 1;
}
if (repos_len > root_len)
@@ -1104,8 +1089,9 @@ 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
- && CVSroot_directory != NULL
- && strcmp (CVSroot_directory, repos) == 0)
+ && current_parsed_root != NULL
+ && current_parsed_root->directory != NULL
+ && strcmp (current_parsed_root->directory, repos) == 0)
{
if (fprintf (f, "/.") < 0)
{
@@ -2435,6 +2421,9 @@ 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 ();
}
@@ -2492,13 +2481,13 @@ check_command_legal_p (cmd_name)
int found_it = 0;
/* else */
- flen = strlen (CVSroot_directory)
+ flen = strlen (current_parsed_root->directory)
+ strlen (CVSROOTADM)
+ strlen (CVSROOTADM_READERS)
+ 3;
fname = xmalloc (flen);
- (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_READERS);
fp = fopen (fname, "r");
@@ -2544,13 +2533,13 @@ check_command_legal_p (cmd_name)
/* Now check the writers file. */
- flen = strlen (CVSroot_directory)
+ flen = strlen (current_parsed_root->directory)
+ strlen (CVSROOTADM)
+ strlen (CVSROOTADM_WRITERS)
+ 3;
fname = xmalloc (flen);
- (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_WRITERS);
fp = fopen (fname, "r");
@@ -2792,7 +2781,9 @@ 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 */
@@ -2809,11 +2800,11 @@ error \n");
exitstatus = (*command) (argument_count, argument_vector);
/* Output any partial lines. If the client doesn't support
- "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))
+ "MT", we go ahead and just tack on a newline since the
+ protocol doesn't support anything better. */
+ if (! buf_empty_p (saved_output))
{
- buf_output0 (protocol, "MT text ");
+ buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M ");
buf_append_buffer (protocol, saved_output);
buf_output (protocol, "\n", 1);
buf_send_counted (protocol);
@@ -2836,7 +2827,7 @@ error \n");
struct buffer *protocol_inbuf;
/* Number of file descriptors to check in select (). */
int num_to_check;
- int count_needed = 0;
+ int count_needed = 1;
#ifdef SERVER_FLOWCONTROL
int have_flowcontrolled = 0;
#endif /* SERVER_FLOWCONTROL */
@@ -2924,13 +2915,16 @@ error \n");
while (stdout_pipe[0] >= 0
|| stderr_pipe[0] >= 0
- || protocol_pipe[0] >= 0)
+ || protocol_pipe[0] >= 0
+ || count_needed <= 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.
@@ -2951,8 +2945,24 @@ 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)
{
@@ -2968,28 +2978,34 @@ 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, (struct timeval *)NULL);
+ (fd_set *)0, timeout_ptr);
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? */
@@ -3001,7 +3017,6 @@ error \n");
{
int status;
int count_read;
- int special;
status = buf_input_data (protocol_inbuf, &count_read);
@@ -3024,29 +3039,49 @@ error \n");
* have.
*/
count_needed -= count_read;
- while (count_needed <= 0)
- {
- count_needed = buf_copy_counted (buf_to_net,
+ }
+ /* 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,
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 -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)
+ /* 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 (supported_response ("F"))
- {
- buf_append_char (buf_to_net, 'F');
- buf_append_char (buf_to_net, '\n');
- }
-
- cvs_flusherr ();
+ buf_append_char (buf_to_net, 'F');
+ buf_append_char (buf_to_net, '\n');
}
+ cvs_flusherr ();
+ break;
}
}
@@ -3433,6 +3468,11 @@ 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)
{
@@ -3592,6 +3632,15 @@ 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;
{
@@ -3630,7 +3679,9 @@ static void
serve_rtag (arg)
char *arg;
{
- do_cvs_command ("rtag", rtag);
+ /* Tell cvstag() to behave like rtag not tag. */
+ command_name = "rtag";
+ do_cvs_command ("rtag", cvstag);
}
static void
@@ -3754,7 +3805,10 @@ serve_init (arg)
/* Fall through to do_cvs_command which will return the
actual error. */
}
- set_local_cvsroot (arg);
+
+ if (current_parsed_root != NULL)
+ free_cvsroot_t (current_parsed_root);
+ current_parsed_root = local_cvsroot (arg);
do_cvs_command ("init", init);
}
@@ -3767,6 +3821,17 @@ 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)
@@ -4164,6 +4229,23 @@ 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)
{
@@ -4497,7 +4579,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,
+ NULL, 0, 0, 0, 0,
(char *) NULL);
close_module (db);
server_expanding = 0;
@@ -4698,6 +4780,7 @@ 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),
@@ -4719,6 +4802,7 @@ 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)
@@ -4752,7 +4836,7 @@ serve_valid_requests (arg)
buf_flush (buf_to_net, 1);
}
-#ifdef sun
+#ifdef SUNOS_KLUDGE
/*
* Delete temporary files. SIG is the signal making this happen, or
* 0 if not called as a result of a signal.
@@ -4766,7 +4850,7 @@ static void wait_sig (sig)
if (r == command_pid)
command_pid_is_dead++;
}
-#endif
+#endif /* SUNOS_KLUDGE */
void
server_cleanup (sig)
@@ -4810,7 +4894,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 sun
+#ifdef SUNOS_KLUDGE
if (command_pid > 0)
{
/* To avoid crashes on SunOS due to bugs in SunOS tmpfs
@@ -4883,7 +4967,7 @@ server_cleanup (sig)
}
}
}
-#endif
+#endif /* SUNOS_KLUDGE */
CVS_CHDIR (Tmpdir);
/* Temporarily clear noexec, so that we clean up our temp directory
@@ -5021,19 +5105,25 @@ error ENOMEM Virtual memory exhausted.\n");
pending_error = status;
}
#ifndef CHMOD_BROKEN
- else
+ else if (chmod (server_temp_dir, S_IRWXU) < 0)
{
- if (chmod (server_temp_dir, S_IRWXU) < 0)
- {
- int save_errno = errno;
- if (alloc_pending (80 + strlen (server_temp_dir)))
- sprintf (pending_error_text,
+ 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;
+ }
}
}
@@ -5129,7 +5219,7 @@ error ENOMEM Virtual memory exhausted.\n");
continue;
if (!(rq->flags & RQ_ROOTLESS)
- && CVSroot_directory == NULL)
+ && current_parsed_root == NULL)
{
/* For commands which change the way in which data
is sent and received, for example Gzip-stream,
@@ -5263,10 +5353,10 @@ error 0 %s: no such user\n", username);
#endif
#if HAVE_PUTENV
- /* Set LOGNAME and USER in the environment, in case they are
- already set to something else. */
+ /* Set LOGNAME, USER and CVS_USER in the environment, in case they
+ are already set to something else. */
{
- char *env;
+ char *env, *cvs_user;
env = xmalloc (sizeof "LOGNAME=" + strlen (username));
(void) sprintf (env, "LOGNAME=%s", username);
@@ -5275,6 +5365,11 @@ 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 */
}
@@ -5309,7 +5404,7 @@ check_repository_password (username, password, repository, host_user_ptr)
int found_it = 0;
int namelen;
- /* We don't use CVSroot_directory because it hasn't been set yet
+ /* We don't use current_parsed_root->directory because it hasn't been set yet
* -- our `repository' argument came from the authentication
* protocol, not the regular CVS protocol.
*/
@@ -5642,8 +5737,13 @@ pserver_authenticate_connection ()
{
int on = 1;
- (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
- (char *) &on, sizeof on);
+ 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
+ }
}
#endif
@@ -5699,13 +5799,13 @@ pserver_authenticate_connection ()
error (1, 0, "bad auth protocol end: %s", tmp);
}
if (!root_allow_ok (repository))
- /* 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). */
+ {
+ printf ("error 0 %s: no such repository\n", repository);
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository);
+#endif
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
@@ -5721,6 +5821,13 @@ 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);
@@ -5802,8 +5909,13 @@ error %s getpeername or getsockname failed\n", strerror (errno));
{
int on = 1;
- (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
- (char *) &on, sizeof on);
+ 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
+ }
}
#endif
@@ -6399,13 +6511,20 @@ 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, -1);
+ buf_send_special_count (protocol, -2);
}
else
#endif
@@ -6431,7 +6550,13 @@ 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. */
+ 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);
}
else
#endif
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index bec2397..c92dc41 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -60,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));
+static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers));
static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir,
char *repository, char *update_dir,
List *entries));
@@ -101,6 +101,7 @@ 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;
@@ -109,7 +110,7 @@ static List *ignlist = (List *) NULL;
static time_t last_register_time;
static const char *const update_usage[] =
{
- "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n",
+ "Usage: %s %s [-APCdflRp] [-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",
@@ -119,7 +120,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.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\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",
@@ -235,7 +236,7 @@ update (argc, argv)
argv += optind;
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
int pass;
@@ -411,7 +412,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);
+ pipeout, which, join_rev1, join_rev2, (char *) NULL, 1);
/* free the space Make_Date allocated if necessary */
if (date != NULL)
@@ -425,7 +426,8 @@ 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)
+ xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir,
+ xdotemplate)
int argc;
char **argv;
char *xoptions;
@@ -441,6 +443,7 @@ 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;
@@ -454,6 +457,7 @@ 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;
@@ -505,11 +509,15 @@ 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)
{
- while (time ((time_t *) NULL) == last_register_time)
- sleep (1);
+ sleep_past (last_register_time);
}
return (err);
@@ -577,9 +585,6 @@ 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);
@@ -625,9 +630,7 @@ 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;
@@ -652,8 +655,12 @@ update_fileproc (callerdat, finfo)
write_letter (finfo, 'C');
break;
case T_NEEDS_MERGE: /* needs merging */
- retval = merge_file (finfo, vers);
- break;
+ if (! toss_local_changes)
+ {
+ retval = merge_file (finfo, vers);
+ break;
+ }
+ /* else FALL THROUGH */
case T_MODIFIED: /* locally modified */
retval = 0;
if (toss_local_changes)
@@ -733,8 +740,8 @@ update_fileproc (callerdat, finfo)
}
}
break;
-#ifdef SERVER_SUPPORT
case T_PATCH: /* needs patch */
+#ifdef SERVER_SUPPORT
if (patches)
{
int docheckout;
@@ -756,11 +763,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;
@@ -773,18 +780,7 @@ update_fileproc (callerdat, finfo)
retval = 0;
break;
case T_REMOVE_ENTRY: /* needs to be un-registered */
- 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
+ retval = scratch_file (finfo, vers);
break;
default: /* can't ever happen :-) */
error (0, 0,
@@ -799,7 +795,7 @@ update_fileproc (callerdat, finfo)
join_file (finfo, vers);
/* if this directory has an ignore list, add this file to it */
- if (ignlist)
+ if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
{
Node *p;
@@ -879,7 +875,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, CVSroot_original);
+ Create_Root ((char *) NULL, current_parsed_root->original);
}
return (err);
@@ -972,7 +968,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
via WriteTag. */
0,
0,
- 1);
+ dotemplate);
rewrite_tag = 1;
nonbranch = 0;
Subdir_Register (entries, (char *) NULL, dir);
@@ -1175,7 +1171,7 @@ isemptydir (dir, might_not_exist)
return (0);
}
errno = 0;
- while ((dp = readdir (dirp)) != NULL)
+ while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") != 0
&& strcmp (dp->d_name, "..") != 0)
@@ -1184,7 +1180,7 @@ isemptydir (dir, might_not_exist)
{
/* An entry other than the CVS directory. The directory
is certainly not empty. */
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
return (0);
}
else
@@ -1215,7 +1211,7 @@ isemptydir (dir, might_not_exist)
{
/* There are files that have been removed, but not
committed! Do not consider the directory empty. */
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
return (0);
}
}
@@ -1225,10 +1221,10 @@ isemptydir (dir, might_not_exist)
if (errno != 0)
{
error (0, errno, "cannot read directory %s", dir);
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
return (0);
}
- (void) closedir (dirp);
+ (void) CVS_CLOSEDIR (dirp);
return (1);
}
@@ -1236,13 +1232,46 @@ isemptydir (dir, might_not_exist)
* scratch the Entries file entry associated with a file
*/
static int
-scratch_file (finfo)
+scratch_file (finfo, vers)
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);
}
@@ -1742,7 +1771,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
diff_options = "-n";
}
- retcode = diff_exec (file1, file2, diff_options, finfo->file);
+ retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file);
/* A retcode of 0 means no differences. 1 means some differences. */
if (retcode != 0
@@ -2108,6 +2137,17 @@ 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;
@@ -2276,7 +2316,14 @@ 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. */
+ 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);
#ifdef SERVER_SUPPORT
if (server_active)
{
@@ -2285,8 +2332,6 @@ 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);
@@ -2329,6 +2374,7 @@ 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);
@@ -2343,6 +2389,7 @@ 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);
OpenPOWER on IntegriCloud