[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.47

1.47    ! tobias      1: /*     $OpenBSD: logmsg.c,v 1.46 2008/02/11 20:33:11 tobias 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.45      chl        26: #include <stdlib.h>
1.38      otto       27: #include <string.h>
                     28: #include <unistd.h>
1.1       jfb        29:
                     30: #include "cvs.h"
                     31:
1.30      joris      32: #define CVS_LOGMSG_PREFIX              "CVS:"
                     33: #define CVS_LOGMSG_LINE                \
1.1       jfb        34: "----------------------------------------------------------------------"
                     35:
1.39      xsa        36: int    cvs_logmsg_edit(const char *);
                     37:
1.17      xsa        38: char *
1.30      joris      39: cvs_logmsg_read(const char *path)
1.1       jfb        40: {
1.30      joris      41:        int fd;
                     42:        BUF *bp;
                     43:        FILE *fp;
1.1       jfb        44:        size_t len;
                     45:        struct stat st;
1.30      joris      46:        char *buf, *lbuf;
                     47:
                     48:        if ((fd = open(path, O_RDONLY)) == -1)
                     49:                fatal("cvs_logmsg_read: open %s", strerror(errno));
1.1       jfb        50:
1.30      joris      51:        if (fstat(fd, &st) == -1)
                     52:                fatal("cvs_logmsg_read: fstat %s", strerror(errno));
1.1       jfb        53:
1.24      xsa        54:        if (!S_ISREG(st.st_mode))
1.30      joris      55:                fatal("cvs_logmsg_read: file is not a regular file");
1.1       jfb        56:
1.30      joris      57:        if ((fp = fdopen(fd, "r")) == NULL)
                     58:                fatal("cvs_logmsg_read: fdopen %s", strerror(errno));
1.47    ! tobias     59:
        !            60:        if (st.st_size > SIZE_MAX)
        !            61:                fatal("cvs_buf_load_fd: %s: file size too big", path);
1.1       jfb        62:
1.30      joris      63:        lbuf = NULL;
1.46      tobias     64:        bp = cvs_buf_alloc(st.st_size);
1.30      joris      65:        while ((buf = fgetln(fp, &len))) {
                     66:                if (buf[len - 1] == '\n') {
                     67:                        buf[len - 1] = '\0';
                     68:                } else {
                     69:                        lbuf = xmalloc(len + 1);
1.36      otto       70:                        memcpy(lbuf, buf, len);
                     71:                        lbuf[len] = '\0';
1.30      joris      72:                        buf = lbuf;
                     73:                }
1.1       jfb        74:
1.30      joris      75:                len = strlen(buf);
                     76:
                     77:                if (!strncmp(buf, CVS_LOGMSG_PREFIX,
1.44      tobias     78:                    sizeof(CVS_LOGMSG_PREFIX) - 1))
1.1       jfb        79:                        continue;
                     80:
1.30      joris      81:                cvs_buf_append(bp, buf, len);
                     82:                cvs_buf_putc(bp, '\n');
                     83:        }
                     84:
                     85:        if (lbuf != NULL)
                     86:                xfree(lbuf);
1.1       jfb        87:
1.11      jfb        88:        (void)fclose(fp);
                     89:
1.23      xsa        90:        cvs_buf_putc(bp, '\0');
1.30      joris      91:        return (cvs_buf_release(bp));
1.1       jfb        92: }
                     93:
1.17      xsa        94: char *
1.30      joris      95: cvs_logmsg_create(struct cvs_flisthead *added, struct cvs_flisthead *removed,
                     96:        struct cvs_flisthead *modified)
1.1       jfb        97: {
                     98:        FILE *fp;
1.39      xsa        99:        int c, fd, saved_errno;
1.30      joris     100:        struct cvs_filelist *cf;
1.1       jfb       101:        struct stat st1, st2;
1.39      xsa       102:        char *fpath, *logmsg;
1.8       jfb       103:
1.35      xsa       104:        (void)xasprintf(&fpath, "%s/cvsXXXXXXXXXX", cvs_tmpdir);
1.1       jfb       105:
1.45      chl       106:        if ((fd = mkstemp(fpath)) == -1)
1.30      joris     107:                fatal("cvs_logmsg_create: mkstemp %s", strerror(errno));
1.33      joris     108:
                    109:        cvs_worklist_add(fpath, &temp_files);
1.1       jfb       110:
1.24      xsa       111:        if ((fp = fdopen(fd, "w")) == NULL) {
1.34      xsa       112:                saved_errno = errno;
1.30      joris     113:                (void)unlink(fpath);
1.34      xsa       114:                fatal("cvs_logmsg_create: fdopen %s", strerror(saved_errno));
1.8       jfb       115:        }
1.1       jfb       116:
1.8       jfb       117:        fprintf(fp, "\n%s %s\n%s Enter Log.  Lines beginning with `%s' are "
                    118:            "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE,
                    119:            CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX);
                    120:
1.31      joris     121:        if (added != NULL && !TAILQ_EMPTY(added)) {
1.30      joris     122:                fprintf(fp, "%s Added Files:", CVS_LOGMSG_PREFIX);
                    123:                TAILQ_FOREACH(cf, added, flist)
                    124:                        fprintf(fp, "\n%s\t%s",
                    125:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    126:                fputs("\n", fp);
                    127:        }
                    128:
1.31      joris     129:        if (removed != NULL && !TAILQ_EMPTY(removed)) {
1.30      joris     130:                fprintf(fp, "%s Removed Files:", CVS_LOGMSG_PREFIX);
                    131:                TAILQ_FOREACH(cf, removed, flist)
                    132:                        fprintf(fp, "\n%s\t%s",
                    133:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    134:                fputs("\n", fp);
                    135:        }
                    136:
1.31      joris     137:        if (modified != NULL && !TAILQ_EMPTY(modified)) {
1.30      joris     138:                fprintf(fp, "%s Modified Files:", CVS_LOGMSG_PREFIX);
                    139:                TAILQ_FOREACH(cf, modified, flist)
                    140:                        fprintf(fp, "\n%s\t%s",
                    141:                            CVS_LOGMSG_PREFIX, cf->file_path);
                    142:                fputs("\n", fp);
                    143:        }
1.1       jfb       144:
1.9       jfb       145:        fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE);
1.1       jfb       146:        (void)fflush(fp);
                    147:
                    148:        if (fstat(fd, &st1) == -1) {
1.34      xsa       149:                saved_errno = errno;
1.30      joris     150:                (void)unlink(fpath);
1.34      xsa       151:                fatal("cvs_logmsg_create: fstat %s", strerror(saved_errno));
1.1       jfb       152:        }
                    153:
1.30      joris     154:        logmsg = NULL;
                    155:
1.1       jfb       156:        for (;;) {
1.41      ray       157:                if (cvs_logmsg_edit(fpath) == -1)
1.1       jfb       158:                        break;
1.8       jfb       159:
1.1       jfb       160:                if (fstat(fd, &st2) == -1) {
1.34      xsa       161:                        saved_errno = errno;
1.30      joris     162:                        (void)unlink(fpath);
1.34      xsa       163:                        fatal("cvs_logmsg_create: fstat %s",
                    164:                            strerror(saved_errno));
1.1       jfb       165:                }
                    166:
1.30      joris     167:                if (st1.st_mtime != st2.st_mtime) {
                    168:                        logmsg = cvs_logmsg_read(fpath);
1.1       jfb       169:                        break;
                    170:                }
                    171:
1.30      joris     172:                printf("\nLog message unchanged or not specified\n"
1.32      jasper    173:                    "a)bort, c)ontinue, e)dit\nAction: (continue) ");
1.30      joris     174:                (void)fflush(stdout);
                    175:
                    176:                c = getc(stdin);
1.43      tobias    177:                if (c == EOF || c == 'a') {
1.30      joris     178:                        fatal("Aborted by user");
                    179:                } else if (c == '\n' || c == 'c') {
                    180:                        logmsg = xstrdup("");
1.1       jfb       181:                        break;
1.30      joris     182:                } else if (c == 'e') {
1.1       jfb       183:                        continue;
1.30      joris     184:                } else {
                    185:                        cvs_log(LP_ERR, "invalid input");
1.1       jfb       186:                        continue;
                    187:                }
                    188:        }
                    189:
                    190:        (void)fclose(fp);
1.30      joris     191:        (void)unlink(fpath);
                    192:        xfree(fpath);
1.1       jfb       193:
1.30      joris     194:        return (logmsg);
1.39      xsa       195: }
                    196:
1.41      ray       197: /*
                    198:  * Execute an editor on the specified pathname, which is interpreted
                    199:  * from the shell.  This means flags may be included.
                    200:  *
                    201:  * Returns -1 on error, or the exit value on success.
                    202:  */
1.39      xsa       203: int
                    204: cvs_logmsg_edit(const char *pathname)
                    205: {
                    206:        char *argp[] = {"sh", "-c", NULL, NULL}, *p;
                    207:        sig_t sighup, sigint, sigquit;
                    208:        pid_t pid;
1.40      ray       209:        int saved_errno, st;
1.39      xsa       210:
                    211:        (void)xasprintf(&p, "%s %s", cvs_editor, pathname);
                    212:        argp[2] = p;
                    213:
                    214:        sighup = signal(SIGHUP, SIG_IGN);
                    215:        sigint = signal(SIGINT, SIG_IGN);
                    216:        sigquit = signal(SIGQUIT, SIG_IGN);
1.40      ray       217:        if ((pid = fork()) == -1)
                    218:                goto fail;
1.39      xsa       219:        if (pid == 0) {
                    220:                execv(_PATH_BSHELL, argp);
                    221:                _exit(127);
                    222:        }
1.40      ray       223:        while (waitpid(pid, &st, 0) == -1)
                    224:                if (errno != EINTR)
                    225:                        goto fail;
1.39      xsa       226:        xfree(p);
                    227:        (void)signal(SIGHUP, sighup);
                    228:        (void)signal(SIGINT, sigint);
                    229:        (void)signal(SIGQUIT, sigquit);
1.40      ray       230:        if (!WIFEXITED(st)) {
                    231:                errno = EINTR;
1.39      xsa       232:                return (-1);
                    233:        }
1.40      ray       234:        return (WEXITSTATUS(st));
                    235:
                    236:  fail:
                    237:        saved_errno = errno;
                    238:        (void)signal(SIGHUP, sighup);
                    239:        (void)signal(SIGINT, sigint);
                    240:        (void)signal(SIGQUIT, sigquit);
                    241:        xfree(p);
                    242:        errno = saved_errno;
                    243:        return (-1);
1.1       jfb       244: }