summaryrefslogtreecommitdiffstats
path: root/contrib/cvs
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2002-09-02 05:57:14 +0000
committerpeter <peter@FreeBSD.org>2002-09-02 05:57:14 +0000
commita2b6a3a9b8cf8113c377699deba118c6b57d881e (patch)
tree32949f652e8da27bbd93bd53f3dc7bca126e7e9e /contrib/cvs
parent9977823bcf0469bcd2b9a4a936f590610431dc1e (diff)
downloadFreeBSD-src-a2b6a3a9b8cf8113c377699deba118c6b57d881e.zip
FreeBSD-src-a2b6a3a9b8cf8113c377699deba118c6b57d881e.tar.gz
Initial merge of 1.11.1p1 -> 1.11.2 changes onto mainline
Diffstat (limited to 'contrib/cvs')
-rwxr-xr-xcontrib/cvs/contrib/sccs2rcs.in13
-rw-r--r--contrib/cvs/diff/diff3.c6
-rw-r--r--contrib/cvs/man/cvs.127
-rw-r--r--contrib/cvs/src/checkout.c130
-rw-r--r--contrib/cvs/src/client.c755
-rw-r--r--contrib/cvs/src/commit.c14
-rw-r--r--contrib/cvs/src/cvs.h36
-rw-r--r--contrib/cvs/src/diff.c122
-rw-r--r--contrib/cvs/src/filesubr.c3
-rw-r--r--contrib/cvs/src/import.c23
-rw-r--r--contrib/cvs/src/lock.c11
-rw-r--r--contrib/cvs/src/login.c14
-rw-r--r--contrib/cvs/src/logmsg.c160
-rw-r--r--contrib/cvs/src/main.c8
-rw-r--r--contrib/cvs/src/mkmodules.c12
-rw-r--r--contrib/cvs/src/rcs.c249
-rw-r--r--contrib/cvs/src/recurse.c3
-rw-r--r--contrib/cvs/src/server.c176
-rw-r--r--contrib/cvs/src/update.c20
19 files changed, 1082 insertions, 700 deletions
diff --git a/contrib/cvs/contrib/sccs2rcs.in b/contrib/cvs/contrib/sccs2rcs.in
index 199a5a0..2cd4813 100755
--- a/contrib/cvs/contrib/sccs2rcs.in
+++ b/contrib/cvs/contrib/sccs2rcs.in
@@ -178,13 +178,12 @@ foreach sfile (SCCS/s.*)
if ($status != 0) goto ERROR
# get file into current dir and get stats
- set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
- set year = `echo $date | cut -c3-4`
- if ($year < 70) then
- # Y2K Bug, change century to 20
- set date = `echo $date | sed -e s/19/20/`
- endif
- set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
+
+ # Is the substr stuff and the +0 in the following awk script really
+ # necessary? It seems to me that if we didn't find the date format
+ # we expected in the output we have other problems.
+ set date = `sccs prs -r$rev $file | awk '/^D / {print (substr($3,0,2)+0<70?20:19) $3, $4; exit}'`
+ set author = `sccs prs -r$rev $file | awk '/^D / {print $5; exit}'`
echo ""
echo "==> file $file, rev=$rev, date=$date, author=$author"
sccs edit -r$rev $file >>& $logfile
diff --git a/contrib/cvs/diff/diff3.c b/contrib/cvs/diff/diff3.c
index dc89606..fc32abd 100644
--- a/contrib/cvs/diff/diff3.c
+++ b/contrib/cvs/diff/diff3.c
@@ -447,7 +447,7 @@ diff3_run (argc, argv, out, callbacks_arg)
outfile = fopen (out, "w");
if (outfile == NULL)
{
- perror_with_name ("could not open output file");
+ perror_with_name (out);
return 2;
}
opened_file = 1;
@@ -1850,10 +1850,10 @@ myread (fd, ptr, size)
char *ptr;
size_t size;
{
- size_t result = read (fd, ptr, size);
+ ssize_t result = read (fd, ptr, size);
if (result == -1)
diff3_perror_with_exit ("read failed");
- return result;
+ return (size_t)result;
}
static void
diff --git a/contrib/cvs/man/cvs.1 b/contrib/cvs/man/cvs.1
index e9446dc..a034a6b 100644
--- a/contrib/cvs/man/cvs.1
+++ b/contrib/cvs/man/cvs.1
@@ -27,8 +27,12 @@ cvs \- Concurrent Versions System
.SH "NOTE"
This manpage is a summary of some of the features of
.B cvs
-but for more in-depth documentation, consult the Cederqvist manual (as
-described in the SEE ALSO section of this manpage).
+but it may no longer be kept up-to-date.
+For more current and in-depth documentation, please consult the
+Cederqvist manual (via the
+.B info cvs
+command or otherwise,
+as described in the SEE ALSO section of this manpage).
.SH "DESCRIPTION"
.IX "revision control system" "\fLcvs\fR"
.IX cvs "" "\fLcvs\fP \- concurrent versions system"
@@ -958,7 +962,7 @@ the
.B \-s
option within the modules file.
.TP
-\fBcommit\fP [\fB\-lnR\fP] [\fB\-m\fP '\fIlog_message\fP' | \fB\-f\fP \fIfile\fP] [\fB\-r\fP \fIrevision\fP] [\fIfiles.\|.\|.\fP]
+\fBcommit\fP [\fB\-lnR\fP] [\fB\-m\fP '\fIlog_message\fP' | \fB\-F\fP \fIfile\fP] [\fB\-r\fP \fIrevision\fP] [\fIfiles.\|.\|.\fP]
.I Requires:
working directory, repository.
.br
@@ -1494,7 +1498,7 @@ Working directory.
Working directory, history log.
.br
This command is meant to safely cancel the effect of
-.` "cvs checkout'.
+.` "cvs checkout".
Since
.B cvs
doesn't lock files, it isn't strictly necessary to use this command.
@@ -1677,6 +1681,13 @@ Use this command to assign symbolic tags to the nearest repository
versions to your working sources. The tags are applied immediately to
the repository, as with \fBrtag\fP.
.SP
+One potentially surprising aspect of the fact that \fBcvs tag\fP
+operates on the repository is that you are tagging the checked-in
+revisions, which may differ from locally modified files in your working
+directory. If you want to avoid doing this by mistake, specify the
+\fB-c\fP option to \fBcvs tag\fP. If there are any locally modified files, CVS
+will abort with an error before it tags any files.
+.SP
One use for tags is to record a ``snapshot'' of the current sources
when the software freeze date of a project arrives. As bugs are fixed
after the freeze date, only those changed sources that are to be part
@@ -1762,7 +1773,7 @@ or
.B update
keeps you informed of its progress by printing a line for each file,
prefaced with one of the characters
-.` "U A R M C ?"
+.` "U P A R M C ?"
to indicate the status of the file:
.TP 1i
\fBU\fP \fIfile\fP
@@ -1771,6 +1782,10 @@ This is done for any file that exists in the repository but not in
your source, and for files that you haven't changed but are not the most
recent versions available in the repository.
.TP 1i
+\fBP\fP \fIfile\fP
+Like \fBU\fP, but the CVS server sends a patch instead of an entire file.
+This accomplishes the same thing as \fBU\fP using less bandwidth.
+.TP 1i
\fBA\fP \fIfile\fP
The file has been \fIadded\fP to your private copy of the sources, and
will be added to the
@@ -2180,7 +2195,7 @@ command or it may be available as cvs.ps (postscript), cvs.texinfo
For CVS updates, more information on documentation, software related
to CVS, development of CVS, and more, see:
.in +1i
-.B http://www.cyclic.com
+.B http://cvshome.org
.B http://www.loria.fr/~molli/cvs-index.html
.in -1i
.SP
diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c
index a9afa49..0748988 100644
--- a/contrib/cvs/src/checkout.c
+++ b/contrib/cvs/src/checkout.c
@@ -87,19 +87,19 @@ static const char *const export_usage[] =
};
static int checkout_prune_dirs;
-static int force_tag_match = 1;
+static int force_tag_match;
static int pipeout;
static int aflag;
-static char *options = NULL;
-static char *tag = NULL;
-static int tag_validated = 0;
-static char *date = NULL;
-static char *join_rev1 = NULL;
-static char *join_rev2 = NULL;
-static int join_tags_validated = 0;
-static int pull_template = 0;
-static char *preload_update_dir = NULL;
-static char *history_name = NULL;
+static char *options;
+static char *tag;
+static int tag_validated;
+static char *date;
+static char *join_rev1;
+static char *join_rev2;
+static int join_tags_validated;
+static int pull_template;
+static char *preload_update_dir;
+static char *history_name;
static enum mtype m_type;
int
@@ -118,6 +118,18 @@ checkout (argc, argv)
char *valid_options;
const char *const *valid_usage;
+ /* initialize static options */
+ force_tag_match = 1;
+ if (options)
+ {
+ free (options);
+ options = NULL;
+ }
+ tag = date = join_rev1 = join_rev2 = preload_update_dir = NULL;
+ history_name = NULL;
+ tag_validated = join_tags_validated = 0;
+
+
/*
* A smaller subset of options are allowed for the export command, which
* is essentially like checkout, except that it hard-codes certain
@@ -257,7 +269,7 @@ checkout (argc, argv)
}
#endif
- if (!cat && !safe_location()) {
+ if (!cat && !pipeout && !safe_location( where )) {
error(1, 0, "Cannot check out files into the repository itself");
}
@@ -342,7 +354,10 @@ checkout (argc, argv)
{
cat_module (status);
if (options)
+ {
free (options);
+ options = NULL;
+ }
return (0);
}
db = open_module ();
@@ -360,17 +375,17 @@ checkout (argc, argv)
/* If we will be calling history_write, work out the name to pass
it. */
- if (m_type == CHECKOUT && !pipeout)
+ if (!pipeout)
{
- if (tag && date)
+ if (!date)
+ history_name = tag;
+ else if (!tag)
+ history_name = date;
+ else
{
history_name = xmalloc (strlen (tag) + strlen (date) + 2);
sprintf (history_name, "%s:%s", tag, date);
}
- else if (tag)
- history_name = tag;
- else
- history_name = date;
}
@@ -380,7 +395,12 @@ checkout (argc, argv)
(char *) NULL);
close_module (db);
if (options)
+ {
free (options);
+ options = NULL;
+ }
+ if (history_name != tag && history_name != date && history_name != NULL)
+ free (history_name);
return (err);
}
@@ -388,9 +408,11 @@ checkout (argc, argv)
reasons, probably want to move them. */
int
-safe_location ()
+safe_location (where)
+ char *where;
{
char *current;
+ char *where_location;
char hardpath[PATH_MAX+5];
size_t hardpath_len;
int x;
@@ -412,9 +434,68 @@ safe_location ()
{
hardpath[x] = '\0';
}
+
+ /* set current - even if where is set we'll need to cd back... */
current = xgetwd ();
if (current == NULL)
error (1, errno, "could not get working directory");
+
+ /* if where is set, set current to where, where - last_component( where ),
+ * or fail, depending on whether the directories exist or not.
+ */
+ if( where != NULL )
+ {
+ if( chdir( where ) != -1 )
+ {
+ /* where */
+ where_location = xgetwd();
+ if( where_location == NULL )
+ error( 1, errno, "could not get working directory" );
+
+ if( chdir( current ) == -1 )
+ error( 1, errno, "could not change directory to `%s'", current );
+
+ free( current );
+ current = where_location;
+ }
+ else if( errno == ENOENT )
+ {
+ if ( last_component( where ) != where )
+ {
+ /* where - last_component( where ) */
+ char *parent;
+
+ /* strip the last_component */
+ where_location = strdup( where );
+ parent = last_component( where_location );
+ parent[-1] = '\0';
+
+ if( chdir( where_location ) != -1 )
+ {
+ where_location = xgetwd();
+ if( where_location == NULL )
+ error( 1, errno, "could not get working directory (nominally `%s')", where_location );
+
+ if( chdir( current ) == -1 )
+ error( 1, errno, "could not change directory to `%s'", current );
+
+ free( current );
+ current = where_location;
+ }
+ else
+ /* fail */
+ error( 1, errno, "could not change directory to requested checkout directory `%s'", where_location );
+ }
+ /* else: ERRNO == ENOENT & last_component(where) == where
+ * for example, 'cvs co -d newdir module', where newdir hasn't
+ * been created yet, so leave current set to '.' and check that
+ */
+ }
+ else
+ /* fail */
+ error( 1, errno, "could not change directory to requested checkout directory `%s'", where );
+ }
+
hardpath_len = strlen (hardpath);
if (strlen (current) >= hardpath_len
&& strncmp (current, hardpath, hardpath_len) == 0)
@@ -860,7 +941,7 @@ internal error: %s doesn't start with %s in checkout_proc",
build_one_dir whenever the -d command option was specified
to checkout. */
- if (! where_is_absolute && top_level_admin)
+ if (! where_is_absolute && top_level_admin && m_type == CHECKOUT)
{
/* It may be argued that we shouldn't set any sticky
bits for the top-level repository. FIXME? */
@@ -1007,12 +1088,9 @@ internal error: %s doesn't start with %s in checkout_proc",
*/
if (!(local_specified || argc > 1))
{
- if (m_type == CHECKOUT && !pipeout)
- history_write ('O', preload_update_dir, history_name, where,
- repository);
- else if (m_type == EXPORT && !pipeout)
- history_write ('E', preload_update_dir, tag ? tag : date, where,
- repository);
+ if (!pipeout)
+ history_write (m_type == CHECKOUT ? 'O' : 'E', preload_update_dir,
+ history_name, where, repository);
err += do_update (0, (char **) NULL, options, tag, date,
force_tag_match, 0 /* !local */ ,
1 /* update -d */ , aflag, checkout_prune_dirs,
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index 1e332bc..1fffbdb 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -17,7 +17,7 @@
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <assert.h>
@@ -28,68 +28,67 @@
#ifdef CLIENT_SUPPORT
-#include "md5.h"
-
-#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# else /* No winsock.h */
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-# endif /* No winsock.h */
-#endif
+# include "md5.h"
+
+# if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# else /* No winsock.h */
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# endif /* No winsock.h */
+# endif
/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls
do not set errno, but that this macro should be used to obtain an
error code. This probably doesn't make sense unless
NO_SOCKET_TO_FD is also defined. */
-#ifndef SOCK_ERRNO
-#define SOCK_ERRNO errno
-#endif
+# ifndef SOCK_ERRNO
+# define SOCK_ERRNO errno
+# endif
/* If SOCK_STRERROR is defined, then the error codes returned by
socket operations are not known to strerror, and this macro must be
used instead to convert those error codes to strings. */
-#ifndef SOCK_STRERROR
-# define SOCK_STRERROR strerror
+# ifndef SOCK_STRERROR
+# define SOCK_STRERROR strerror
-# if STDC_HEADERS
-# include <string.h>
-# endif
+# if STDC_HEADERS
+# include <string.h>
+# endif
-# ifndef strerror
+# ifndef strerror
extern char *strerror ();
-# endif
-#endif /* ! SOCK_STRERROR */
+# endif
+# endif /* ! SOCK_STRERROR */
-#if HAVE_KERBEROS
-#define CVS_PORT 1999
+# if HAVE_KERBEROS
-#include <krb.h>
+# include <krb.h>
extern char *krb_realmofhost ();
-#ifndef HAVE_KRB_GET_ERR_TEXT
-#define krb_get_err_text(status) krb_err_txt[status]
-#endif /* HAVE_KRB_GET_ERR_TEXT */
+# ifndef HAVE_KRB_GET_ERR_TEXT
+# define krb_get_err_text(status) krb_err_txt[status]
+# endif /* HAVE_KRB_GET_ERR_TEXT */
/* Information we need if we are going to use Kerberos encryption. */
static C_Block kblock;
static Key_schedule sched;
-#endif /* HAVE_KERBEROS */
+# endif /* HAVE_KERBEROS */
-#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSAPI
-# include "xgssapi.h"
+# include "xgssapi.h"
/* This is needed for GSSAPI encryption. */
static gss_ctx_id_t gcontext;
-static int connect_to_gserver PROTO((int, struct hostent *));
+static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *));
-#endif /* HAVE_GSSAPI */
+# endif /* HAVE_GSSAPI */
static void add_prune_candidate PROTO((char *));
@@ -138,9 +137,9 @@ static void handle_f PROTO((char *, int));
static void handle_notified PROTO((char *, int));
static size_t try_read_from_server PROTO ((char *, size_t));
-#endif /* CLIENT_SUPPORT */
-
-#ifdef CLIENT_SUPPORT
+
+static void auth_server PROTO ((cvsroot_t *, struct buffer *, struct buffer *,
+ int, int, struct hostent *));
/* We need to keep track of the list of directories we've sent to the
server. This list, along with the current CVSROOT, will help us
@@ -271,8 +270,11 @@ arg_should_not_be_sent_to_server (arg)
}
+
#endif /* CLIENT_SUPPORT */
-
+
+
+
#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
/* Shared with server. */
@@ -442,16 +444,9 @@ static List *ignlist = (List *) NULL;
/* Buffer to write to the server. */
static struct buffer *to_server;
-/* The stream underlying to_server, if we are using a stream. */
-static FILE *to_server_fp;
/* Buffer used to read from the server. */
static struct buffer *from_server;
-/* The stream underlying from_server, if we are using a stream. */
-static FILE *from_server_fp;
-
-/* Process ID of rsh subprocess. */
-static int rsh_pid = -1;
/* We want to be able to log data sent between us and the server. We
@@ -474,7 +469,7 @@ static int log_buffer_input PROTO((void *, char *, int, int, int *));
static int log_buffer_output PROTO((void *, const char *, int, int *));
static int log_buffer_flush PROTO((void *));
static int log_buffer_block PROTO((void *, int));
-static int log_buffer_shutdown PROTO((void *));
+static int log_buffer_shutdown PROTO((struct buffer *));
/* Create a log buffer. */
@@ -598,10 +593,10 @@ log_buffer_block (closure, block)
/* The shutdown function for a log buffer. */
static int
-log_buffer_shutdown (closure)
- void *closure;
+log_buffer_shutdown (buf)
+ struct buffer *buf;
{
- struct log_buffer *lb = (struct log_buffer *) closure;
+ struct log_buffer *lb = (struct log_buffer *) buf->closure;
int retval;
retval = buf_shutdown (lb->buf);
@@ -609,7 +604,7 @@ log_buffer_shutdown (closure)
error (0, errno, "closing log file");
return retval;
}
-
+
#ifdef NO_SOCKET_TO_FD
/* Under certain circumstances, we must communicate with the server
@@ -622,9 +617,6 @@ log_buffer_shutdown (closure)
in these cases. This is handled through the SOCK_ERRNO and
SOCK_STRERROR macros. */
-static int use_socket_style = 0;
-static int server_sock;
-
/* These routines implement a buffer structure which uses send and
recv. The buffer is always in blocking mode so we don't implement
the block routine. */
@@ -648,14 +640,17 @@ static struct buffer *socket_buffer_initialize
static int socket_buffer_input PROTO((void *, char *, int, int, int *));
static int socket_buffer_output PROTO((void *, const char *, int, int *));
static int socket_buffer_flush PROTO((void *));
+static int socket_buffer_shutdown PROTO((struct buffer *));
+
+
/* Create a buffer based on a socket. */
static struct buffer *
socket_buffer_initialize (socket, input, memory)
- int socket;
- int input;
- void (*memory) PROTO((struct buffer *));
+ int socket;
+ int input;
+ void (*memory) PROTO((struct buffer *));
{
struct socket_buffer *n;
@@ -665,11 +660,13 @@ socket_buffer_initialize (socket, input, memory)
input ? NULL : socket_buffer_output,
input ? NULL : socket_buffer_flush,
(int (*) PROTO((void *, int))) NULL,
- (int (*) PROTO((void *))) NULL,
+ socket_buffer_shutdown,
memory,
n);
}
+
+
/* The buffer input function for a buffer built on a socket. */
static int
@@ -729,6 +726,8 @@ socket_buffer_input (closure, data, need, size, got)
return 0;
}
+
+
/* The buffer output function for a buffer built on a socket. */
static int
@@ -768,6 +767,8 @@ socket_buffer_output (closure, data, have, wrote)
return 0;
}
+
+
/* The buffer flush function for a buffer built on a socket. */
/*ARGSUSED*/
@@ -779,8 +780,61 @@ socket_buffer_flush (closure)
return 0;
}
+
+
+static int
+socket_buffer_shutdown (buf)
+ struct buffer *buf;
+{
+ struct socket_buffer *n = (struct socket_buffer *) buf->closure;
+ char tmp;
+
+ /* no need to flush children of an endpoint buffer here */
+
+ if (buf->input)
+ {
+ int err = 0;
+ if (! buf_empty_p (buf)
+ || (err = recv (n->socket, &tmp, 1, 0)) > 0)
+ error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
+ else if (err == -1)
+ error (0, 0, "reading from %s: %s", current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ if (current_parsed_root->method != server_method)
+# endif
+ if (shutdown (n->socket, 0) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->input = NULL;
+ }
+ else if (buf->output)
+ {
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ /* FIXME: Should have a SHUTDOWN_SERVER_INPUT &
+ * SHUTDOWN_SERVER_OUTPUT
+ */
+ if (current_parsed_root->method == server_method)
+ SHUTDOWN_SERVER (n->socket);
+ else
+# endif
+ if (shutdown (n->socket, 1) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->output = NULL;
+ }
+
+ return 0;
+}
+
#endif /* NO_SOCKET_TO_FD */
-
+
/*
* Read a line from the server. Result does not include the terminating \n.
*
@@ -3523,7 +3577,6 @@ get_server_responses ()
}
/* Get the responses and then close the connection. */
-int server_fd = -1;
/*
* Flag var; we'll set it in start_server() and not one of its
@@ -3552,79 +3605,18 @@ get_responses_and_close ()
if (client_prune_dirs)
process_prune_candidates ();
- /* The calls to buf_shutdown are currently only meaningful when we
- are using compression. First we shut down TO_SERVER. That
- tells the server that its input is finished. It then shuts
- down the buffer it is sending to us, at which point our shut
- down of FROM_SERVER will complete. */
+ /* First we shut down TO_SERVER. That tells the server that its input is
+ * finished. It then shuts down the buffer it is sending to us, at which
+ * point our shut down of FROM_SERVER will complete.
+ */
status = buf_shutdown (to_server);
if (status != 0)
- error (0, status, "shutting down buffer to server");
+ error (0, status, "shutting down buffer to server");
status = buf_shutdown (from_server);
if (status != 0)
error (0, status, "shutting down buffer from server");
-#ifdef NO_SOCKET_TO_FD
- if (use_socket_style)
- {
- if (shutdown (server_sock, 2) < 0)
- error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
- }
- else
-#endif /* NO_SOCKET_TO_FD */
- {
-#if defined(HAVE_KERBEROS) || defined(AUTH_CLIENT_SUPPORT)
- if (server_fd != -1)
- {
- if (shutdown (server_fd, 1) < 0)
- error (1, 0, "shutting down connection to %s: %s",
- current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
- server_fd = -1;
- /*
- * This test will always be true because we dup the descriptor
- */
- if (fileno (from_server_fp) != fileno (to_server_fp))
- {
- if (fclose (to_server_fp) != 0)
- error (1, errno,
- "closing down connection to %s",
- current_parsed_root->hostname);
- }
- }
- else
-#endif
-
-#ifdef SHUTDOWN_SERVER
- SHUTDOWN_SERVER (fileno (to_server_fp));
-#else /* ! SHUTDOWN_SERVER */
- {
-
-#ifdef START_RSH_WITH_POPEN_RW
- if (pclose (to_server_fp) == EOF)
-#else /* ! START_RSH_WITH_POPEN_RW */
- if (fclose (to_server_fp) == EOF)
-#endif /* START_RSH_WITH_POPEN_RW */
- {
- error (1, errno, "closing connection to %s",
- current_parsed_root->hostname);
- }
- }
-
- if (! buf_empty_p (from_server)
- || getc (from_server_fp) != EOF)
- error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
- else if (ferror (from_server_fp))
- error (0, errno, "reading from %s", current_parsed_root->hostname);
-
- fclose (from_server_fp);
-#endif /* SHUTDOWN_SERVER */
- }
-
- if (rsh_pid != -1
- && waitpid (rsh_pid, (int *) 0, 0) == -1)
- error (1, errno, "waiting for process %d", rsh_pid);
-
buf_free (to_server);
buf_free (from_server);
server_started = 0;
@@ -3639,7 +3631,7 @@ get_responses_and_close ()
}
#ifndef NO_EXT_METHOD
-static void start_rsh_server PROTO((int *, int *));
+static void start_rsh_server PROTO((cvsroot_t *, struct buffer **, struct buffer **));
#endif
int
@@ -3762,68 +3754,82 @@ get_cvs_port_number (root)
method_names[root->method]);
break;
}
+ /* NOTREACHED */
+ return -1;
}
-/* 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.
- It is possible it should use the buffers too, which would be faster
- (unlike the server, there isn't really a security issue in terms of
- separating authentication from the rest of the code).
-
- Space for the result is malloc'd and should be freed by the caller.
-
- Returns number of bytes read. */
-static int
-recv_line (sock, resultp)
- int sock;
- char **resultp;
+void
+make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock)
+ int tofd;
+ int fromfd;
+ int child_pid;
+ struct buffer **to_server;
+ struct buffer **from_server;
+ int is_sock;
{
- char *result;
- size_t input_index = 0;
- size_t result_size = 80;
-
- result = (char *) xmalloc (result_size);
+ FILE *to_server_fp;
+ FILE *from_server_fp;
- while (1)
+#ifdef NO_SOCKET_TO_FD
+ if (is_sock)
{
- char ch;
- int n;
- n = recv (sock, &ch, 1, 0);
- if (n <= 0)
- error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname,
- n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
-
- if (ch == '\012')
- break;
+ assert (tofd == fromfd);
+ *to_server = socket_buffer_initialize (tofd, 0,
+ (BUFMEMERRPROC) NULL);
+ *from_server = socket_buffer_initialize (tofd, 1,
+ (BUFMEMERRPROC) NULL);
+ }
+ else
+#endif /* NO_SOCKET_TO_FD */
+ {
+ /* todo: some OS's don't need these calls... */
+ close_on_exec (tofd);
+ close_on_exec (fromfd);
- result[input_index++] = ch;
- while (input_index + 1 >= result_size)
+ /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
+ fdopening the same file descriptor twice, so dup it if it is the
+ same. */
+ if (tofd == fromfd)
{
- result_size *= 2;
- result = (char *) xrealloc (result, result_size);
+ fromfd = dup (tofd);
+ if (fromfd < 0)
+ error (1, errno, "cannot dup net connection");
}
- }
- if (resultp)
- *resultp = result;
-
- /* Terminate it just for kicks, but we *can* deal with embedded NULs. */
- result[input_index] = '\0';
+ /* These will use binary mode on systems which have it. */
+ /*
+ * Also, we know that from_server is shut down second, so we pass
+ * child_pid in there. In theory, it should be stored in both
+ * buffers with a ref count...
+ */
+ to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE);
+ if (to_server_fp == NULL)
+ error (1, errno, "cannot fdopen %d for write", tofd);
+ *to_server = stdio_buffer_initialize (to_server_fp, 0, 0,
+ (BUFMEMERRPROC) NULL);
- if (resultp == NULL)
- free (result);
- return input_index;
+ from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ);
+ if (from_server_fp == NULL)
+ error (1, errno, "cannot fdopen %d for read", fromfd);
+ *from_server = stdio_buffer_initialize (from_server_fp, child_pid, 1,
+ (BUFMEMERRPROC) NULL);
+ }
}
+
+
/* Connect to a forked server process. */
void
-connect_to_forked_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+connect_to_forked_server (to_server, from_server)
+ struct buffer **to_server;
+ struct buffer **from_server;
{
+ int tofd, fromfd;
+ int child_pid;
+
/* This is pretty simple. All we need to do is choose the correct
cvs binary and call piped_child. */
@@ -3840,8 +3846,12 @@ connect_to_forked_server (tofdp, fromfdp)
{
fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]);
}
- if (! piped_child (command, tofdp, fromfdp))
+
+ child_pid = piped_child (command, &tofd, &fromfd);
+ if (child_pid < 0)
error (1, 0, "could not fork server process");
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
}
/* Connect to the authenticating server.
@@ -3857,51 +3867,113 @@ connect_to_forked_server (tofdp, fromfdp)
If we fail to connect or if access is denied, then die with fatal
error. */
void
-connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
- int *tofdp, *fromfdp;
- int verify_only;
- int do_gssapi;
+connect_to_pserver (root, to_server_p, from_server_p, verify_only, do_gssapi)
+ cvsroot_t *root;
+ struct buffer **to_server_p;
+ struct buffer **from_server_p;
+ int verify_only;
+ int do_gssapi;
{
int sock;
-#ifndef NO_SOCKET_TO_FD
- 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 */
+ struct buffer *to_server, *from_server;
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
}
- port_number = get_cvs_port_number (current_parsed_root);
- hostinfo = init_sockaddr (&client_sai, current_parsed_root->hostname, port_number);
+ port_number = get_cvs_port_number (root);
+ hostinfo = init_sockaddr (&client_sai, root->hostname, port_number);
if (trace)
{
fprintf (stderr, " -> Connecting to %s(%s):%d\n",
- current_parsed_root->hostname,
+ 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(%s):%d failed: %s",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (client_sai.sin_addr),
port_number, SOCK_STRERROR (SOCK_ERRNO));
+ make_bufs_from_fds (sock, sock, 0, &to_server, &from_server, 1);
+
+ auth_server (root, to_server, from_server, verify_only, do_gssapi, hostinfo);
+
+ if (verify_only)
+ {
+ int status;
+
+ status = buf_shutdown (to_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer to server");
+ status = buf_shutdown (from_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer from server");
+
+ buf_free (to_server);
+ buf_free (from_server);
+
+ /* Don't need to set server_started = 0 since we don't set it to 1
+ * until returning from this call.
+ */
+ }
+ else
+ {
+ *to_server_p = to_server;
+ *from_server_p = from_server;
+ }
+
+ return;
+}
+
+
+
+static void
+auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
+ cvsroot_t *root;
+ struct buffer *lto_server;
+ struct buffer *lfrom_server;
+ int verify_only;
+ int do_gssapi;
+ struct hostent *hostinfo;
+{
+ char *username; /* the username we use to connect */
+ char no_passwd = 0; /* gets set if no password found */
+
+ /* FIXME!!!!!!!!!!!!!!!!!!
+ *
+ * THIS IS REALLY UGLY!
+ *
+ * I'm setting the globals here so we can make calls to send_to_server &
+ * read_line. This happens again _after_ we return if we're not in
+ * verify_only mode. We should be relying on the values we passed in, but
+ * sent_to_server and read_line don't require an outside buf yet.
+ */
+ to_server = lto_server;
+ from_server = lfrom_server;
+
/* Run the authorization mini-protocol before anything else. */
if (do_gssapi)
{
#ifdef HAVE_GSSAPI
- if (! connect_to_gserver (sock, hostinfo))
+ int fd = (int) lto_server->closure;
+ struct stat s;
+
+ if (fstat (fd, &s) < 0 || !S_ISSOCK(s.st_mode))
{
- error (0, 0,
+ error (1, 0, "gserver currently only enabled for socket connections");
+ }
+
+ if (! connect_to_gserver (root, fd, hostinfo))
+ {
+ error (1, 0,
"authorization failed: server %s rejected access to %s",
- current_parsed_root->hostname, current_parsed_root->directory);
- goto rejected;
+ root->hostname, root->directory);
}
#else
error (1, 0, "This client does not support GSSAPI authentication");
@@ -3915,48 +3987,42 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
if (verify_only)
{
- begin = "BEGIN VERIFICATION REQUEST\012";
- end = "END VERIFICATION REQUEST\012";
+ begin = "BEGIN VERIFICATION REQUEST";
+ end = "END VERIFICATION REQUEST";
}
else
{
- begin = "BEGIN AUTH REQUEST\012";
- end = "END AUTH REQUEST\012";
+ begin = "BEGIN AUTH REQUEST";
+ end = "END AUTH REQUEST";
}
/* Get the password, probably from ~/.cvspass. */
password = get_cvs_password ();
- username = current_parsed_root->username ? current_parsed_root->username : getcaller();
+ username = root->username ? 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)
- {
- no_passwd = 1;
- password = scramble ("");
- }
+ /* Send the empty string by default. This is so anonymous CVS
+ access doesn't require client to have done "cvs login". */
+ if (password == NULL)
+ {
+ no_passwd = 1;
+ password = scramble ("");
+ }
/* Announce that we're starting the authorization protocol. */
- if (send (sock, begin, strlen (begin), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ send_to_server(begin, 0);
+ send_to_server("\012", 1);
/* Send the data the server needs. */
- 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));
- if (send (sock, username, strlen (username), 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));
- if (send (sock, password, strlen (password), 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));
+ send_to_server(root->directory, 0);
+ send_to_server("\012", 1);
+ send_to_server(username, 0);
+ send_to_server("\012", 1);
+ send_to_server(password, 0);
+ send_to_server("\012", 1);
/* Announce that we're ending the authorization protocol. */
- if (send (sock, end, strlen (end), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ send_to_server(end, 0);
+ send_to_server("\012", 1);
/* Paranoia. */
memset (password, 0, strlen (password));
@@ -3968,7 +4034,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
/* Loop, getting responses from the server. */
while (1)
{
- recv_line (sock, &read_buf);
+ read_line (&read_buf);
if (strcmp (read_buf, "I HATE YOU") == 0)
{
@@ -3980,12 +4046,12 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
* 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
+ * i.e. This is a pserver specific error message and should 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);
+ root->hostname, root->directory, username);
/* Output a special error message if authentication was attempted
with no password -- the user should be made aware that they may
@@ -3995,7 +4061,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
error (0, 0,
"used empty password; try \"cvs login\" with a real password");
}
- goto rejected;
+ error_exit();
}
else if (strncmp (read_buf, "E ", 2) == 0)
{
@@ -4018,7 +4084,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
/* Now output the text. */
fprintf (stderr, "%s\n", p);
- goto rejected;
+ error_exit();
}
else if (strcmp (read_buf, "I LOVE YOU") == 0)
{
@@ -4027,62 +4093,13 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
}
else
{
- /* Unrecognized response from server. */
- if (shutdown (sock, 2) < 0)
- {
- error (0, 0,
- "unrecognized auth response from %s: %s",
- current_parsed_root->hostname, read_buf);
- error (1, 0,
- "shutdown() failed, server %s: %s",
- current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- }
error (1, 0,
"unrecognized auth response from %s: %s",
- current_parsed_root->hostname, read_buf);
+ root->hostname, read_buf);
}
free (read_buf);
}
}
-
- if (verify_only)
- {
- if (shutdown (sock, 2) < 0)
- error (0, 0, "shutdown() failed, server %s: %s", current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- return;
- }
- else
- {
-#ifdef NO_SOCKET_TO_FD
- use_socket_style = 1;
- server_sock = sock;
- /* Try to break mistaken callers: */
- *tofdp = 0;
- *fromfdp = 0;
-#else /* ! NO_SOCKET_TO_FD */
- server_fd = sock;
- close_on_exec (server_fd);
- tofd = fromfd = sock;
- /* Hand them back to the caller. */
- *tofdp = tofd;
- *fromfdp = fromfd;
-#endif /* NO_SOCKET_TO_FD */
- }
-
- return;
-
- rejected:
- if (shutdown (sock, 2) < 0)
- {
- error (0, 0,
- "shutdown() failed (server %s): %s",
- current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- }
-
- error_exit();
}
#endif /* AUTH_CLIENT_SUPPORT */
@@ -4094,10 +4111,12 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
(i.e., systems on which sockets cannot be converted to file
descriptors). The first person to try building a kerberos client
on such a system (OS/2, Windows 95, and maybe others) will have to
- make take care of this. */
+ take care of this. */
void
-start_tcp_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+start_tcp_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
int s;
const char *portenv;
@@ -4110,9 +4129,9 @@ start_tcp_server (tofdp, fromfdp)
if (s < 0)
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
- port = get_cvs_port_number (current_parsed_root);
+ port = get_cvs_port_number (root);
- hp = init_sockaddr (&sin, current_parsed_root->hostname, port);
+ hp = init_sockaddr (&sin, root->hostname, port);
hname = xmalloc (strlen (hp->h_name) + 1);
strcpy (hname, hp->h_name);
@@ -4120,13 +4139,13 @@ start_tcp_server (tofdp, fromfdp)
if (trace)
{
fprintf (stderr, " -> Connecting to %s(%s):%d\n",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (sin.sin_addr), port);
}
if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
error (1, 0, "connect to %s(%s):%d failed: %s",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (sin.sin_addr),
port, SOCK_STRERROR (SOCK_ERRNO));
@@ -4155,14 +4174,12 @@ start_tcp_server (tofdp, fromfdp)
memcpy (kblock, cred.session, sizeof (C_Block));
}
- server_fd = s;
- close_on_exec (server_fd);
+ close_on_exec (s);
free (hname);
/* Give caller the values it wants. */
- *tofdp = s;
- *fromfdp = s;
+ make_bufs_from_fds (s, s, 0, to_server, from_server, 1);
}
#endif /* HAVE_KERBEROS */
@@ -4193,13 +4210,29 @@ recv_bytes (sock, buf, need)
/* Connect to the server using GSSAPI authentication. */
+/* FIXME
+ *
+ * This really needs to be rewritten to use a buffer and not a socket.
+ * This would enable gserver to work with the SSL code I'm about to commit
+ * since the SSL connection is going to look like a FIFO and not a socket.
+ *
+ * I think, basically, it will need to use buf_output and buf_read directly
+ * since I don't think there is a read_bytes function - only read_line.
+ *
+ * recv_bytes could then be removed too.
+ *
+ * Besides, I added some cruft to reenable the socket which shouldn't be
+ * there. This would also enable its removal.
+ */
+#define BUFSIZE 1024
static int
-connect_to_gserver (sock, hostinfo)
- int sock;
- struct hostent *hostinfo;
+connect_to_gserver (root, sock, hostinfo)
+ cvsroot_t *root;
+ int sock;
+ struct hostent *hostinfo;
{
char *str;
- char buf[1024];
+ char buf[BUFSIZE];
gss_buffer_desc *tok_in_ptr, tok_in, tok_out;
OM_uint32 stat_min, stat_maj;
gss_name_t server_name;
@@ -4209,6 +4242,8 @@ connect_to_gserver (sock, hostinfo)
if (send (sock, str, strlen (str), 0) < 0)
error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ if (strlen (hostinfo->h_name) > BUFSIZE - 5)
+ error (1, 0, "Internal error: hostname exceeds length of buffer");
sprintf (buf, "cvs@%s", hostinfo->h_name);
tok_in.length = strlen (buf);
tok_in.value = buf;
@@ -4278,11 +4313,11 @@ connect_to_gserver (sock, hostinfo)
got = recv (sock, buf + 2, sizeof buf - 2, 0);
if (got < 0)
error (1, 0, "recv() from server %s: %s",
- current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+ 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", current_parsed_root->hostname,
+ error (1, 0, "error from server %s: %s", root->hostname,
buf);
}
@@ -4319,10 +4354,9 @@ send_variable_proc (node, closure)
void
start_server ()
{
- int tofd, fromfd, rootless;
+ int rootless;
char *log = getenv ("CVS_CLIENT_LOG");
-
/* Clear our static variables for this invocation. */
if (toplevel_repos != NULL)
free (toplevel_repos);
@@ -4339,22 +4373,23 @@ start_server ()
#ifdef AUTH_CLIENT_SUPPORT
case pserver_method:
- /* Toss the return value. It will die with error if anything
- goes wrong anyway. */
- connect_to_pserver (&tofd, &fromfd, 0, 0);
+ /* Toss the return value. It will die with an error message if
+ * anything goes wrong anyway.
+ */
+ connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 0);
break;
#endif
#if HAVE_KERBEROS
case kserver_method:
- start_tcp_server (&tofd, &fromfd);
+ start_tcp_server (current_parsed_root, &to_server, &from_server);
break;
#endif
#ifdef HAVE_GSSAPI
case gserver_method:
/* GSSAPI authentication is handled by the pserver. */
- connect_to_pserver (&tofd, &fromfd, 0, 1);
+ connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 1);
break;
#endif
@@ -4363,34 +4398,34 @@ start_server ()
error (0, 0, ":ext: method not supported by this port of CVS");
error (1, 0, "try :server: instead");
#else
- start_rsh_server (&tofd, &fromfd);
+ start_rsh_server (current_parsed_root, &to_server, &from_server);
#endif
break;
case server_method:
#if defined(START_SERVER)
+ {
+ int tofd, fromfd;
START_SERVER (&tofd, &fromfd, getcaller (),
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
- return a socket. */
- use_socket_style = 1;
- server_sock = tofd;
-# endif
-
+# ifdef START_SERVER_RETURNS_SOCKET
+ make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 1);
+# else
+ make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 0);
+# endif /* START_SERVER_RETURNS_SOCKET */
+ }
#else
/* FIXME: It should be possible to implement this portably,
like pserver, which would get rid of the duplicated code
in {vms,windows-NT,...}/startserver.c. */
- error (1, 0, "\
-the :server: access method is not supported by this port of CVS");
+ error (1, 0,
+"the :server: access method is not supported by this port of CVS");
#endif
break;
case fork_method:
- connect_to_forked_server (&tofd, &fromfd);
+ connect_to_forked_server (&to_server, &from_server);
break;
default:
@@ -4402,46 +4437,11 @@ the :server: access method is not supported by this port of CVS");
/* "Hi, I'm Darlene and I'll be your server tonight..." */
server_started = 1;
-#ifdef NO_SOCKET_TO_FD
- if (use_socket_style)
- {
- to_server = socket_buffer_initialize (server_sock, 0,
- (BUFMEMERRPROC) NULL);
- from_server = socket_buffer_initialize (server_sock, 1,
- (BUFMEMERRPROC) NULL);
- }
- else
-#endif /* NO_SOCKET_TO_FD */
- {
- /* todo: some OS's don't need these calls... */
- close_on_exec (tofd);
- close_on_exec (fromfd);
-
- /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
- fdopening the same file descriptor twice, so dup it if it is the
- same. */
- if (tofd == fromfd)
- {
- fromfd = dup (tofd);
- if (fromfd < 0)
- error (1, errno, "cannot dup net connection");
- }
-
- /* These will use binary mode on systems which have it. */
- to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE);
- if (to_server_fp == NULL)
- error (1, errno, "cannot fdopen %d for write", tofd);
- to_server = stdio_buffer_initialize (to_server_fp, 0,
- (BUFMEMERRPROC) NULL);
-
- from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ);
- if (from_server_fp == NULL)
- error (1, errno, "cannot fdopen %d for read", fromfd);
- from_server = stdio_buffer_initialize (from_server_fp, 1,
- (BUFMEMERRPROC) NULL);
- }
-
- /* Set up logfiles, if any. */
+ /* Set up logfiles, if any.
+ *
+ * We do this _after_ authentication on purpose. Wouldn't really like to
+ * worry about logging passwords...
+ */
if (log)
{
int len = strlen (log);
@@ -4767,7 +4767,7 @@ the :server: access method is not supported by this port of CVS");
implementing piped_child)... but I'm doing something else at the
moment, and wish to make only one change at a time. -Karl */
-#ifdef START_RSH_WITH_POPEN_RW
+# ifdef START_RSH_WITH_POPEN_RW
/* This is actually a crock -- it's OS/2-specific, for no one else
uses it. If I get time, I want to make piped_child and all the
@@ -4775,10 +4775,13 @@ the :server: access method is not supported by this port of CVS");
up and running, and that's most important. */
static void
-start_rsh_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+start_rsh_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
int pipes[2];
+ int child_pid;
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
@@ -4818,19 +4821,19 @@ start_rsh_server (tofdp, fromfdp)
/* The command line starts out with rsh. */
rsh_argv[i++] = cvs_rsh;
-#ifdef RSH_NEEDS_BINARY_FLAG
+# ifdef RSH_NEEDS_BINARY_FLAG
/* "-b" for binary, under OS/2. */
rsh_argv[i++] = "-b";
-#endif /* RSH_NEEDS_BINARY_FLAG */
+# endif /* RSH_NEEDS_BINARY_FLAG */
/* Then we strcat more things on the end one by one. */
- if (current_parsed_root->username != NULL)
+ if (root->username != NULL)
{
rsh_argv[i++] = "-l";
- rsh_argv[i++] = current_parsed_root->username;
+ rsh_argv[i++] = root->username;
}
- rsh_argv[i++] = current_parsed_root->hostname;
+ rsh_argv[i++] = root->hostname;
rsh_argv[i++] = cvs_server;
rsh_argv[i++] = "server";
@@ -4846,21 +4849,21 @@ start_rsh_server (tofdp, fromfdp)
}
/* Do the deed. */
- rsh_pid = popenRW (rsh_argv, pipes);
- if (rsh_pid < 0)
+ child_pid = popenRW (rsh_argv, pipes);
+ if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
- /* Give caller the file descriptors. */
- *tofdp = pipes[0];
- *fromfdp = pipes[1];
+ /* Give caller the file descriptors in a form it can deal with. */
+ make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server, from_server, 0);
}
-#else /* ! START_RSH_WITH_POPEN_RW */
+# else /* ! START_RSH_WITH_POPEN_RW */
static void
-start_rsh_server (tofdp, fromfdp)
- int *tofdp;
- int *fromfdp;
+start_rsh_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
@@ -4868,6 +4871,8 @@ start_rsh_server (tofdp, fromfdp)
char *cvs_rsh = getenv ("CVS_RSH");
char *cvs_server = getenv ("CVS_SERVER");
char *command;
+ int tofd, fromfd;
+ int child_pid;
if (!cvs_rsh)
cvs_rsh = "ssh";
@@ -4878,9 +4883,7 @@ start_rsh_server (tofdp, fromfdp)
affect most rsh servers at all, and will pacify some buggy
versions of rsh that grab switches out of the middle of the
command (they're calling the GNU getopt routines incorrectly). */
- command = xmalloc (strlen (cvs_server)
- + strlen (current_parsed_root->directory)
- + 50);
+ command = xmalloc (strlen (cvs_server) + 8);
/* If you are running a very old (Nov 3, 1994, before 1.5)
* version of the server, you need to make sure that your .bashrc
@@ -4893,15 +4896,15 @@ start_rsh_server (tofdp, fromfdp)
char **p = argv;
*p++ = cvs_rsh;
- *p++ = current_parsed_root->hostname;
+ *p++ = root->hostname;
/* If the login names differ between client and server
* pass it on to rsh.
*/
- if (current_parsed_root->username != NULL)
+ if (root->username != NULL)
{
*p++ = "-l";
- *p++ = current_parsed_root->username;
+ *p++ = root->username;
}
*p++ = command;
@@ -4916,19 +4919,21 @@ start_rsh_server (tofdp, fromfdp)
fprintf (stderr, "%s ", argv[i]);
putc ('\n', stderr);
}
- rsh_pid = piped_child (argv, tofdp, fromfdp);
+ child_pid = piped_child (argv, &tofd, &fromfd);
- if (rsh_pid < 0)
+ if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
}
free (command);
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
}
-#endif /* START_RSH_WITH_POPEN_RW */
+# endif /* START_RSH_WITH_POPEN_RW */
#endif /* NO_EXT_METHOD */
-
+
/* Send an argument STRING. */
void
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 226b09b..a951f49 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -352,9 +352,10 @@ commit (argc, argv)
struct passwd *pw;
if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
- error (1, 0, "you are unknown to this system");
+ error (1, 0, "your apparent username (%s) is unknown to this system",
+ getcaller ());
if (pw->pw_uid == (uid_t) 0)
- error (1, 0, "cannot commit files as 'root'");
+ error (1, 0, "'root' is not allowed to commit files");
}
#endif /* CVS_BADROOT */
@@ -496,11 +497,6 @@ commit (argc, argv)
if (use_editor)
do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
- /* Run the user-defined script to verify/check information in
- *the log message
- */
- do_verify (&saved_message, (char *)NULL);
-
/* We always send some sort of message, even if empty. */
/* FIXME: is that true? There seems to be some code in do_editor
which can leave the message NULL. */
@@ -1576,7 +1572,7 @@ commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
this being a confusing feature! */
if (err == 0 && write_dirtag != NULL)
{
- char *repos = Name_Repository (dir, update_dir);
+ char *repos = Name_Repository (NULL, update_dir);
WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
update_dir, repos);
free (repos);
@@ -1810,7 +1806,7 @@ unlockrcs (rcs)
{
int retcode;
- if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0)
+ if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0)
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"could not unlock %s", rcs->path);
else
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index d8b5c89..ac2de4a 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -82,8 +82,11 @@ extern int errno;
#include "system.h"
#include "hash.h"
+
+#include "root.h"
+
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
-#include "client.h"
+# include "client.h"
#endif
#ifdef MY_NDBM
@@ -369,26 +372,7 @@ extern int cvswrite;
extern mode_t cvsumask;
extern char *RCS_citag;
-/* Access method specified in CVSroot. */
-typedef enum {
- null_method, local_method, server_method, pserver_method, kserver_method, gserver_method,
- 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
@@ -401,7 +385,7 @@ extern List *root_directories;
extern cvsroot_t *current_parsed_root;
extern char *emptydir_name PROTO ((void));
-extern int safe_location PROTO ((void));
+extern int safe_location PROTO ((char *));
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
@@ -411,6 +395,12 @@ extern int require_real_user; /* skip CVSROOT/passwd, /etc/passwd users only*/
extern int top_level_admin;
+
+#define LOGMSG_REREAD_NEVER 0 /* do_verify - never reread message */
+#define LOGMSG_REREAD_ALWAYS 1 /* do_verify - always reread message */
+#define LOGMSG_REREAD_STAT 2 /* do_verify - reread message if changed */
+extern int RereadLogAfterVerify;
+
#ifdef CLIENT_SUPPORT
extern List *dirs_sent_to_server; /* used to decide which "Argument
xxx" commands to send to each
@@ -482,7 +472,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 *));
+void xrealloc_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));
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c
index 8d001c6..be1fb5f 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -64,24 +64,71 @@ static size_t opts_allocated = 1;
static int diff_errors;
static int empty_files = 0;
-/* FIXME: should be documenting all the options here. They don't
- perfectly match rcsdiff options (for example, we always support
- --ifdef and --context, but rcsdiff only does if diff does). */
static const char *const diff_usage[] =
{
- "Usage: %s %s [-lNR] [rcsdiff-options]\n",
+ "Usage: %s %s [-lR] [-k kopt] [format_options]\n",
" [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n",
"\t-l\tLocal directory only, not recursive\n",
"\t-R\tProcess directories recursively.\n",
+ "\t-k kopt\tSpecify keyword expansion mode.\n",
"\t-D d1\tDiff revision for date against working file.\n",
"\t-D d2\tDiff rev1/date1 against date2.\n",
- "\t-N\tinclude diffs for added and removed files.\n",
"\t-r rev1\tDiff revision for rev1 against working file.\n",
"\t-r rev2\tDiff rev1/date1 against rev2.\n",
- "\t--ifdef=arg\tOutput diffs in ifdef format.\n",
- "(consult the documentation for your diff program for rcsdiff-options.\n",
- "The most popular is -c for context diffs but there are many more).\n",
- "(Specify the --help global option for a list of other help options)\n",
+ "\nformat_options:\n",
+ " -i --ignore-case Consider upper- and lower-case to be the same.\n",
+ " -w --ignore-all-space Ignore all white space.\n",
+ " -b --ignore-space-change Ignore changes in the amount of white space.\n",
+ " -B --ignore-blank-lines Ignore changes whose lines are all blank.\n",
+ " -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n",
+ " --binary Read and write data in binary mode.\n",
+ " -a --text Treat all files as text.\n\n",
+ " -c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.\n",
+ " -u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.\n",
+ " -NUM Use NUM context lines.\n",
+ " -L LABEL --label LABEL Use LABEL instead of file name.\n",
+ " -p --show-c-function Show which C function each change is in.\n",
+ " -F RE --show-function-line=RE Show the most recent line matching RE.\n",
+ " --brief Output only whether files differ.\n",
+ " -e --ed Output an ed script.\n",
+ " -f --forward-ed Output something like an ed script in forward order.\n",
+ " -n --rcs Output an RCS format diff.\n",
+ " -y --side-by-side Output in two columns.\n",
+ " -W NUM --width=NUM Output at most NUM (default 130) characters per line.\n",
+ " --left-column Output only the left column of common lines.\n",
+ " --suppress-common-lines Do not output common lines.\n",
+ " --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.\n",
+ " --GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.\n",
+ " --line-format=LFMT Similar, but format all input lines with LFMT.\n",
+ " --LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.\n",
+ " LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.\n",
+ " GFMT may contain:\n",
+ " %%< lines from FILE1\n",
+ " %%> lines from FILE2\n",
+ " %%= lines common to FILE1 and FILE2\n",
+ " %%[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n",
+ " LETTERs are as follows for new group, lower case for old group:\n",
+ " F first line number\n",
+ " L last line number\n",
+ " N number of lines = L-F+1\n",
+ " E F-1\n",
+ " M L+1\n",
+ " LFMT may contain:\n",
+ " %%L contents of line\n",
+ " %%l contents of line, excluding any trailing newline\n",
+ " %%[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number\n",
+ " Either GFMT or LFMT may contain:\n",
+ " %%%% %%\n",
+ " %%c'C' the single character C\n",
+ " %%c'\\OOO' the character with octal code OOO\n\n",
+ " -t --expand-tabs Expand tabs to spaces in output.\n",
+ " -T --initial-tab Make tabs line up by prepending a tab.\n\n",
+ " -N --new-file Treat absent files as empty.\n",
+ " -s --report-identical-files Report when two files are the same.\n",
+ " --horizon-lines=NUM Keep NUM lines of the common prefix and suffix.\n",
+ " -d --minimal Try hard to find a smaller set of changes.\n",
+ " -H --speed-large-files Assume large files and many scattered small changes.\n",
+ "\n(Specify the --help global option for a list of other help options)\n",
NULL
};
@@ -89,19 +136,20 @@ static const char *const diff_usage[] =
removing the following entries, none of which seem relevant to use
with CVS:
--help
- --version
- --recursive
- --unidirectional-new-file
- --starting-file
- --exclude
- --exclude-from
+ --version (-v)
+ --recursive (-r)
+ --unidirectional-new-file (-P)
+ --starting-file (-S)
+ --exclude (-x)
+ --exclude-from (-X)
--sdiff-merge-assist
+ --paginate (-l) (doesn't work with library callbacks)
I changed the options which take optional arguments (--context and
--unified) to return a number rather than a letter, so that the
optional argument could be handled more easily. I changed the
- --paginate and --brief options to return a number, since -l and -q
- mean something else to cvs diff.
+ --brief and --ifdef options to return numbers, since -q and -D mean
+ something else to cvs diff.
The numbers 129- that appear in the fourth element of some entries
tell the big switch in `diff' how to process those options. -- Ian
@@ -128,7 +176,6 @@ static struct option const longopts[] =
{"ed", 0, 0, 'e'},
{"forward-ed", 0, 0, 'f'},
{"ignore-case", 0, 0, 'i'},
- {"paginate", 0, 0, 144},
{"rcs", 0, 0, 'n'},
{"show-c-function", 0, 0, 'p'},
@@ -229,19 +276,22 @@ diff (argc, argv)
optind = 0;
while ((c = getopt_long (argc, argv,
- "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:j:",
+ "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:j:",
longopts, &option_index)) != -1)
{
switch (c)
{
+ case 'y':
+ xrealloc_and_strcat (&opts, &opts_allocated, " --side-by-side");
+ break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'h': case 'i': case 'n': case 'p': case 's': case 't':
- case 'u': case 'w': case 'y':
+ case '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 'T':
(void) sprintf (tmp, " -%c", (char) c);
- allocate_and_strcat (&opts, &opts_allocated, tmp);
+ xrealloc_and_strcat (&opts, &opts_allocated, tmp);
break;
case 'L':
if (have_rev1_label++)
@@ -251,31 +301,31 @@ diff (argc, argv)
break;
}
- allocate_and_strcat (&opts, &opts_allocated, " -L");
- allocate_and_strcat (&opts, &opts_allocated, optarg);
+ xrealloc_and_strcat (&opts, &opts_allocated, " -L");
+ xrealloc_and_strcat (&opts, &opts_allocated, optarg);
break;
- case 'C': case 'F': case 'I': case 'U': case 'V': case 'W':
+ case 'C': case 'F': case 'I': case 'U': case 'W':
(void) sprintf (tmp, " -%c", (char) c);
- allocate_and_strcat (&opts, &opts_allocated, tmp);
- allocate_and_strcat (&opts, &opts_allocated, optarg);
+ xrealloc_and_strcat (&opts, &opts_allocated, tmp);
+ xrealloc_and_strcat (&opts, &opts_allocated, optarg);
break;
case 131:
/* --ifdef. */
- allocate_and_strcat (&opts, &opts_allocated, " --ifdef=");
- allocate_and_strcat (&opts, &opts_allocated, optarg);
+ xrealloc_and_strcat (&opts, &opts_allocated, " --ifdef=");
+ xrealloc_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:
- allocate_and_strcat (&opts, &opts_allocated, " --");
- allocate_and_strcat (&opts, &opts_allocated,
+ case 141: case 142: case 143: case 145: case 146:
+ xrealloc_and_strcat (&opts, &opts_allocated, " --");
+ xrealloc_and_strcat (&opts, &opts_allocated,
longopts[option_index].name);
if (longopts[option_index].has_arg == 1
|| (longopts[option_index].has_arg == 2
&& optarg != NULL))
{
- allocate_and_strcat (&opts, &opts_allocated, "=");
- allocate_and_strcat (&opts, &opts_allocated, optarg);
+ xrealloc_and_strcat (&opts, &opts_allocated, "=");
+ xrealloc_and_strcat (&opts, &opts_allocated, optarg);
}
break;
case 'R':
@@ -470,8 +520,7 @@ diff_fileproc (callerdat, finfo)
(vers->vn_rcs == NULL
? NULL
: RCS_branch_head (vers->srcfile, vers->vn_rcs));
- exists = (head != NULL
- && !RCS_isdead (vers->srcfile, head));
+ exists = head != NULL && !RCS_isdead(vers->srcfile, head);
if (head != NULL)
free (head);
}
@@ -481,8 +530,7 @@ diff_fileproc (callerdat, finfo)
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
1, 0);
- exists = (xvers->vn_rcs != NULL
- && !RCS_isdead (xvers->srcfile, xvers->vn_rcs));
+ exists = xvers->vn_rcs != NULL && !RCS_isdead(xvers->srcfile, xvers->vn_rcs);
freevers_ts (&xvers);
}
if (exists)
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
index 0282005..4b163e3 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -335,8 +335,7 @@ mkdir_if_needed (name)
{
if (mkdir (name, 0777) < 0)
{
- if (!(errno == EEXIST
- || (errno == EACCES && isdir (name))))
+ if (errno != EEXIST && !isdir (name))
error (1, errno, "cannot make directory %s", name);
return 1;
}
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 9065cdd..09ed285 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -220,7 +220,11 @@ import (argc, argv)
if (use_editor)
{
- do_editor ((char *) NULL, &message, repository,
+ do_editor ((char *) NULL, &message,
+#ifdef CLIENT_SUPPORT
+ current_parsed_root->isremote ? (char *) NULL :
+#endif
+ repository,
(List *) NULL);
}
do_verify (&message, repository);
@@ -280,7 +284,7 @@ import (argc, argv)
}
#endif
- if (!safe_location ())
+ if (!safe_location ( NULL ))
{
error (1, 0, "attempt to import the repository");
}
@@ -313,7 +317,6 @@ import (argc, argv)
if (!really_quiet)
{
char buf[20];
- char *buf2;
cvs_output_tagged ("+importmergecmd", NULL);
cvs_output_tagged ("newline", NULL);
@@ -333,12 +336,9 @@ import (argc, argv)
cvs_output_tagged ("text", CVSroot_cmdline);
}
cvs_output_tagged ("text", " checkout -j");
- buf2 = xmalloc (strlen (argv[1]) + 20);
- sprintf (buf2, "%s:yesterday", argv[1]);
- cvs_output_tagged ("mergetag1", buf2);
- free (buf2);
+ cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
cvs_output_tagged ("text", " -j");
- cvs_output_tagged ("mergetag2", argv[1]);
+ cvs_output_tagged ("mergetag2", argv[2]);
cvs_output_tagged ("text", " ");
cvs_output_tagged ("repository", argv[0]);
cvs_output_tagged ("newline", NULL);
@@ -620,6 +620,7 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
Vers_TS *vers;
int letter;
char *tocvsPath;
+ char *expand;
struct file_info finfo;
memset (&finfo, 0, sizeof finfo);
@@ -649,7 +650,9 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
tocvsPath = wrap_tocvs_process_file (vfile);
/* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
not NULL? */
- different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, "-ko", vfile);
+ expand = vers->srcfile->expand != NULL &&
+ vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
+ different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, expand, vfile);
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
@@ -1153,7 +1156,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
goto write_error;
}
- if (local_opt != NULL)
+ if (local_opt != NULL && strcmp (local_opt, "kv") != 0)
{
if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0)
{
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 7fe92c9..c287201 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -293,6 +293,9 @@ Lock_Cleanup ()
/* FIXME-reentrancy: the workaround isn't reentrant. */
static int in_lock_cleanup = 0;
+ if (trace)
+ (void) fprintf (stderr, "%s-> Lock_Cleanup()\n", CLIENT_SERVER_STR);
+
if (in_lock_cleanup)
return;
in_lock_cleanup = 1;
@@ -398,6 +401,10 @@ Reader_Lock (xrepository)
FILE *fp;
char *tmp;
+ if (trace)
+ (void) fprintf (stderr, "%s-> Reader_Lock(%s)\n", CLIENT_SERVER_STR,
+ xrepository);
+
if (noexec || readonlyfs)
return (0);
@@ -561,6 +568,10 @@ write_lock (lock)
FILE *fp;
char *tmp;
+ if (trace)
+ (void) fprintf (stderr, "%s-> write_lock(%s)\n",
+ CLIENT_SERVER_STR, lock->repository);
+
if (writelock == NULL)
{
writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40);
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
index df6abe1..a90212f 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -324,8 +324,8 @@ password_entry_operation (operation, root, newpassword)
fp = CVS_FOPEN (passfile, "r");
if (fp == NULL)
{
- error (0, errno, "failed to open %s for reading", passfile);
- goto error_exit;
+ error (0, errno, "warning: failed to open %s for reading", passfile);
+ goto process;
}
cvsroot_canonical = normalize_cvsroot (root);
@@ -363,6 +363,8 @@ password_entry_operation (operation, root, newpassword)
password = xstrdup (password);
}
+process:
+
/* might as well return now */
if (operation == password_entry_lookup)
goto out;
@@ -552,6 +554,12 @@ login (argc, argv)
{
char *tmp;
tmp = GETPASS ("CVS password: ");
+ /* Must deal with a NULL return value here. I haven't managed to
+ * disconnect the CVS process from the tty and force a NULL return
+ * in sanity.sh, but the Linux version of getpass is documented
+ * to return NULL when it can't open /dev/tty...
+ */
+ if (!tmp) error (1, errno, "login: Failed to read password.");
typed_password = scramble (tmp);
memset (tmp, 0, strlen (tmp));
}
@@ -562,7 +570,7 @@ login (argc, argv)
* will get zeroed by connect_to_server(). */
cvs_password = xstrdup (typed_password);
- connect_to_pserver (NULL, NULL, 1, 0);
+ connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0);
password_entry_operation (password_entry_add, current_parsed_root, typed_password);
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index 917915c..d67410d 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -8,6 +8,8 @@
* $FreeBSD$
*/
+#include <assert.h>
+
#include "cvs.h"
#include "getline.h"
@@ -29,6 +31,15 @@ static char *editinfo_editor;
static char *verifymsg_script;
static Ctype type;
+/*
+ * Should the logmsg be re-read during the do_verify phase?
+ * RereadLogAfterVerify=no|stat|yes
+ * LOGMSG_REREAD_NEVER - never re-read the logmsg
+ * LOGMSG_REREAD_STAT - re-read the logmsg only if it has changed
+ * LOGMSG_REREAD_ALWAYS - always re-read the logmsg
+ */
+int RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
+
/*
* Puts a standard header on the output which is either being prepared for an
* editor session, or being sent to a logfile program. The modified, added,
@@ -168,7 +179,8 @@ fmt_proc (p, closure)
* stripped and the log message is stored in the "message" argument.
*
* If REPOSITORY is non-NULL, process rcsinfo for that repository; if it
- * is NULL, use the CVSADM_TEMPLATE file instead.
+ * is NULL, use the CVSADM_TEMPLATE file instead. REPOSITORY should be
+ * NULL when running in client mode.
*/
void
do_editor (dir, messagep, repository, changes)
@@ -185,6 +197,9 @@ do_editor (dir, messagep, repository, changes)
struct stat pre_stbuf, post_stbuf;
int retcode = 0;
+ assert (current_parsed_root->isremote && !repository
+ || !current_parsed_root->isremote && repository);
+
if (noexec || reuse_log_message)
return;
@@ -309,7 +324,7 @@ do_editor (dir, messagep, repository, changes)
/* On NT, we might read less than st_size bytes, but we won't
read more. So this works. */
*messagep = (char *) xmalloc (post_stbuf.st_size + 1);
- *messagep[0] = '\0';
+ (*messagep)[0] = '\0';
}
line = NULL;
@@ -342,8 +357,14 @@ do_editor (dir, messagep, repository, changes)
if (pre_stbuf.st_mtime == post_stbuf.st_mtime ||
*messagep == NULL ||
+ (*messagep)[0] == '\0' ||
strcmp (*messagep, "\n") == 0)
{
+ if (*messagep)
+ {
+ free (*messagep);
+ *messagep = NULL;
+ }
for (;;)
{
(void) printf ("\nLog message unchanged or not specified\n");
@@ -399,11 +420,7 @@ do_verify (messagep, repository)
char *fname;
int retcode = 0;
- char *line;
- int line_length;
- size_t line_chars_allocated;
- char *p;
- struct stat stbuf;
+ struct stat pre_stbuf, post_stbuf;
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
@@ -429,78 +446,104 @@ do_verify (messagep, repository)
if ((fp = cvs_temp_file (&fname)) == NULL)
error (1, errno, "cannot create temporary file %s", fname);
- else
+
+ fprintf (fp, "%s", *messagep);
+ if ((*messagep)[0] == '\0' ||
+ (*messagep)[strlen (*messagep) - 1] != '\n')
+ (void) fprintf (fp, "%s", "\n");
+ if (fclose (fp) == EOF)
+ error (1, errno, "%s", fname);
+
+ if (RereadLogAfterVerify == LOGMSG_REREAD_STAT)
{
- fprintf (fp, "%s", *messagep);
- if ((*messagep)[0] == '\0' ||
- (*messagep)[strlen (*messagep) - 1] != '\n')
- (void) fprintf (fp, "%s", "\n");
- if (fclose (fp) == EOF)
- error (1, errno, "%s", fname);
+ /* Remember the status of the temp file for later */
+ if ( CVS_STAT (fname, &pre_stbuf) != 0 )
+ error (1, errno, "cannot stat temp file %s", fname);
+
+ /*
+ * See if we need to sleep before running the verification
+ * script to avoid time-stamp races.
+ */
+ sleep_past (pre_stbuf.st_mtime);
+ }
- /* Get the name of the verification script to run */
+ /* Get the name of the verification script to run */
- if (repository != NULL)
- (void) Parse_Info (CVSROOTADM_VERIFYMSG, repository,
- verifymsg_proc, 0);
+ if (repository != NULL)
+ (void) Parse_Info (CVSROOTADM_VERIFYMSG, repository,
+ verifymsg_proc, 0);
- /* Run the verification script */
+ /* Run the verification script */
- if (verifymsg_script)
+ if (verifymsg_script)
+ {
+ run_setup (verifymsg_script);
+ run_arg (fname);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE)) != 0)
{
- run_setup (verifymsg_script);
- run_arg (fname);
- if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
- RUN_NORMAL | RUN_SIGIGNORE)) != 0)
- {
- /* Since following error() exits, delete the temp file
- now. */
- if (unlink_file (fname) < 0)
- error (0, errno, "cannot remove %s", fname);
+ /* Since following error() exits, delete the temp file now. */
+ if (unlink_file (fname) < 0)
+ error (0, errno, "cannot remove %s", fname);
- error (1, retcode == -1 ? errno : 0,
- "Message verification failed");
- }
+ error (1, retcode == -1 ? errno : 0,
+ "Message verification failed");
}
+ }
- /* put the entire message back into the *messagep variable */
+ /* Get the mod time and size of the possibly new log message
+ * in always and stat modes.
+ */
+ if (RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS ||
+ RereadLogAfterVerify == LOGMSG_REREAD_STAT)
+ {
+ if ( CVS_STAT (fname, &post_stbuf) != 0 )
+ error (1, errno, "cannot find size of temp file %s", fname);
+ }
- fp = open_file (fname, "r");
- if (fp == NULL)
- {
+ /* And reread the log message in `always' mode or in `stat' mode when it's
+ * changed
+ */
+ if (RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS ||
+ (RereadLogAfterVerify == LOGMSG_REREAD_STAT &&
+ (pre_stbuf.st_mtime != post_stbuf.st_mtime ||
+ pre_stbuf.st_size != post_stbuf.st_size)))
+ {
+ /* put the entire message back into the *messagep variable */
+ if ( (fp = open_file (fname, "r")) == NULL )
error (1, errno, "cannot open temporary file %s", fname);
- return;
- }
-
- if (*messagep)
- free (*messagep);
- if ( CVS_STAT (fname, &stbuf) != 0)
- error (1, errno, "cannot find size of temp file %s", fname);
+ if (*messagep) free (*messagep);
- if (stbuf.st_size == 0)
+ if (post_stbuf.st_size == 0)
*messagep = NULL;
else
{
- /* On NT, we might read less than st_size bytes, but we won't
- read more. So this works. */
- *messagep = (char *) xmalloc (stbuf.st_size + 1);
+ /* On NT, we might read less than st_size bytes,
+ but we won't read more. So this works. */
+ *messagep = (char *) xmalloc (post_stbuf.st_size + 1);
*messagep[0] = '\0';
}
- line = NULL;
- line_chars_allocated = 0;
-
if (*messagep)
{
- p = *messagep;
+ char *line = NULL;
+ int line_length;
+ size_t line_chars_allocated = 0;
+ char *p = *messagep;
+
while (1)
{
- line_length = getline (&line, &line_chars_allocated, fp);
+ line_length = getline (&line,
+ &line_chars_allocated,
+ fp);
if (line_length == -1)
{
if (ferror (fp))
- error (0, errno, "warning: cannot read %s", fname);
+ /* Fail in this case because otherwise we will have no
+ * log message
+ */
+ error (1, errno, "cannot read %s", fname);
break;
}
if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
@@ -508,16 +551,17 @@ do_verify (messagep, repository)
(void) strcpy (p, line);
p += line_length;
}
+ if (line) free (line);
}
if (fclose (fp) < 0)
error (0, errno, "warning: cannot close %s", fname);
+ }
- /* Delete the temp file */
+ /* Delete the temp file */
- if (unlink_file (fname) < 0)
- error (0, errno, "cannot remove %s", fname);
- free (fname);
- }
+ if (unlink_file (fname) < 0)
+ error (0, errno, "cannot remove %s", fname);
+ free (fname);
}
/*
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index 855d2ae..5c9596d 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -156,7 +156,7 @@ static const char *const usg[] =
putting metavariables in uppercase. I don't know whether that
is a good convention or not, but if it changes it would have to
change in all the usage messages. For now, they consistently
- use lowercase, as far as I know. Puncutation is pretty funky,
+ use lowercase, as far as I know. Punctuation is pretty funky,
though. Sometimes they use none, as here. Sometimes they use
single quotes (not the TeX-ish `' stuff), as in --help-options.
Sometimes they use double quotes, as in cvs -H add.
@@ -338,6 +338,8 @@ lookup_command_attribute (cmd_name)
if (strcmp (cmd_name, cm->fullname) == 0)
break;
}
+ if (!cm->fullname)
+ error (1, 0, "unknown command: %s", cmd_name);
return cm->attr;
}
@@ -868,7 +870,7 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\
error (0, 0,
"CVSROOT is set but empty! Make sure that the");
error (0, 0,
- "specification of CVSROOT is legal, either via the");
+ "specification of CVSROOT is valid, either via the");
error (0, 0,
"`-d' option, the %s environment variable, or the",
CVSROOT_ENV);
@@ -928,7 +930,7 @@ Copyright (c) 1989-2001 Brian Berliner, david d `zoo' zuhn, \n\
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.");
+ error (1, 0, "Bad CVSROOT: `%s'.", current_root);
if (trace)
fprintf (stderr, "%s-> main loop with CVSROOT=%s\n",
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index 3082f7d..699ff2a 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -209,10 +209,12 @@ static const char *const checkoutlist_contents[] = {
static const char *const cvswrappers_contents[] = {
"# This file affects handling of files based on their names.\n",
"#\n",
+#if 0 /* see comments in wrap_add in wrapper.c */
"# The -t/-f options allow one to treat directories of files\n",
"# as a single file, or to transform a file in other ways on\n",
"# its way in and out of CVS.\n",
"#\n",
+#endif
"# The -m option specifies whether CVS attempts to merge files.\n",
"#\n",
"# The -k option specifies keyword expansion (e.g. -kb for binary).\n",
@@ -245,7 +247,7 @@ static const char *const notify_contents[] = {
"# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n",
"#\n",
"# For example:\n",
- "#ALL mail %s -s \"CVS notification\"\n",
+ "#ALL mail -s \"CVS notification\" %s\n",
NULL
};
@@ -300,6 +302,14 @@ static const char *const config_contents[] = {
"# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n",
"# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
"#LogHistory=TOFEWGCMAR\n",
+ "\n",
+ "# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n",
+ "# script to change the log message. Set it to `stat' to force CVS to verify",
+ "# that the file has changed before reading it (this can take up to an extra\n",
+ "# second per directory being committed, so it is not recommended for large\n",
+ "# repositories. Set it to `never' (the previous CVS behavior) to prevent\n",
+ "# verifymsg scripts from changing the log message.\n",
+ "#RereadLogAfterVerify=always\n",
NULL
};
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index c7963b415..faa6ee7 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -15,6 +15,14 @@
#include "edit.h"
#include "hardlink.h"
+/* These need to be source after cvs.h or HAVE_MMAP won't be set... */
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+# ifndef HAVE_GETPAGESIZE
+# include "getpagesize.h"
+# endif
+#endif
+
int preserve_perms = 0;
/* The RCS -k options, and a set of enums that must match the array.
@@ -60,8 +68,10 @@ static void rcsbuf_close PROTO ((struct rcsbuffer *));
static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
char **valp));
static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
+#ifndef HAVE_MMAP
static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
char **valp));
+#endif
static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
size_t *lenp));
@@ -734,8 +744,8 @@ RCS_fully_parse (rcs)
vers = findnode (rcs->versions, key);
if (vers == NULL)
error (1, 0,
- "mismatch in rcs file %s between deltas and deltatexts",
- rcs->path);
+ "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->path, key);
vnode = (RCSVers *) vers->data;
@@ -793,12 +803,12 @@ unrecognized operation '\\x%x' in %s",
op, rcs->path);
(void) strtoul (cp, (char **) &cp, 10);
if (*cp++ != ' ')
- error (1, 0, "space expected in %s",
- rcs->path);
+ error (1, 0, "space expected in %s revision %s",
+ rcs->path, vnode->version);
count = strtoul (cp, (char **) &cp, 10);
if (*cp++ != '\012')
- error (1, 0, "linefeed expected in %s",
- rcs->path);
+ error (1, 0, "linefeed expected in %s revision %s",
+ rcs->path, vnode->version);
if (op == 'd')
del += count;
@@ -813,8 +823,8 @@ unrecognized operation '\\x%x' in %s",
{
if (count != 1)
error (1, 0, "\
-invalid rcs file %s: premature end of value",
- rcs->path);
+premature end of value in %s revision %s",
+ rcs->path, vnode->version);
else
break;
}
@@ -991,14 +1001,45 @@ rcsbuf_open (rcsbuf, fp, filename, pos)
error (1, 0, "rcsbuf_open: internal error");
rcsbuf_inuse = 1;
+#ifdef HAVE_MMAP
+ {
+ /* When we have mmap, it is much more efficient to let the system do the
+ * buffering and caching for us
+ */
+ struct stat fs;
+ size_t mmap_off = 0;
+
+ if ( fstat (fileno(fp), &fs) < 0 )
+ error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
+
+ if (pos)
+ {
+ size_t ps = getpagesize ();
+ mmap_off = ( pos / ps ) * ps;
+ }
+
+ /* Map private here since this particular buffer is read only */
+ rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fileno(fp), mmap_off );
+ if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
+ error ( 1, errno, "Could not map memory to RCS archive %s", filename );
+
+ rcsbuf_buffer_size = fs.st_size - mmap_off;
+ rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
+ rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
+ rcsbuf->pos = mmap_off;
+ }
+#else /* HAVE_MMAP */
if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
rcsbuf->ptr = rcsbuf_buffer;
rcsbuf->ptrend = rcsbuf_buffer;
+ rcsbuf->pos = pos;
+#endif /* HAVE_MMAP */
rcsbuf->fp = fp;
rcsbuf->filename = filename;
- rcsbuf->pos = pos;
rcsbuf->vlen = 0;
rcsbuf->at_string = 0;
rcsbuf->embedded_at = 0;
@@ -1012,6 +1053,9 @@ rcsbuf_close (rcsbuf)
{
if (! rcsbuf_inuse)
error (1, 0, "rcsbuf_close: internal error");
+#ifdef HAVE_MMAP
+ munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
+#endif
rcsbuf_inuse = 0;
}
@@ -1052,9 +1096,9 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
ptrend = rcsbuf->ptrend;
/* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
+ assert (ptr >= rcsbuf_buffer && ptr < rcsbuf_buffer + rcsbuf_buffer_size);
+#ifndef HAVE_MMAP
/* If the pointer is more than RCSBUF_BUFSIZE bytes into the
buffer, move back to the start of the buffer. This keeps the
buffer from growing indefinitely. */
@@ -1066,8 +1110,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
/* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
+ assert (len <= RCSBUF_BUFSIZE);
/* Update the POS field, which holds the file offset of the
first byte in the RCSBUF_BUFFER buffer. */
@@ -1078,18 +1121,23 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
ptrend = ptr + len;
rcsbuf->ptrend = ptrend;
}
+#endif /* ndef HAVE_MMAP */
/* Skip leading whitespace. */
while (1)
{
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
if (ptr == NULL)
+#endif
return 0;
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
c = *ptr;
if (! my_whitespace (c))
@@ -1108,13 +1156,17 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
{
++ptr;
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
if (ptr == NULL)
+#endif
error (1, 0, "EOF in key in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
c = *ptr;
if (c == ';' || my_whitespace (c))
break;
@@ -1143,13 +1195,17 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
if (ptr == NULL)
+#endif
error (1, 0, "EOF while looking for value in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
c = *ptr;
if (c == ';')
{
@@ -1184,6 +1240,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
+#ifndef HAVE_MMAP
{
/* Note that we pass PTREND as the PTR value to
rcsbuf_fill, so that we will wind up setting PTR to
@@ -1191,25 +1248,31 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
that we don't search the same bytes again. */
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
+#endif
error (1, 0,
"EOF while looking for end of string in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
/* Handle the special case of an '@' right at the end of
the known bytes. */
if (pat + 1 >= ptrend)
+#ifndef HAVE_MMAP
{
/* Note that we pass PAT, not PTR, here. */
pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
if (pat == NULL)
{
+#endif
/* EOF here is OK; it just means that the last
character of the file was an '@' terminating a
value for a key type which does not require a
trailing ';'. */
pat = rcsbuf->ptrend - 1;
+#ifndef HAVE_MMAP
}
ptrend = rcsbuf->ptrend;
@@ -1217,6 +1280,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
/* Note that the value of PTR is bogus here. This is
OK, because we don't use it. */
}
+#endif
if (pat + 1 >= ptrend || pat[1] != '@')
break;
@@ -1266,13 +1330,17 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
char n;
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
if (ptr == NULL)
+#endif
error (1, 0, "EOF in value in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
n = *ptr;
if (n == ';')
{
@@ -1307,6 +1375,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
/* Find the ';' which must end the value. */
start = ptr;
while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
+#ifndef HAVE_MMAP
{
int slen;
@@ -1317,10 +1386,13 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
slen = start - *valp;
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
+#endif
error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
+#ifndef HAVE_MMAP
start = *valp + slen;
ptrend = rcsbuf->ptrend;
}
+#endif
/* See if there are any '@' strings in the value. */
pat = memchr (start, '@', psemi - start);
@@ -1364,6 +1436,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
+#ifndef HAVE_MMAP
{
/* Note that we pass PTREND as the PTR value to
rcsbuff_fill, so that we will wind up setting PTR
@@ -1371,22 +1444,29 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
that we don't search the same bytes again. */
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
+#endif
error (1, 0,
"EOF while looking for end of string in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
/* Handle the special case of an '@' right at the end of
the known bytes. */
if (pat + 1 >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
if (ptr == NULL)
+#endif
error (1, 0, "EOF in value in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
if (pat[1] != '@')
break;
@@ -1429,12 +1509,16 @@ rcsbuf_getrevnum (rcsbuf, revp)
while (1)
{
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
if (ptr == NULL)
+#endif
return 0;
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
c = *ptr;
if (! whitespace (c))
@@ -1455,14 +1539,18 @@ unexpected '\\x%x' reading revision number in RCS file %s",
{
++ptr;
if (ptr >= ptrend)
+#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
if (ptr == NULL)
+#endif
error (1, 0,
"unexpected EOF reading revision number in RCS file %s",
rcsbuf->filename);
+#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
+#endif
c = *ptr;
}
@@ -1480,6 +1568,7 @@ unexpected '\\x%x' reading revision number in RCS file %s",
return 1;
}
+#ifndef HAVE_MMAP
/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
then *KEYP points into the buffer, and must be adjusted if the
@@ -1531,6 +1620,7 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
return ptr;
}
+#endif /* HAVE_MMAP */
/* Test whether the last value returned by rcsbuf_getkey is a composite
value or not. */
@@ -1687,7 +1777,19 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
{
++from;
- /* Sanity check. */
+ /* Sanity check.
+ *
+ * FIXME: I restored this to an abort from an assert based on
+ * advice from Larry Jones that asserts should not be used to
+ * confirm the validity of an RCS file... This leaves two
+ * issues here: 1) I am uncertain that the fact that we will
+ * only find double '@'s hasn't already been confirmed; and:
+ * 2) If this is the proper place to spot the error in the RCS
+ * file, then we should print a much clearer error here for the
+ * user!!!!!!!
+ *
+ * - DRP
+ */
if (*from != '@' || clen == 0)
abort ();
@@ -1711,11 +1813,8 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
}
/* Sanity check. */
- if (from != orig_from + len
- || to != orig_to + (len - rcsbuf->embedded_at))
- {
- abort ();
- }
+ assert (from == orig_from + len
+ && to == orig_to + (len - rcsbuf->embedded_at));
*to = '\0';
}
@@ -1736,7 +1835,7 @@ rcsbuf_valword (rcsbuf, valp)
register char *ptr, *pat;
char c;
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
+# define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
if (*valp == NULL)
return NULL;
@@ -1794,7 +1893,7 @@ rcsbuf_valword (rcsbuf, valp)
or an id. Make sure it is not another special character. */
if (c == '$' || c == '.' || c == ',')
{
- error (1, 0, "illegal special character in RCS field in %s",
+ error (1, 0, "invalid special character in RCS field in %s",
rcsbuf->filename);
}
@@ -1814,7 +1913,7 @@ rcsbuf_valword (rcsbuf, valp)
the character in its memory cell. Check to make sure that it
is a legitimate word delimiter -- whitespace or end. */
if (c != '\0' && !my_whitespace (c))
- error (1, 0, "illegal special character in RCS field in %s",
+ error (1, 0, "invalid special character in RCS field in %s",
rcsbuf->filename);
*pat = '\0';
@@ -1822,7 +1921,7 @@ rcsbuf_valword (rcsbuf, valp)
*valp = pat;
return xstrdup (ptr);
-#undef my_whitespace
+# undef my_whitespace
}
#endif
@@ -1833,7 +1932,7 @@ static unsigned long
rcsbuf_ftell (rcsbuf)
struct rcsbuffer *rcsbuf;
{
- return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
+ return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
}
/* Return a pointer to any data buffered for RCSBUF, along with the
@@ -1880,9 +1979,9 @@ rcsbuf_cache_close ()
{
if (cached_rcs != NULL)
{
+ rcsbuf_close (&cached_rcsbuf);
if (fclose (cached_rcsbuf.fp) != 0)
error (0, errno, "cannot close %s", cached_rcsbuf.filename);
- rcsbuf_close (&cached_rcsbuf);
freercsnode (&cached_rcs);
cached_rcs = NULL;
}
@@ -1899,6 +1998,7 @@ rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
FILE **pfp;
struct rcsbuffer *prcsbuf;
{
+#ifndef HAVE_MMAP
if (cached_rcs == rcs)
{
if (rcsbuf_ftell (&cached_rcsbuf) != pos)
@@ -1929,19 +2029,32 @@ rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
}
else
{
+#endif /* ifndef HAVE_MMAP */
+ /* FIXME: If these routines can be rewritten to not write to the
+ * rcs file buffer, there would be a considerably larger memory savings
+ * from using mmap since the shared file would never need be copied to
+ * process memory.
+ *
+ * If this happens, cached mmapped buffers would be usable, but don't
+ * forget to make sure rcs->pos < pos here...
+ */
if (cached_rcs != NULL)
rcsbuf_cache_close ();
*pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
if (*pfp == NULL)
error (1, 0, "unable to reopen `%s'", rcs->path);
+#ifndef HAVE_MMAP
if (pos != 0)
{
if (fseek (*pfp, pos, SEEK_SET) != 0)
error (1, 0, "cannot fseek RCS file %s", rcs->path);
}
+#endif /* ifndef HAVE_MMAP */
rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
+#ifndef HAVE_MMAP
}
+#endif /* ifndef HAVE_MMAP */
}
@@ -2239,7 +2352,7 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
/* If tag is "HEAD", special case to get head RCS revision */
- if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
+ if (tag && STREQ (tag, TAG_HEAD))
#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
return ((char *) NULL); /* head request for removed file */
@@ -2848,16 +2961,21 @@ RCS_getdate (rcs, date, force_tag_match)
/* if the head is on a branch, try the branch first */
if (rcs->branch != NULL)
+ {
retval = RCS_getdatebranch (rcs, date, rcs->branch);
-
- /* if we found a match, we are done */
- if (retval != NULL)
- return (retval);
+ if (retval != NULL)
+ return (retval);
+ }
/* otherwise if we have a trunk, try it */
if (rcs->head)
{
p = findnode (rcs->versions, rcs->head);
+ if (p == NULL)
+ {
+ error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
+ rcs->head);
+ }
while (p != NULL)
{
/* if the date of this one is before date, take it */
@@ -2875,10 +2993,13 @@ RCS_getdate (rcs, date, force_tag_match)
p = (Node *) NULL;
}
}
+ else
+ error (0, 0, "%s: no head revision", rcs->path);
/*
* at this point, either we have the revision we want, or we have the
- * first revision on the trunk (1.1?) in our hands
+ * first revision on the trunk (1.1?) in our hands, or we've come up
+ * completely empty
*/
/* if we found what we're looking for, and it's not 1.1 return it */
@@ -2913,7 +3034,8 @@ RCS_getdate (rcs, date, force_tag_match)
if (retval != NULL)
return (retval);
- if (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)
+ if (!force_tag_match ||
+ (vers != NULL && RCS_datecmp (vers->date, date) <= 0))
return (xstrdup (vers->version));
else
return (NULL);
@@ -3186,6 +3308,8 @@ translate_symtag (rcs, tag)
while (! whitespace (*cp) && *cp != '\0')
++cp;
+ if (*cp == '\0')
+ break;
}
}
@@ -4267,7 +4391,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
/* If the size of `devtype' changes, fix the sscanf call also */
char devtype[16];
- if (sscanf (info->data, "%16s %lu",
+ if (sscanf (info->data, "%15s %lu",
devtype, &devnum_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
workfile, vers->version, info->data);
@@ -4332,7 +4456,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
#ifdef PRESERVE_PERMISSIONS_SUPPORT
else if (special_file)
{
-#ifdef HAVE_MKNOD
+# ifdef HAVE_MKNOD
char *dest;
/* Can send either to WORKFILE or to SOUT, as long as SOUT is
@@ -4353,11 +4477,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (mknod (dest, special_file, devnum) < 0)
error (1, errno, "could not create special file %s",
dest);
-#else
+# else
error (1, 0,
"cannot create %s: unable to create special files on this system",
workfile);
-#endif
+# endif
}
#endif
else
@@ -4960,7 +5084,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
case S_IFREG: break;
case S_IFCHR:
case S_IFBLK:
-#ifdef HAVE_ST_RDEV
+# ifdef HAVE_ST_RDEV
np = getnode();
np->type = RCSFIELD;
np->key = xstrdup ("special");
@@ -4970,11 +5094,11 @@ RCS_checkin (rcs, workfile, message, rev, flags)
(unsigned long) sb.st_rdev);
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
-#else
+# else
error (0, 0,
"can't preserve %s: unable to save device files on this system",
workfile);
-#endif
+# endif
break;
default:
@@ -5825,7 +5949,9 @@ RCS_unlock (rcs, rev, unlock_quiet)
if (rcs->flags & PARTIAL)
RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
- /* If rev is NULL, unlock the latest revision (first in
+ /* If rev is NULL, unlock the revision held by the caller; if more
+ than one, make the user specify the revision explicitly. This
+ differs from RCS which unlocks the latest revision (first in
rcs->locks) held by the caller. */
if (rev == NULL)
{
@@ -5850,17 +5976,24 @@ RCS_unlock (rcs, rev, unlock_quiet)
lock = NULL;
for (p = locks->list->next; p != locks->list; p = p->next)
{
- if (lock != NULL)
+ if (STREQ (p->data, user))
{
- if (!unlock_quiet)
- error (0, 0, "\
+ if (lock != NULL)
+ {
+ if (!unlock_quiet)
+ error (0, 0, "\
%s: multiple revisions locked by %s; please specify one", rcs->path, user);
- return 1;
+ return 1;
+ }
+ lock = p;
}
- lock = p;
}
if (lock == NULL)
+ {
+ if (!unlock_quiet)
+ error (0, 0, "No locks are set for %s.\n", user);
return 0; /* no lock found, ergo nothing to do */
+ }
xrev = xstrdup (lock->key);
}
else
@@ -5888,6 +6021,9 @@ RCS_unlock (rcs, rev, unlock_quiet)
is called with a NULL revision, since that means "whatever
revision is currently locked by the caller." */
char *repos, *workfile;
+ if (!unlock_quiet)
+ error (0, 0, "\
+%s: revision %s locked by %s; breaking lock", rcs->path, xrev, lock->data);
repos = xstrdup (rcs->path);
workfile = strrchr (repos, '/');
*workfile++ = '\0';
@@ -7109,8 +7245,8 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
node = findnode (rcs->versions, key);
if (node == NULL)
error (1, 0,
- "mismatch in rcs file %s between deltas and deltatexts",
- rcs->path);
+ "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->path, key);
/* Stash the previous version. */
prev_vers = vers;
@@ -7602,8 +7738,8 @@ RCS_getdeltatext (rcs, fp, rcsbuf)
p = findnode (rcs->versions, num);
if (p == NULL)
- error (1, 0, "mismatch in rcs file %s between deltas and deltatexts",
- rcs->path);
+ error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->path, num);
d = (Deltatext *) xmalloc (sizeof (Deltatext));
d->version = xstrdup (num);
@@ -7963,8 +8099,10 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
char *bufrest;
int nls;
size_t buflen;
+#ifndef HAVE_MMAP
char buf[8192];
int got;
+#endif
/* Count the number of versions for which we have to do some
special operation. */
@@ -8073,7 +8211,12 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
fwrite (bufrest, 1, buflen, fout);
}
-
+#ifndef HAVE_MMAP
+ /* This bit isn't necessary when using mmap since the entire file
+ * will already be available via the RCS buffer. Besides, the
+ * mmap code doesn't always keep the file pointer up to date, so
+ * this adds some data twice.
+ */
while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
{
if (nls > 0
@@ -8090,6 +8233,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
nls = 0;
}
+#endif /* HAVE_MMAP */
}
/* A helper procedure for RCS_copydeltas. This is called via walklist
@@ -8351,7 +8495,8 @@ RCS_rewrite (rcs, newdtext, insertpt)
/* Update delta_pos to the current position in the output file.
Do NOT move these statements: they must be done after fin has
been positioned at the old delta_pos, but before any delta
- texts have been written to fout. */
+ texts have been written to fout.
+ */
rcs->delta_pos = ftell (fout);
if (rcs->delta_pos == -1)
error (1, errno, "cannot ftell in RCS file %s", rcs->path);
@@ -8368,7 +8513,7 @@ RCS_rewrite (rcs, newdtext, insertpt)
fragile even if it happens to sometimes be true. The real
solution is to make sure that all the code which reads
from fin checks for errors itself (some does, some doesn't). */
- error (0, 0, "warning: when closing RCS file `%s'", rcs->path);
+ error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
if (fclose (fin) < 0)
error (0, errno, "warning: closing RCS file `%s'", rcs->path);
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index 0af0d56..e07869c 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -248,7 +248,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
directories. */
if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i]))
+ {
+ strip_trailing_slashes (argv[i]);
addlist (&dirlist, argv[i]);
+ }
else
{
/* otherwise, split argument into directory and component names. */
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index 525d1ce..00852e9 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -63,7 +63,10 @@ int cvs_gssapi_encrypt;
#endif
#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
+# include <syslog.h>
+# ifndef LOG_DAEMON /* for ancient syslogs */
+# define LOG_DAEMON 0
+# endif
#endif
#ifdef HAVE_KERBEROS
@@ -163,7 +166,7 @@ static int fd_buffer_input PROTO((void *, char *, int, int, int *));
static int fd_buffer_output PROTO((void *, const char *, int, int *));
static int fd_buffer_flush PROTO((void *));
static int fd_buffer_block PROTO((void *, int));
-static int fd_buffer_shutdown PROTO((void *));
+static int fd_buffer_shutdown PROTO((struct buffer *));
/* Initialize a buffer built on a file descriptor. FD is the file
descriptor. INPUT is nonzero if this is for input, zero if this is
@@ -325,10 +328,10 @@ fd_buffer_block (closure, block)
/* The buffer shutdown function for a buffer built on a file descriptor. */
static int
-fd_buffer_shutdown (closure)
- void *closure;
+fd_buffer_shutdown (buf)
+ struct buffer *buf;
{
- free (closure);
+ free (buf->closure);
return 0;
}
@@ -364,7 +367,7 @@ create_adm_p (base_dir, dir)
if (tmp == NULL)
return ENOMEM;
-
+
/* We make several passes through this loop. On the first pass,
we simply create the CVSADM directory in the deepest directory.
For each subsequent pass, we try to remove the last path
@@ -427,8 +430,7 @@ create_adm_p (base_dir, dir)
}
(void) umask (omask);
}
-
-
+
f = CVS_FOPEN (tmp, "w");
if (f == NULL)
{
@@ -735,7 +737,7 @@ serve_root (arg)
{
char *env;
char *path;
-
+
if (error_pending()) return;
if (!isabsolute (arg))
@@ -773,12 +775,11 @@ serve_root (arg)
sprintf (pending_error_text, "\
E Protocol error: Root says \"%s\" but pserver says \"%s\"",
arg, Pserver_Repos);
+ return;
}
}
#endif
- 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
@@ -919,7 +920,7 @@ E protocol error: directory '%s' not within current directory",
}
return 0;
}
-
+
/*
* Add as many directories to the temp directory as the client tells us it
* will use "..", so we never try to access something outside the temp
@@ -1008,7 +1009,7 @@ dirswitch (dir, repos)
pending_error = ENOMEM;
return;
}
-
+
strcpy (dir_name, server_temp_dir);
strcat (dir_name, "/");
strcat (dir_name, dir);
@@ -2125,9 +2126,9 @@ serve_argument (arg)
char *arg;
{
char *p;
-
+
if (error_pending()) return;
-
+
if (argument_vector_size <= argument_count)
{
argument_vector_size *= 2;
@@ -2155,9 +2156,9 @@ serve_argumentx (arg)
char *arg;
{
char *p;
-
+
if (error_pending()) return;
-
+
p = argument_vector[argument_count - 1];
p = realloc (p, strlen (p) + 1 + strlen (arg) + 1);
if (p == NULL)
@@ -2479,7 +2480,7 @@ check_command_legal_p (cmd_name)
size_t flen;
FILE *fp;
int found_it = 0;
-
+
/* else */
flen = strlen (current_parsed_root->directory)
+ strlen (CVSROOTADM)
@@ -2571,7 +2572,7 @@ check_command_legal_p (cmd_name)
/* Chop newline by hand, for strcmp()'s sake. */
if (linebuf[num_red - 1] == '\n')
linebuf[num_red - 1] = '\0';
-
+
if (strcmp (linebuf, CVS_Username) == 0)
{
found_it = 1;
@@ -2638,7 +2639,7 @@ do_cvs_command (cmd_name, command)
* interleaved with data from stdout_pipe or stderr_pipe).
*/
int protocol_pipe[2];
-
+
int dev_null_fd = -1;
int errs;
@@ -3017,7 +3018,7 @@ error \n");
{
int status;
int count_read;
-
+
status = buf_input_data (protocol_inbuf, &count_read);
if (status == -1)
@@ -3175,7 +3176,7 @@ error \n");
*/
continue;
}
-
+
if (WIFEXITED (status))
errs += WEXITSTATUS (status);
else
@@ -3302,7 +3303,7 @@ server_pause_check()
FD_ZERO (&fds);
FD_SET (flowcontrol_pipe[0], &fds);
numtocheck = flowcontrol_pipe[0] + 1;
-
+
do {
numfds = select (numtocheck, &fds, (fd_set *)0,
(fd_set *)0, (struct timeval *)NULL);
@@ -3314,7 +3315,7 @@ server_pause_check()
return;
}
} while (numfds < 0);
-
+
if (FD_ISSET (flowcontrol_pipe[0], &fds))
{
int got;
@@ -3437,7 +3438,7 @@ server_register (name, version, timestamp, options, tag, date, conflict)
len += strlen (tag);
if (date)
len += strlen (date);
-
+
entries_line = xmalloc (len);
sprintf (entries_line, "/%s/%s/", name, version);
if (conflict != NULL)
@@ -3672,7 +3673,7 @@ static void
serve_tag (arg)
char *arg;
{
- do_cvs_command ("cvstag", cvstag);
+ do_cvs_command ("tag", cvstag);
}
static void
@@ -3797,20 +3798,38 @@ static void
serve_init (arg)
char *arg;
{
+ cvsroot_t *saved_parsed_root;
+
if (!isabsolute (arg))
{
if (alloc_pending (80 + strlen (arg)))
sprintf (pending_error_text,
- "E Root %s must be an absolute pathname", arg);
- /* Fall through to do_cvs_command which will return the
- actual error. */
+ "E init %s must be an absolute pathname", arg);
+ }
+#ifdef AUTH_SERVER_SUPPORT
+ else if (Pserver_Repos != NULL)
+ {
+ if (strcmp (Pserver_Repos, arg) != 0)
+ {
+ if (alloc_pending (80 + strlen (Pserver_Repos) + strlen (arg)))
+ /* The explicitness is to aid people who are writing clients.
+ I don't see how this information could help an
+ attacker. */
+ sprintf (pending_error_text, "\
+E Protocol error: init says \"%s\" but pserver says \"%s\"",
+ arg, Pserver_Repos);
+ }
}
+#endif
- if (current_parsed_root != NULL)
- free_cvsroot_t (current_parsed_root);
- current_parsed_root = local_cvsroot (arg);
+ if (print_pending_error ())
+ return;
+ saved_parsed_root = current_parsed_root;
+ current_parsed_root = local_cvsroot (arg);
do_cvs_command ("init", init);
+ free_cvsroot_t (current_parsed_root);
+ current_parsed_root = saved_parsed_root;
}
static void serve_annotate PROTO ((char *));
@@ -4574,7 +4593,6 @@ serve_expand_modules (arg)
DBM *db;
err = 0;
- server_expanding = 1;
db = open_module ();
for (i = 1; i < argument_count; i++)
err += do_module (db, argument_vector[i],
@@ -4582,7 +4600,6 @@ serve_expand_modules (arg)
NULL, 0, 0, 0, 0,
(char *) NULL);
close_module (db);
- server_expanding = 0;
{
/* argument_vector[0] is a dummy argument, we don't mess with it. */
char **cp;
@@ -4612,23 +4629,24 @@ server_prog (dir, name, which)
{
if (!supported_response ("Set-checkin-prog"))
{
- buf_output0 (buf_to_net, "E \
+ buf_output0 (protocol, "E \
warning: this client does not support -i or -u flags in the modules file.\n");
return;
}
switch (which)
{
case PROG_CHECKIN:
- buf_output0 (buf_to_net, "Set-checkin-prog ");
+ buf_output0 (protocol, "Set-checkin-prog ");
break;
case PROG_UPDATE:
- buf_output0 (buf_to_net, "Set-update-prog ");
+ buf_output0 (protocol, "Set-update-prog ");
break;
}
- buf_output0 (buf_to_net, dir);
- buf_append_char (buf_to_net, '\n');
- buf_output0 (buf_to_net, name);
- buf_append_char (buf_to_net, '\n');
+ buf_output0 (protocol, dir);
+ buf_append_char (protocol, '\n');
+ buf_output0 (protocol, name);
+ buf_append_char (protocol, '\n');
+ buf_send_counted (protocol);
}
static void
@@ -4862,32 +4880,33 @@ server_cleanup (sig)
if (buf_to_net != NULL)
{
- /* FIXME: If this is not the final call from server, this
- could deadlock, because the client might be blocked writing
- to us. This should not be a problem in practice, because
- we do not generate much output when the client is not
- waiting for it. */
+ /* Since we're done, go ahead and put BUF_TO_NET back into blocking
+ * mode and send any pending output. In the usual case there won't
+ * won't be any, but there might be if an error occured.
+ */
+
set_block (buf_to_net);
buf_flush (buf_to_net, 1);
- /* The calls to buf_shutdown are currently only meaningful
- when we are using compression. First we shut down
- BUF_FROM_NET. That will pick up the checksum generated
- when the client shuts down its buffer. Then, after we have
- generated any final output, we shut down BUF_TO_NET. */
+ /* Next we shut down BUF_FROM_NET. That will pick up the checksum
+ * generated when the client shuts down its buffer. Then, after we
+ * have generated any final output, we shut down BUF_TO_NET.
+ */
status = buf_shutdown (buf_from_net);
if (status != 0)
{
error (0, status, "shutting down buffer from client");
- buf_flush (buf_to_net, 1);
}
}
if (dont_delete_temp)
{
if (buf_to_net != NULL)
+ {
+ (void) buf_flush (buf_to_net, 1);
(void) buf_shutdown (buf_to_net);
+ }
return;
}
@@ -4985,11 +5004,13 @@ server_cleanup (sig)
noexec = save_noexec;
if (buf_to_net != NULL)
+ {
+ (void) buf_flush (buf_to_net, 1);
(void) buf_shutdown (buf_to_net);
+ }
}
int server_active = 0;
-int server_expanding = 0;
int
server (argc, argv)
@@ -5010,7 +5031,7 @@ server (argc, argv)
buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0,
outbuf_memory_error);
- buf_from_net = stdio_buffer_initialize (stdin, 1, outbuf_memory_error);
+ buf_from_net = stdio_buffer_initialize (stdin, 0, 1, outbuf_memory_error);
saved_output = buf_nonio_initialize (outbuf_memory_error);
saved_outerr = buf_nonio_initialize (outbuf_memory_error);
@@ -5190,7 +5211,7 @@ error ENOMEM Virtual memory exhausted.\n");
char *cmd, *orig_cmd;
struct request *rq;
int status;
-
+
status = buf_read_line (buf_from_net, &cmd, (int *) NULL);
if (status == -2)
{
@@ -5327,7 +5348,7 @@ error 0 %s: no such user\n", username);
error_exit ();
}
}
-
+
if (setuid (pw->pw_uid) < 0)
{
/* Note that this means that if run as a non-root user,
@@ -5351,12 +5372,12 @@ error 0 %s: no such user\n", username);
if (CVS_Username == NULL)
CVS_Username = xstrdup (username);
#endif
-
+
#if HAVE_PUTENV
/* Set LOGNAME, USER and CVS_USER in the environment, in case they
are already set to something else. */
{
- char *env, *cvs_user;
+ char *env;
env = xmalloc (sizeof "LOGNAME=" + strlen (username));
(void) sprintf (env, "LOGNAME=%s", username);
@@ -5366,10 +5387,11 @@ error 0 %s: no such user\n", 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);
+#ifdef AUTH_SERVER_SUPPORT
+ env = xmalloc (sizeof "CVS_USER=" + strlen (CVS_Username));
+ (void) sprintf (env, "CVS_USER=%s", CVS_Username);
(void) putenv (env);
+#endif
}
#endif /* HAVE_PUTENV */
}
@@ -5380,7 +5402,7 @@ error 0 %s: no such user\n", username);
extern char *crypt PROTO((const char *, const char *));
-/*
+/*
* 0 means no entry found for this user.
* 1 means entry found and password matches (or found password is empty)
* 2 means entry found, but password does not match.
@@ -5449,7 +5471,7 @@ check_repository_password (username, password, repository, host_user_ptr)
char *found_password, *host_user_tmp;
char *non_cvsuser_portion;
- /* We need to make sure lines such as
+ /* We need to make sure lines such as
*
* "username::sysuser\n"
* "username:\n"
@@ -5582,7 +5604,7 @@ check_password (username, password, repository)
{
found_passwd = pw->pw_passwd;
}
-
+
if (found_passwd == NULL)
{
printf ("E Fatal error, aborting.\n\
@@ -5600,7 +5622,7 @@ error 0 %s: no such user\n", username);
exit (EXIT_FAILURE);
}
-
+
if (*found_passwd)
{
/* user exists and has a password */
@@ -5655,7 +5677,7 @@ error 0 %s: no such user\n", username);
handle_return:
if (host_user)
{
- /* Set CVS_Username here, in allocated space.
+ /* Set CVS_Username here, in allocated space.
It might or might not be the same as host_user. */
CVS_Username = xmalloc (strlen (username) + 1);
strcpy (CVS_Username, username);
@@ -5749,10 +5771,12 @@ pserver_authenticate_connection ()
/* Make sure the protocol starts off on the right foot... */
if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0)
- /* FIXME: what? We could try writing error/eof, but chances
- are the network connection is dead bidirectionally. log it
- somewhere? */
- ;
+ {
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE, "bad auth protocol start: EOF");
+#endif
+ error (1, 0, "bad auth protocol start: EOF");
+ }
if (strcmp (tmp, "BEGIN VERIFICATION REQUEST\n") == 0)
verify_and_exit = 1;
@@ -5783,7 +5807,7 @@ pserver_authenticate_connection ()
getline_safe (&username, &username_allocated, stdin, PATH_MAX);
getline_safe (&password, &password_allocated, stdin, PATH_MAX);
- /* Make them pure. */
+ /* Make them pure. */
strip_trailing_newlines (repository);
strip_trailing_newlines (username);
strip_trailing_newlines (password);
@@ -5817,8 +5841,6 @@ pserver_authenticate_connection ()
/* We need the real cleartext before we hash it. */
descrambled_password = descramble (password);
host_user = check_password (username, descrambled_password, repository);
- memset (descrambled_password, 0, strlen (descrambled_password));
- free (descrambled_password);
if (host_user == NULL)
{
#ifdef HAVE_SYSLOG_H
@@ -5828,6 +5850,8 @@ pserver_authenticate_connection ()
username, descrambled_password, repository);
#endif
#endif
+ memset (descrambled_password, 0, strlen (descrambled_password));
+ free (descrambled_password);
i_hate_you:
printf ("I HATE YOU\n");
fflush (stdout);
@@ -5836,6 +5860,8 @@ pserver_authenticate_connection ()
yet. */
error_exit ();
}
+ memset (descrambled_password, 0, strlen (descrambled_password));
+ free (descrambled_password);
/* Don't go any farther if we're just responding to "cvs login". */
if (verify_and_exit)
@@ -6521,7 +6547,7 @@ cvs_flusherr ()
{
/* make sure stderr is flushed before we send the flush count on the
* protocol pipe
- */
+ */
fflush (stderr);
/* Send a special count to tell the parent to flush. */
buf_send_special_count (protocol, -2);
@@ -6551,7 +6577,7 @@ cvs_flushout ()
main.c, didn't get called in the server child process. But
in the future it is quite plausible that we'll want to make
this case work analogously to cvs_flusherr.
-
+
FIXME - DRP - I tried to implement this and triggered the following
error: "Protocol error: uncounted data discarded". I don't need
this feature right now, so I'm not going to bother with it yet.
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index fa75977..12f02fa 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -38,7 +38,7 @@
#include "cvs.h"
#include "savecwd.h"
#ifdef SERVER_SUPPORT
-#include "md5.h"
+# include "md5.h"
#endif
#include "watch.h"
#include "fileattr.h"
@@ -1793,7 +1793,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
}
else
{
-#define BINARY "Binary"
+# define BINARY "Binary"
char buf[sizeof BINARY];
unsigned int c;
@@ -2689,7 +2689,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_symlink = xreadlink (finfo->file);
else
{
-#ifdef HAVE_ST_RDEV
+# ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2698,10 +2698,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_mode = sb.st_mode;
if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
rev1_dev = sb.st_rdev;
-#else
+# else
error (1, 0, "cannot handle device files on this system (%s)",
finfo->file);
-#endif
+# endif
}
rev1_hardlinks = list_linked_files_on_disk (finfo->file);
}
@@ -2740,7 +2740,7 @@ special_file_mismatch (finfo, rev1, rev2)
{
/* If the size of `ftype' changes, fix the sscanf call also */
char ftype[16];
- if (sscanf (n->data, "%16s %lu", ftype,
+ if (sscanf (n->data, "%15s %lu", ftype,
&dev_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
finfo->file, rev1, n->data);
@@ -2767,7 +2767,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_symlink = xreadlink (finfo->file);
else
{
-#ifdef HAVE_ST_RDEV
+# ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2776,10 +2776,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_mode = sb.st_mode;
if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
rev2_dev = sb.st_rdev;
-#else
+# else
error (1, 0, "cannot handle device files on this system (%s)",
finfo->file);
-#endif
+# endif
}
rev2_hardlinks = list_linked_files_on_disk (finfo->file);
}
@@ -2818,7 +2818,7 @@ special_file_mismatch (finfo, rev1, rev2)
{
/* If the size of `ftype' changes, fix the sscanf call also */
char ftype[16];
- if (sscanf (n->data, "%16s %lu", ftype,
+ if (sscanf (n->data, "%15s %lu", ftype,
&dev_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
finfo->file, rev2, n->data);
OpenPOWER on IntegriCloud