summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/logmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/logmsg.c')
-rw-r--r--contrib/cvs/src/logmsg.c160
1 files changed, 102 insertions, 58 deletions
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index 917915cf93bb..d67410d4e037 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);
}
/*