=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/cvs/logmsg.c,v retrieving revision 1.29 retrieving revision 1.30 diff -c -r1.29 -r1.30 *** src/usr.bin/cvs/logmsg.c 2006/05/27 03:30:31 1.29 --- src/usr.bin/cvs/logmsg.c 2007/01/07 02:39:24 1.30 *************** *** 1,298 **** ! /* $OpenBSD: logmsg.c,v 1.29 2006/05/27 03:30:31 joris dead $ */ /* ! * Copyright (c) 2004 Jean-Francois Brousseau ! * All rights reserved. * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: * ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. The name of the author may not be used to endorse or promote products ! * derived from this software without specific prior written permission. ! * ! * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ! * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ! * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ! * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ! * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ! * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ! * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ! * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ! * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" - #include "buf.h" #include "cvs.h" #include "log.h" ! #include "proto.h" ! ! #define CVS_LOGMSG_BIGMSG 32000 ! #define CVS_LOGMSG_PREFIX "CVS:" ! #define CVS_LOGMSG_LINE \ "----------------------------------------------------------------------" - - static const char *cvs_logmsg_ops[3] = { - "Added", "Modified", "Removed", - }; - - - /* - * cvs_logmsg_open() - * - * Open the file specified by and allocate a buffer large enough to - * hold all of the file's contents. Lines starting with the log prefix - * are not included in the result. - * The returned value must later be free()d. - * Returns a pointer to the allocated buffer on success, or NULL on failure. - */ char * ! cvs_logmsg_open(const char *path) { ! int lcont; size_t len; - char lbuf[256], *msg; struct stat st; ! FILE *fp; ! BUF *bp; ! if (stat(path, &st) == -1) ! fatal("cvs_logmsg_open: stat: `%s': %s", path, strerror(errno)); if (!S_ISREG(st.st_mode)) ! fatal("cvs_logmsg_open: message file must be a regular file"); ! if (st.st_size > CVS_LOGMSG_BIGMSG) { ! do { ! fprintf(stderr, ! "The specified message file seems big. " ! "Proceed anyways? (y/n) "); ! if (fgets(lbuf, (int)sizeof(lbuf), stdin) == NULL) ! fatal("cvs_logmsg_open: fgets failed"); ! len = strlen(lbuf); ! if (len == 0 || len > 2 || ! (lbuf[0] != 'y' && lbuf[0] != 'n')) { ! fprintf(stderr, "invalid input\n"); ! continue; ! } else if (lbuf[0] == 'y') ! break; ! else if (lbuf[0] == 'n') ! fatal("aborted by user"); ! } while (1); ! } ! ! if ((fp = fopen(path, "r")) == NULL) ! fatal("cvs_logmsg_open: fopen: `%s': %s", ! path, strerror(errno)); ! ! bp = cvs_buf_alloc((size_t)128, BUF_AUTOEXT); ! ! /* lcont is used to tell if a buffer returned by fgets is a start ! * of line or just line continuation because the buffer isn't ! * large enough to hold the entire line. ! */ ! lcont = 0; ! ! while (fgets(lbuf, (int)sizeof(lbuf), fp) != NULL) { ! len = strlen(lbuf); if (len == 0) continue; ! else if (lcont == 0 && ! strncmp(lbuf, CVS_LOGMSG_PREFIX, strlen(CVS_LOGMSG_PREFIX)) == 0) ! /* skip lines starting with the prefix */ continue; ! cvs_buf_append(bp, lbuf, strlen(lbuf)); ! ! lcont = (lbuf[len - 1] == '\n') ? 0 : 1; } - (void)fclose(fp); ! cvs_buf_putc(bp, '\0'); ! msg = (char *)cvs_buf_release(bp); ! return (msg); } - - /* - * cvs_logmsg_get() - * - * Get a log message by forking and executing the user's editor. The - * argument is a relative path to the directory for which the log message - * applies, and the 3 tail queue arguments contains all the files for which the - * log message will apply. Any of these arguments can be set to NULL in the - * case where there is no information to display. - * Returns the message in a dynamically allocated string on success, NULL on - * failure. - */ char * ! cvs_logmsg_get(const char *dir, struct cvs_flist *added, ! struct cvs_flist *modified, struct cvs_flist *removed) { - int i, fd, argc, fds[3], nl; - size_t len, tlen; - char *argv[4], buf[16], path[MAXPATHLEN], fpath[MAXPATHLEN], *msg; FILE *fp; ! CVSFILE *cvsfp; struct stat st1, st2; ! struct cvs_flist *files[3]; ! files[0] = added; ! files[1] = modified; ! files[2] = removed; ! msg = NULL; ! fds[0] = -1; ! fds[1] = -1; ! fds[2] = -1; ! strlcpy(path, cvs_tmpdir, sizeof(path)); ! strlcat(path, "/cvsXXXXXXXXXX", sizeof(path)); ! argc = 0; ! argv[argc++] = cvs_editor; ! argv[argc++] = path; ! argv[argc] = NULL; ! tlen = 0; ! if ((fd = mkstemp(path)) == -1) ! fatal("cvs_logmsg_get: mkstemp: `%s': %s", ! path, strerror(errno)); if ((fp = fdopen(fd, "w")) == NULL) { ! if (unlink(path) == -1) ! cvs_log(LP_ERRNO, "failed to unlink temporary file"); ! fatal("cvs_logmsg_get: fdopen failed"); } fprintf(fp, "\n%s %s\n%s Enter Log. Lines beginning with `%s' are " "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX); ! if (dir != NULL) ! fprintf(fp, "%s Commiting in %s\n%s\n", CVS_LOGMSG_PREFIX, dir, ! CVS_LOGMSG_PREFIX); ! for (i = 0; i < 3; i++) { ! if (files[i] == NULL) ! continue; ! if (SIMPLEQ_EMPTY(files[i])) ! continue; ! ! fprintf(fp, "%s %s Files:", CVS_LOGMSG_PREFIX, ! cvs_logmsg_ops[i]); ! nl = 1; ! SIMPLEQ_FOREACH(cvsfp, files[i], cf_list) { ! /* take the space into account */ ! cvs_file_getpath(cvsfp, fpath, sizeof(fpath)); ! len = strlen(fpath) + 1; ! if (tlen + len >= 72) ! nl = 1; ! ! if (nl) { ! fprintf(fp, "\n%s\t", CVS_LOGMSG_PREFIX); ! tlen = 8; ! nl = 0; ! } ! ! fprintf(fp, " %s", fpath); ! tlen += len; ! } ! fputc('\n', fp); ! } fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE); (void)fflush(fp); if (fstat(fd, &st1) == -1) { ! if (unlink(path) == -1) ! cvs_log(LP_ERRNO, "failed to unlink log file %s", path); ! fatal("cvs_logmsg_get: fstat failed"); } for (;;) { ! if (cvs_exec(argc, argv, fds) < 0) break; if (fstat(fd, &st2) == -1) { ! cvs_log(LP_ERRNO, "failed to stat log message file"); ! break; } ! if (st2.st_mtime != st1.st_mtime) { ! msg = cvs_logmsg_open(path); break; } ! /* nothing was entered */ ! fprintf(stderr, ! "\nLog message unchanged or not specified\na)bort, " ! "c)ontinue, e)dit, !)reuse this message unchanged " ! "for remaining dirs\nAction: (continue) "); ! if (fgets(buf, (int)sizeof(buf), stdin) == NULL) { ! cvs_log(LP_ERRNO, "failed to read from standard input"); break; ! } ! ! len = strlen(buf); ! if (len == 0 || len > 2) { ! fprintf(stderr, "invalid input\n"); continue; ! } else if (buf[0] == 'a') { ! cvs_log(LP_ABORT, "aborted by user"); ! break; ! } else if (buf[0] == '\n' || buf[0] == 'c') { ! /* empty message */ ! msg = xstrdup(""); ! break; ! } else if (buf[0] == 'e') continue; - else if (buf[0] == '!') { - /* XXX do something */ } } (void)fclose(fp); (void)close(fd); ! if (unlink(path) == -1) ! cvs_log(LP_ERRNO, "failed to unlink log file %s", path); ! ! return (msg); ! } ! ! ! /* ! * cvs_logmsg_send() ! * ! */ ! void ! cvs_logmsg_send(struct cvsroot *root, const char *msg) ! { ! const char *mp; ! char *np, buf[256]; ! ! cvs_sendarg(root, "-m", 0); ! ! for (mp = msg; mp != NULL; mp = strchr(mp, '\n')) { ! if (*mp == '\n') ! mp++; ! ! /* XXX ghetto */ ! strlcpy(buf, mp, sizeof(buf)); ! np = strchr(buf, '\n'); ! if (np != NULL) ! *np = '\0'; ! cvs_sendarg(root, buf, (mp == msg) ? 0 : 1); ! } } --- 1,193 ---- ! /* $OpenBSD: logmsg.c,v 1.30 2007/01/07 02:39:24 joris Exp $ */ /* ! * Copyright (c) 2007 Joris Vink * ! * Permission to use, copy, modify, and distribute this software for any ! * purpose with or without fee is hereby granted, provided that the above ! * copyright notice and this permission notice appear in all copies. * ! * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ! * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ! * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ! * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ! * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ! * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include "cvs.h" + #include "file.h" #include "log.h" ! #include "worklist.h" ! #define CVS_LOGMSG_PREFIX "CVS:" ! #define CVS_LOGMSG_LINE \ "----------------------------------------------------------------------" char * ! cvs_logmsg_read(const char *path) { ! int fd; ! BUF *bp; ! FILE *fp; size_t len; struct stat st; ! char *buf, *lbuf; ! if ((fd = open(path, O_RDONLY)) == -1) ! fatal("cvs_logmsg_read: open %s", strerror(errno)); + if (fstat(fd, &st) == -1) + fatal("cvs_logmsg_read: fstat %s", strerror(errno)); + if (!S_ISREG(st.st_mode)) ! fatal("cvs_logmsg_read: file is not a regular file"); ! if ((fp = fdopen(fd, "r")) == NULL) ! fatal("cvs_logmsg_read: fdopen %s", strerror(errno)); ! lbuf = NULL; ! bp = cvs_buf_alloc(st.st_size, BUF_AUTOEXT); ! while ((buf = fgetln(fp, &len))) { ! if (buf[len - 1] == '\n') { ! buf[len - 1] = '\0'; ! } else { ! lbuf = xmalloc(len + 1); ! strlcpy(lbuf, buf, len); ! buf = lbuf; ! } ! len = strlen(buf); if (len == 0) continue; ! ! if (!strncmp(buf, CVS_LOGMSG_PREFIX, ! strlen(CVS_LOGMSG_PREFIX))) continue; ! cvs_buf_append(bp, buf, len); ! cvs_buf_putc(bp, '\n'); } ! if (lbuf != NULL) ! xfree(lbuf); ! (void)fclose(fp); ! (void)close(fd); ! cvs_buf_putc(bp, '\0'); ! return (cvs_buf_release(bp)); } char * ! cvs_logmsg_create(struct cvs_flisthead *added, struct cvs_flisthead *removed, ! struct cvs_flisthead *modified) { FILE *fp; ! size_t len; ! int c, fd, argc; ! struct cvs_filelist *cf; struct stat st1, st2; ! char *fpath, *logmsg, *argv[4]; ! fpath = xmalloc(MAXPATHLEN); ! len = strlcpy(fpath, cvs_tmpdir, MAXPATHLEN); ! if (len >= MAXPATHLEN) ! fatal("cvs_logmsg_create: truncation"); ! len = strlcat(fpath, "/cvsXXXXXXXXXX", MAXPATHLEN); ! if (len >= MAXPATHLEN) ! fatal("cvs_logmsg_create: truncation"); ! if ((fd = mkstemp(fpath)) == NULL) ! fatal("cvs_logmsg_create: mkstemp %s", strerror(errno)); if ((fp = fdopen(fd, "w")) == NULL) { ! (void)unlink(fpath); ! fatal("cvs_logmsg_create: fdopen %s", strerror(errno)); } fprintf(fp, "\n%s %s\n%s Enter Log. Lines beginning with `%s' are " "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX); ! if (!TAILQ_EMPTY(added)) { ! fprintf(fp, "%s Added Files:", CVS_LOGMSG_PREFIX); ! TAILQ_FOREACH(cf, added, flist) ! fprintf(fp, "\n%s\t%s", ! CVS_LOGMSG_PREFIX, cf->file_path); ! fputs("\n", fp); ! } ! if (!TAILQ_EMPTY(removed)) { ! fprintf(fp, "%s Removed Files:", CVS_LOGMSG_PREFIX); ! TAILQ_FOREACH(cf, removed, flist) ! fprintf(fp, "\n%s\t%s", ! CVS_LOGMSG_PREFIX, cf->file_path); ! fputs("\n", fp); ! } ! if (!TAILQ_EMPTY(modified)) { ! fprintf(fp, "%s Modified Files:", CVS_LOGMSG_PREFIX); ! TAILQ_FOREACH(cf, modified, flist) ! fprintf(fp, "\n%s\t%s", ! CVS_LOGMSG_PREFIX, cf->file_path); ! fputs("\n", fp); } + fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE); (void)fflush(fp); if (fstat(fd, &st1) == -1) { ! (void)unlink(fpath); ! fatal("cvs_logmsg_create: fstat %s", strerror(errno)); } + argc = 0; + argv[argc++] = cvs_editor; + argv[argc++] = fpath; + argv[argc] = NULL; + + logmsg = NULL; + for (;;) { ! if (cvs_exec(argc, argv) < 0) break; if (fstat(fd, &st2) == -1) { ! (void)unlink(fpath); ! fatal("cvs_logmsg_create: fstat %s", strerror(errno)); } ! if (st1.st_mtime != st2.st_mtime) { ! logmsg = cvs_logmsg_read(fpath); break; } ! printf("\nLog message unchanged or not specified\n" ! "a)bort, c)ontinue, e(dit)\nAction: (continue) "); ! (void)fflush(stdout); ! c = getc(stdin); ! if (c == 'a') { ! fatal("Aborted by user"); ! } else if (c == '\n' || c == 'c') { ! logmsg = xstrdup(""); break; ! } else if (c == 'e') { continue; ! } else { ! cvs_log(LP_ERR, "invalid input"); continue; } } (void)fclose(fp); (void)close(fd); + (void)unlink(fpath); + xfree(fpath); ! return (logmsg); }