diff options
Diffstat (limited to 'contrib/cvs/src/logmsg.c')
-rw-r--r-- | contrib/cvs/src/logmsg.c | 160 |
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); } /* |