[BACK]Return to logmsg.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/logmsg.c, Revision 1.41

1.41    ! ray         1: /*     $OpenBSD: logmsg.c,v 1.40 2007/05/11 02:37:31 ray Exp $ */
1.1       jfb         2: /*
1.30      joris       3:  * Copyright (c) 2007 Joris Vink <joris@openbsd.org>
1.1       jfb         4:  *
1.30      joris       5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       jfb        16:  */
                     17:
1.38      otto       18: #include <sys/stat.h>
1.39      xsa        19: #include <sys/types.h>
                     20: #include <sys/wait.h>
1.38      otto       21:
                     22: #include <errno.h>
                     23: #include <fcntl.h>
1.39      xsa        24: #include <paths.h>
                     25: #include <signal.h>
1.38      otto       26: #include <string.h>
                     27: #include <unistd.h>
1.1       jfb        28:
                     29: #include "cvs.h"
                     30:
1.30      joris      31: #define CVS_LOGMSG_PREFIX              "CVS:"
                     32: #define CVS_LOGMSG_LINE                \
1.1       jfb        33: "----------------------------------------------------------------------"
                     34:
1.39      xsa        35: int    cvs_logmsg_edit(const char *);
                     36:
1.17      xsa        37: char *
1.30      joris      38: cvs_logmsg_read(const char *path)
1.1       jfb        39: {
1.30      joris      40:        int fd;
                     41:        BUF *bp;
                     42:        FILE *fp;
1.1       jfb        43:        size_t len;
                     44:        struct stat st;
1.30      joris      45:        char *buf, *lbuf;
                     46:
                     47:        if ((fd = open(path, O_RDONLY)) == -1)
                     48:                fatal("cvs_logmsg_read: open %s", strerror(errno));
1.1       jfb        49:
1.30      joris      50:        if (fstat(fd, &st) == -1)
                     51:                fatal("cvs_logmsg_read: fstat %s", strerror(errno));
1.1       jfb        52:
1.24      xsa        53:        if (!S_ISREG(st.st_mode))
1.30      joris      54:                fatal("cvs_logmsg_read: file is not a regular file");
1.1       jfb        55:
1.30      joris      56:        if ((fp = fdopen(fd, "r")) == NULL)
                     57:                fatal("cvs_logmsg_read: fdopen %s", strerror(errno));
1.1       jfb        58:
1.30      joris      59:        lbuf = NULL;
                     60:        bp = cvs_buf_alloc(st.st_size, BUF_AUTOEXT);
                     61:        while ((buf = fgetln(fp, &len))) {
                     62:                if (buf[len - 1] == '\n') {
                     63:                        buf[len - 1] = '\0';
                     64:                } else {
                     65:                        lbuf = xmalloc(len + 1);
1.36      otto       66:                        memcpy(lbuf, buf, len);
                     67:                        lbuf[len] = '\0';
1.30      joris      68:                        buf = lbuf;
                     69:                }
1.1       jfb        70:
1.30      joris      71:                len = strlen(buf);
1.1       jfb        72:                if (len == 0)
                     73:                        continue;
1.30      joris      74:
                     75:                if (!strncmp(buf, CVS_LOGMSG_PREFIX,
                     76:                    strlen(CVS_LOGMSG_PREFIX)))
1.1       jfb        77:                        continue;
                     78:
1.30      joris      79:                cvs_buf_append(bp, buf, len);
                     80:                cvs_buf_putc(bp, '\n');
                     81:        }
                     82:
                     83:        if (lbuf != NULL)
                     84:                xfree(lbuf);
1.1       jfb        85:
1.11      jfb        86:        (void)fclose(fp);
                     87:
1.23      xsa        88:        cvs_buf_putc(bp, '\0');
1.30      joris      89:        return (cvs_buf_release(bp));
1.1       jfb        90: }
                     91:
1.17      xsa        92: char *
1.30      joris      93: cvs_logmsg_create(struct cvs_flisthead *added, struct cvs_flisthead *removed,
                     94:        struct cvs_flisthead *modified)
1.1       jfb        95: {
                     96:        FILE *fp;
1.39      xsa        97:        int c, fd, saved_errno;
1.30      joris      98:        struct cvs_filelist *cf;
1.1       jfb        99:        struct stat st1, st2;
1.39      xsa       100:        char *fpath, *logmsg;
1.8       jfb       101:
1.35      xsa       102:        (void)xasprintf(&fpath, "%s/cvsXXXXXXXXXX", cvs_tmpdir);
1.1       jfb       103:
1.30      joris     104:        if ((fd = mkstemp(fpath)) == NULL)
                    105:                fatal("cvs_logmsg_create: mkstemp %s", strerror(errno));
1.33      joris     106:
                    107:        cvs_worklist_add(fpath, &temp_files);
1.1       jfb       108:
1.24      xsa       109:        if ((fp = fdopen(fd, "w")) == NULL) {
1.34      xsa       110:                saved_errno = errno;
1.30      joris     111:                (void)unlink(fpath);
1.34      xsa       112:                fatal("cvs_logmsg_create: fdopen %s", strerror(saved_errno));
1.8       jfb       113:        }
1.1       jfb       114:
1.8       jfb       115:        fprintf(fp, "\n%s %s\n%s Enter Log.  Lines beginning with `%s' are "
                    116:            "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE,
                    117:            CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX);
                    118:
1.31      joris     119:        if (added != NULL && !TAILQ_EMPTY(added)) {
1.30      joris     120:                fprintf(fp, "%s Added Files:", CVS_LOGMSG_PREFIX);
                    121:                TAILQ_FOREACH(cf, added, flist)
                    122:                        fprintf(fp, "\n%s\t%s",
                    123:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    124:                fputs("\n", fp);
                    125:        }
                    126:
1.31      joris     127:        if (removed != NULL && !TAILQ_EMPTY(removed)) {
1.30      joris     128:                fprintf(fp, "%s Removed Files:", CVS_LOGMSG_PREFIX);
                    129:                TAILQ_FOREACH(cf, removed, flist)
                    130:                        fprintf(fp, "\n%s\t%s",
                    131:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    132:                fputs("\n", fp);
                    133:        }
                    134:
1.31      joris     135:        if (modified != NULL && !TAILQ_EMPTY(modified)) {
1.30      joris     136:                fprintf(fp, "%s Modified Files:", CVS_LOGMSG_PREFIX);
                    137:                TAILQ_FOREACH(cf, modified, flist)
                    138:                        fprintf(fp, "\n%s\t%s",
                    139:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    140:                fputs("\n", fp);
                    141:        }
1.1       jfb       142:
1.9       jfb       143:        fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE);
1.1       jfb       144:        (void)fflush(fp);
                    145:
                    146:        if (fstat(fd, &st1) == -1) {
1.34      xsa       147:                saved_errno = errno;
1.30      joris     148:                (void)unlink(fpath);
1.34      xsa       149:                fatal("cvs_logmsg_create: fstat %s", strerror(saved_errno));
1.1       jfb       150:        }
                    151:
1.30      joris     152:        logmsg = NULL;
                    153:
1.1       jfb       154:        for (;;) {
1.41    ! ray       155:                if (cvs_logmsg_edit(fpath) == -1)
1.1       jfb       156:                        break;
1.8       jfb       157:
1.1       jfb       158:                if (fstat(fd, &st2) == -1) {
1.34      xsa       159:                        saved_errno = errno;
1.30      joris     160:                        (void)unlink(fpath);
1.34      xsa       161:                        fatal("cvs_logmsg_create: fstat %s",
                    162:                            strerror(saved_errno));
1.1       jfb       163:                }
                    164:
1.30      joris     165:                if (st1.st_mtime != st2.st_mtime) {
                    166:                        logmsg = cvs_logmsg_read(fpath);
1.1       jfb       167:                        break;
                    168:                }
                    169:
1.30      joris     170:                printf("\nLog message unchanged or not specified\n"
1.32      jasper    171:                    "a)bort, c)ontinue, e)dit\nAction: (continue) ");
1.30      joris     172:                (void)fflush(stdout);
                    173:
                    174:                c = getc(stdin);
                    175:                if (c == 'a') {
                    176:                        fatal("Aborted by user");
                    177:                } else if (c == '\n' || c == 'c') {
                    178:                        logmsg = xstrdup("");
1.1       jfb       179:                        break;
1.30      joris     180:                } else if (c == 'e') {
1.1       jfb       181:                        continue;
1.30      joris     182:                } else {
                    183:                        cvs_log(LP_ERR, "invalid input");
1.1       jfb       184:                        continue;
                    185:                }
                    186:        }
                    187:
                    188:        (void)fclose(fp);
1.30      joris     189:        (void)unlink(fpath);
                    190:        xfree(fpath);
1.1       jfb       191:
1.30      joris     192:        return (logmsg);
1.39      xsa       193: }
                    194:
1.41    ! ray       195: /*
        !           196:  * Execute an editor on the specified pathname, which is interpreted
        !           197:  * from the shell.  This means flags may be included.
        !           198:  *
        !           199:  * Returns -1 on error, or the exit value on success.
        !           200:  */
1.39      xsa       201: int
                    202: cvs_logmsg_edit(const char *pathname)
                    203: {
                    204:        char *argp[] = {"sh", "-c", NULL, NULL}, *p;
                    205:        sig_t sighup, sigint, sigquit;
                    206:        pid_t pid;
1.40      ray       207:        int saved_errno, st;
1.39      xsa       208:
                    209:        (void)xasprintf(&p, "%s %s", cvs_editor, pathname);
                    210:        argp[2] = p;
                    211:
                    212:        sighup = signal(SIGHUP, SIG_IGN);
                    213:        sigint = signal(SIGINT, SIG_IGN);
                    214:        sigquit = signal(SIGQUIT, SIG_IGN);
1.40      ray       215:        if ((pid = fork()) == -1)
                    216:                goto fail;
1.39      xsa       217:        if (pid == 0) {
                    218:                execv(_PATH_BSHELL, argp);
                    219:                _exit(127);
                    220:        }
1.40      ray       221:        while (waitpid(pid, &st, 0) == -1)
                    222:                if (errno != EINTR)
                    223:                        goto fail;
1.39      xsa       224:        xfree(p);
                    225:        (void)signal(SIGHUP, sighup);
                    226:        (void)signal(SIGINT, sigint);
                    227:        (void)signal(SIGQUIT, sigquit);
1.40      ray       228:        if (!WIFEXITED(st)) {
                    229:                errno = EINTR;
1.39      xsa       230:                return (-1);
                    231:        }
1.40      ray       232:        return (WEXITSTATUS(st));
                    233:
                    234:  fail:
                    235:        saved_errno = errno;
                    236:        (void)signal(SIGHUP, sighup);
                    237:        (void)signal(SIGINT, sigint);
                    238:        (void)signal(SIGQUIT, sigquit);
                    239:        xfree(p);
                    240:        errno = saved_errno;
                    241:        return (-1);
1.1       jfb       242: }