summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/server.c')
-rw-r--r--contrib/cvs/src/server.c172
1 files changed, 125 insertions, 47 deletions
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index e186c34..3262bba 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -20,6 +20,8 @@
#include "getline.h"
#include "buffer.h"
+int server_active = 0;
+
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
# ifdef HAVE_GSSAPI
/* This stuff isn't included solely with SERVER_SUPPORT since some of these
@@ -360,13 +362,20 @@ create_adm_p (base_dir, dir)
dir_where_cvsadm_lives = xmalloc (strlen (base_dir) + strlen (dir) + 100);
if (dir_where_cvsadm_lives == NULL)
+ {
+ free (p);
return ENOMEM;
+ }
/* Allocate some space for the temporary string in which we will
construct filenames. */
tmp = xmalloc (strlen (base_dir) + strlen (dir) + 100);
if (tmp == NULL)
+ {
+ free (p);
+ free (dir_where_cvsadm_lives);
return ENOMEM;
+ }
/* We make several passes through this loop. On the first pass,
@@ -1234,6 +1243,7 @@ serve_sticky (arg)
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
pending_error = save_errno;
+ (void) fclose (f);
return;
}
if (fclose (f) == EOF)
@@ -1682,7 +1692,9 @@ serve_unchanged (arg)
* is allowed, but broken versions of WinCVS & TortoiseCVS rely on
* this behavior.
*/
- *timefield = '=';
+ if (*timefield != '+')
+ /* Skip this for entries with conflict markers. */
+ *timefield = '=';
break;
}
}
@@ -1753,7 +1765,10 @@ serve_is_modified (arg)
* is allowed, but broken versions of WinCVS & TortoiseCVS rely on
* this behavior.
*/
- *timefield = 'M';
+ if (*timefield != '+')
+ /* Skip this for entries with conflict markers. */
+ *timefield = 'M';
+
if (kopt != NULL)
{
if (alloc_pending (strlen (name) + 80))
@@ -1840,6 +1855,7 @@ serve_entry (arg)
cp = xmalloc (strlen (arg) + 2);
if (cp == NULL)
{
+ free (p);
pending_error = ENOMEM;
return;
}
@@ -2703,6 +2719,25 @@ set_nonblock_fd (fd)
+/*
+ * Set buffer FD to blocking I/O. Returns 0 for success or errno code.
+ */
+int
+set_block_fd (fd)
+ int fd;
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
+ return errno;
+ return 0;
+}
+
+
+
static void
do_cvs_command (cmd_name, command)
char *cmd_name;
@@ -2926,22 +2961,31 @@ error \n");
{
char junk;
ssize_t status;
- while ((status = read (flowcontrol_pipe[0], &junk, 1)) > 0
- || (status == -1 && errno == EAGAIN));
+ set_block_fd (flowcontrol_pipe[0]);
+ while ((status = read (flowcontrol_pipe[0], &junk, 1)) > 0);
}
/* FIXME: No point in printing an error message with error(),
* as STDERR is already closed, but perhaps this could be syslogged?
*/
#endif
+ rcs_cleanup ();
+ Lock_Cleanup ();
+ /* Don't call server_cleanup - the parent will handle that. */
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
exit (exitstatus);
}
/* OK, sit around getting all the input from the child. */
{
- struct buffer *stdoutbuf;
- struct buffer *stderrbuf;
- struct buffer *protocol_inbuf;
+ struct buffer *stdoutbuf = NULL;
+ struct buffer *stderrbuf = NULL;
+ struct buffer *protocol_inbuf = NULL;
+ int err_exit = 0;
/* Number of file descriptors to check in select (). */
int num_to_check;
int count_needed = 1;
@@ -2994,7 +3038,8 @@ error \n");
{
buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
stdout_pipe[1] = -1;
@@ -3002,7 +3047,8 @@ error \n");
{
buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
stderr_pipe[1] = -1;
@@ -3010,7 +3056,8 @@ error \n");
{
buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
protocol_pipe[1] = -1;
@@ -3019,7 +3066,8 @@ error \n");
{
buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
flowcontrol_pipe[0] = -1;
#endif /* SERVER_FLOWCONTROL */
@@ -3028,7 +3076,9 @@ error \n");
{
buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
- goto error_exit;
+ dev_null_fd = -1; /* Do not try to close it again. */
+ err_exit = 1;
+ goto child_finish;
}
dev_null_fd = -1;
@@ -3115,7 +3165,8 @@ error \n");
{
buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
} while (numfds < 0);
@@ -3148,7 +3199,8 @@ error \n");
{
buf_output0 (buf_to_net, "E buf_input_data failed\n");
print_error (status);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
/*
@@ -3222,7 +3274,8 @@ error \n");
{
buf_output0 (buf_to_net, "E buf_input_data failed\n");
print_error (status);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
/* What should we do with errors? syslog() them? */
@@ -3247,7 +3300,8 @@ error \n");
{
buf_output0 (buf_to_net, "E buf_input_data failed\n");
print_error (status);
- goto error_exit;
+ err_exit = 1;
+ goto child_finish;
}
/* What should we do with errors? syslog() them? */
@@ -3327,21 +3381,33 @@ E CVS locks may need cleaning up.\n");
command_pid = -1;
}
+ child_finish:
/*
* OK, we've waited for the child. By now all CVS locks are free
* and it's OK to block on the network.
*/
set_block (buf_to_net);
buf_flush (buf_to_net, 1);
- buf_shutdown (protocol_inbuf);
- buf_free (protocol_inbuf);
- protocol_inbuf = NULL;
- buf_shutdown (stderrbuf);
- buf_free (stderrbuf);
- stderrbuf = NULL;
- buf_shutdown (stdoutbuf);
- buf_free (stdoutbuf);
- stdoutbuf = NULL;
+ if (protocol_inbuf)
+ {
+ buf_shutdown (protocol_inbuf);
+ buf_free (protocol_inbuf);
+ protocol_inbuf = NULL;
+ }
+ if (stderrbuf)
+ {
+ buf_shutdown (stderrbuf);
+ buf_free (stderrbuf);
+ stderrbuf = NULL;
+ }
+ if (stdoutbuf)
+ {
+ buf_shutdown (stdoutbuf);
+ buf_free (stdoutbuf);
+ stdoutbuf = NULL;
+ }
+ if (err_exit)
+ goto error_exit;
}
if (errs)
@@ -3365,7 +3431,8 @@ E CVS locks may need cleaning up.\n");
command_pid = -1;
}
- close (dev_null_fd);
+ if (dev_null_fd >= 0)
+ close (dev_null_fd);
close (protocol_pipe[0]);
close (protocol_pipe[1]);
close (stderr_pipe[0]);
@@ -3693,6 +3760,10 @@ server_checked_in (file, update_dir, repository)
const char *update_dir;
const char *repository;
{
+ assert (file);
+ assert (update_dir);
+ assert (repository);
+
if (noexec)
return;
if (scratched_file != NULL && entries_line == NULL)
@@ -4126,6 +4197,7 @@ server_updated (finfo, vers, updated, mode, checksum, filebuf)
free (scratched_file);
scratched_file = NULL;
}
+ buf_send_counted (protocol);
return;
}
@@ -4204,7 +4276,6 @@ CVS server internal error: no mode in server_updated");
if (updated == SERVER_UPDATED)
{
Node *node;
- Entnode *entnode;
if (!(supported_response ("Created")
&& supported_response ("Update-existing")))
@@ -4222,9 +4293,13 @@ CVS server internal error: no mode in server_updated");
in case we end up processing it again (e.g. modules3-6
in the testsuite). */
node = findnode_fn (finfo->entries, finfo->file);
- entnode = node->data;
- free (entnode->timestamp);
- entnode->timestamp = xstrdup ("=");
+ assert (node != NULL);
+ if (node != NULL)
+ {
+ Entnode *entnode = node->data;
+ free (entnode->timestamp);
+ entnode->timestamp = xstrdup ("=");
+ }
}
else if (updated == SERVER_MERGED)
buf_output0 (protocol, "Merged ");
@@ -4512,9 +4587,12 @@ struct template_proc_data
static struct template_proc_data *tpd;
static int
+template_proc PROTO((const char *repository, const char *template));
+
+static int
template_proc (repository, template)
- char *repository;
- char *template;
+ const char *repository;
+ const char *template;
{
FILE *fp;
char buf[1024];
@@ -4792,6 +4870,7 @@ struct request requests[] =
REQ_LINE("Checkin-time", serve_checkin_time, 0),
REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL),
REQ_LINE("Is-modified", serve_is_modified, 0),
+ REQ_LINE("Empty-conflicts", serve_noop, 0),
/* The client must send this request to interoperate with CVS 1.5
through 1.9 servers. The server must support it (although it can
@@ -5046,8 +5125,6 @@ server_cleanup (sig)
}
}
-int server_active = 0;
-
int
server (argc, argv)
int argc;
@@ -5479,6 +5556,7 @@ check_repository_password (username, password, repository, host_user_ptr)
{
if (!existence_error (errno))
error (0, errno, "cannot open %s", filename);
+ free (filename);
return 0;
}
@@ -5912,6 +5990,8 @@ pserver_authenticate_connection ()
printf ("I LOVE YOU\n");
fflush (stdout);
+ /* It's okay to skip rcs_cleanup() and Lock_Cleanup() here. */
+
#ifdef SYSTEM_CLEANUP
/* Hook for OS-specific behavior, for example socket subsystems on
NT and OS2 or dealing with windows and arguments on Mac. */
@@ -6425,12 +6505,10 @@ cvs_output (str, len)
size_t to_write = len;
const char *p = str;
- /* For symmetry with cvs_outerr we would call fflush (stderr)
- here. I guess the assumption is that stderr will be
- unbuffered, so we don't need to. That sounds like a sound
- assumption from the manpage I looked at, but if there was
- something fishy about it, my guess is that calling fflush
- would not produce a significant performance problem. */
+ /* Local users that do 'cvs status 2>&1' on a local repository
+ may see the informational messages out-of-order with the
+ status messages unless we use the fflush (stderr) here. */
+ fflush (stderr);
while (to_write > 0)
{
@@ -6487,16 +6565,16 @@ this client does not support writing binary files to stdout");
size_t written;
size_t to_write = len;
const char *p = str;
-
- /* For symmetry with cvs_outerr we would call fflush (stderr)
- here. I guess the assumption is that stderr will be
- unbuffered, so we don't need to. That sounds like a sound
- assumption from the manpage I looked at, but if there was
- something fishy about it, my guess is that calling fflush
- would not produce a significant performance problem. */
#ifdef USE_SETMODE_STDOUT
int oldmode;
+#endif
+ /* Local users that do 'cvs status 2>&1' on a local repository
+ may see the informational messages out-of-order with the
+ status messages unless we use the fflush (stderr) here. */
+ fflush (stderr);
+
+#ifdef USE_SETMODE_STDOUT
/* It is possible that this should be the same ifdef as
USE_SETMODE_BINARY but at least for the moment we keep them
separate. Mostly this is just laziness and/or a question
OpenPOWER on IntegriCloud