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

Annotation of src/usr.bin/sendbug/sendbug.c, Revision 1.1

1.1     ! ray         1: /*     $OpenBSD$       */
        !             2:
        !             3: /*
        !             4:  * Written by Ray Lai <ray@cyth.net>.
        !             5:  * Public domain.
        !             6:  */
        !             7:
        !             8: #include <sys/types.h>
        !             9: #include <sys/mman.h>
        !            10: #include <sys/param.h>
        !            11: #include <sys/stat.h>
        !            12: #include <sys/sysctl.h>
        !            13: #include <sys/wait.h>
        !            14:
        !            15: #include <err.h>
        !            16: #include <errno.h>
        !            17: #include <fcntl.h>
        !            18: #include <limits.h>
        !            19: #include <paths.h>
        !            20: #include <pwd.h>
        !            21: #include <stdio.h>
        !            22: #include <stdlib.h>
        !            23: #include <string.h>
        !            24: #include <unistd.h>
        !            25:
        !            26: #include "atomicio.h"
        !            27:
        !            28: int init(void);
        !            29: int prompt(void);
        !            30: int send_file(const char *, int dst);
        !            31: int sendmail(const char *);
        !            32: void template(FILE *);
        !            33:
        !            34: struct passwd *pw;
        !            35: const char *categories = "system user library documentation ports kernel "
        !            36:     "alpha amd64 arm i386 m68k m88k mips ppc sgi sparc sparc64 vax";
        !            37: char os[BUFSIZ], rel[BUFSIZ], mach[BUFSIZ];
        !            38: char *fullname;
        !            39:
        !            40: int
        !            41: main(int argc, char *argv[])
        !            42: {
        !            43:        struct stat sb;
        !            44:        FILE *fp;
        !            45:        const char *editor, *tmpdir;
        !            46:        char *tmppath = NULL;
        !            47:        time_t mtime;
        !            48:        int c, fd, ret = 1;
        !            49:
        !            50:        if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0')
        !            51:                tmpdir = _PATH_TMP;
        !            52:        if (asprintf(&tmppath, "%s/p.XXXXXXXXXX", tmpdir) == -1) {
        !            53:                warn("asprintf");
        !            54:                goto quit;
        !            55:        }
        !            56:        if ((fd = mkstemp(tmppath)) == -1)
        !            57:                err(1, "mkstemp");
        !            58:        if ((fp = fdopen(fd, "w+")) == NULL) {
        !            59:                warn("fdopen");
        !            60:                goto cleanup;
        !            61:        }
        !            62:
        !            63:        if (init() == -1)
        !            64:                goto cleanup;
        !            65:
        !            66:        template(fp);
        !            67:
        !            68:        if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF) {
        !            69:                warn("error creating template");
        !            70:                goto cleanup;
        !            71:        }
        !            72:        mtime = sb.st_mtime;
        !            73:
        !            74:  edit:
        !            75:        if ((editor = getenv("EDITOR")) == NULL)
        !            76:                editor = "vi";
        !            77:        switch (fork()) {
        !            78:        case -1:
        !            79:                warn("fork");
        !            80:                goto cleanup;
        !            81:        case 0:
        !            82:                execlp(editor, editor, tmppath, NULL);
        !            83:                err(1, "execlp");
        !            84:        default:
        !            85:                wait(NULL);
        !            86:                break;
        !            87:        }
        !            88:
        !            89:        if (stat(tmppath, &sb) == -1) {
        !            90:                warn("stat");
        !            91:                goto cleanup;
        !            92:        }
        !            93:        if (mtime == sb.st_mtime) {
        !            94:                warnx("report unchanged, nothing sent");
        !            95:                goto cleanup;
        !            96:        }
        !            97:
        !            98:  prompt:
        !            99:        c = prompt();
        !           100:        switch (c) {
        !           101:        case 'a': case EOF:
        !           102:                warnx("unsent report in %s", tmppath);
        !           103:                goto quit;
        !           104:        case 'e':
        !           105:                goto edit;
        !           106:        case 's':
        !           107:                if (sendmail(tmppath) == -1)
        !           108:                        goto quit;
        !           109:                break;
        !           110:        default:
        !           111:                goto prompt;
        !           112:        }
        !           113:
        !           114:        ret = 0;
        !           115:
        !           116:  cleanup:
        !           117:        if (tmppath && unlink(tmppath) == -1)
        !           118:                warn("unlink");
        !           119:
        !           120:  quit:
        !           121:        return (ret);
        !           122: }
        !           123:
        !           124: int
        !           125: prompt(void)
        !           126: {
        !           127:        int c, ret;
        !           128:
        !           129:        fpurge(stdin);
        !           130:        fprintf(stderr, "a)bort, e)dit, or s)end: ");
        !           131:        fflush(stderr);
        !           132:        ret = getchar();
        !           133:        if (ret == EOF || ret == '\n')
        !           134:                return (ret);
        !           135:        do {
        !           136:                c = getchar();
        !           137:        } while (c != EOF && c != '\n');
        !           138:        return (ret);
        !           139: }
        !           140:
        !           141: int
        !           142: sendmail(const char *tmppath)
        !           143: {
        !           144:        int filedes[2];
        !           145:
        !           146:        if (pipe(filedes) == -1) {
        !           147:                warn("pipe: unsent report in %s", tmppath);
        !           148:                return (-1);
        !           149:        }
        !           150:        switch (fork()) {
        !           151:        case -1:
        !           152:                warn("fork error: unsent report in %s",
        !           153:                    tmppath);
        !           154:                return (-1);
        !           155:        case 0:
        !           156:                close(filedes[1]);
        !           157:                if (dup2(filedes[0], STDIN_FILENO) == -1) {
        !           158:                        warn("dup2 error: unsent report in %s",
        !           159:                            tmppath);
        !           160:                        return (-1);
        !           161:                }
        !           162:                close(filedes[0]);
        !           163:                execl("/usr/sbin/sendmail", "sendmail",
        !           164:                    "-oi", "-t", NULL);
        !           165:                warn("sendmail error: unsent report in %s",
        !           166:                    tmppath);
        !           167:                return (-1);
        !           168:        default:
        !           169:                close(filedes[0]);
        !           170:                /* Pipe into sendmail. */
        !           171:                if (send_file(tmppath, filedes[1]) == -1) {
        !           172:                        warn("send_file error: unsent report in %s",
        !           173:                            tmppath);
        !           174:                        return (-1);
        !           175:                }
        !           176:                close(filedes[1]);
        !           177:                wait(NULL);
        !           178:                break;
        !           179:        }
        !           180:        return (0);
        !           181: }
        !           182:
        !           183: int
        !           184: init(void)
        !           185: {
        !           186:        size_t len;
        !           187:        int sysname[2];
        !           188:
        !           189:        if ((pw = getpwuid(getuid())) == NULL) {
        !           190:                warn("getpwuid");
        !           191:                return (-1);
        !           192:        }
        !           193:
        !           194:        /* Get full name. */
        !           195:        len = strcspn(pw->pw_gecos, ",");
        !           196:        if ((fullname = malloc(len + 1)) == NULL) {
        !           197:                warn("malloc");
        !           198:                return (-1);
        !           199:        }
        !           200:        memcpy(fullname, pw->pw_gecos, len);
        !           201:        fullname[len] = '\0';
        !           202:
        !           203:        sysname[0] = CTL_KERN;
        !           204:        sysname[1] = KERN_OSTYPE;
        !           205:        len = sizeof(os) - 1;
        !           206:        if (sysctl(sysname, 2, &os, &len, NULL, 0) == -1) {
        !           207:                warn("sysctl");
        !           208:                return (-1);
        !           209:        }
        !           210:
        !           211:        sysname[0] = CTL_KERN;
        !           212:        sysname[1] = KERN_OSRELEASE;
        !           213:        len = sizeof(rel) - 1;
        !           214:        if (sysctl(sysname, 2, &rel, &len, NULL, 0) == -1) {
        !           215:                warn("sysctl");
        !           216:                return (-1);
        !           217:        }
        !           218:
        !           219:        sysname[0] = CTL_HW;
        !           220:        sysname[1] = HW_MACHINE;
        !           221:        len = sizeof(mach) - 1;
        !           222:        if (sysctl(sysname, 2, &mach, &len, NULL, 0) == -1) {
        !           223:                warn("sysctl");
        !           224:                return (-1);
        !           225:        }
        !           226:
        !           227:        return (0);
        !           228: }
        !           229:
        !           230: int
        !           231: send_file(const char *file, int dst)
        !           232: {
        !           233:        FILE *fp;
        !           234:        char *buf;
        !           235:        size_t len;
        !           236:        int blank = 0;
        !           237:
        !           238:        if ((fp = fopen(file, "r")) == NULL)
        !           239:                return (-1);
        !           240:        while ((buf = fgetln(fp, &len))) {
        !           241:                /* Skip lines starting with "SENDBUG". */
        !           242:                if (len >= sizeof("SENDBUG") - 1 &&
        !           243:                    memcmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0)
        !           244:                        continue;
        !           245:                if (len == 1 && buf[0] == '\n')
        !           246:                        blank = 1;
        !           247:                /* Skip comments, but only if we encountered a blank line. */
        !           248:                while (len) {
        !           249:                        char *sp, *ep = NULL;
        !           250:                        size_t copylen;
        !           251:
        !           252:                        if (blank && (sp = memchr(buf, '<', len)) != NULL)
        !           253:                                ep = memchr(sp, '>', len - (sp - buf + 1));
        !           254:                        /* Length of string before comment. */
        !           255:                        copylen = ep ? sp - buf : len;
        !           256:                        if (atomicio(vwrite, dst, buf, copylen) != copylen) {
        !           257:                                int saved_errno = errno;
        !           258:
        !           259:                                fclose(fp);
        !           260:                                errno = saved_errno;
        !           261:                                return (-1);
        !           262:                        }
        !           263:                        if (!ep)
        !           264:                                break;
        !           265:                        /* Skip comment. */
        !           266:                        len -= ep - buf + 1;
        !           267:                        buf = ep + 1;
        !           268:                }
        !           269:        }
        !           270:        fclose(fp);
        !           271:        return (0);
        !           272: }
        !           273:
        !           274: void
        !           275: template(FILE *fp)
        !           276: {
        !           277:        fprintf(fp, "SENDBUG: -*- sendbug -*-\n");
        !           278:        fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will be removed automatically, as\n");
        !           279:        fprintf(fp, "SENDBUG: will all comments (text enclosed in `<' and `>').              \n");
        !           280:        fprintf(fp, "SENDBUG:\n");
        !           281:        fprintf(fp, "SENDBUG: Choose from the following categories:\n");
        !           282:        fprintf(fp, "SENDBUG:\n");
        !           283:        fprintf(fp, "SENDBUG: %s\n", categories);
        !           284:        fprintf(fp, "SENDBUG:\n");
        !           285:        fprintf(fp, "SENDBUG:\n");
        !           286:        fprintf(fp, "To: %s\n", "gnats@openbsd.org");
        !           287:        fprintf(fp, "Subject: \n");
        !           288:        fprintf(fp, "From: %s\n", pw->pw_name);
        !           289:        fprintf(fp, "Cc: \n");
        !           290:        fprintf(fp, "Reply-To: %s\n", pw->pw_name);
        !           291:        fprintf(fp, "X-sendbug-version: 4.2\n");
        !           292:        fprintf(fp, "\n");
        !           293:        fprintf(fp, "\n");
        !           294:        fprintf(fp, ">Submitter-Id:\tnet\n");
        !           295:        fprintf(fp, ">Originator:\t%s\n", fullname);
        !           296:        fprintf(fp, ">Organization:\n");
        !           297:        fprintf(fp, "net\n");
        !           298:        fprintf(fp, ">Synopsis:\t<synopsis of the problem (one line)>\n");
        !           299:        fprintf(fp, ">Severity:\t<[ non-critical | serious | critical ] (one line)>\n");
        !           300:        fprintf(fp, ">Priority:\t<[ low | medium | high ] (one line)>\n");
        !           301:        fprintf(fp, ">Category:\t<PR category (one line)>\n");
        !           302:        fprintf(fp, ">Class:\t\t<[ sw-bug | doc-bug | change-request | support ] (one line)>\n");
        !           303:        fprintf(fp, ">Release:\t<release number or tag (one line)>\n");
        !           304:        fprintf(fp, ">Environment:\n");
        !           305:        fprintf(fp, "\t<machine, os, target, libraries (multiple lines)>\n");
        !           306:        fprintf(fp, "\tSystem      : %s %s\n", os, rel);
        !           307:        fprintf(fp, "\tArchitecture: %s.%s\n", os, mach);
        !           308:        fprintf(fp, "\tMachine     : %s\n", mach);
        !           309:        fprintf(fp, ">Description:\n");
        !           310:        fprintf(fp, "\t<precise description of the problem (multiple lines)>\n");
        !           311:        fprintf(fp, ">How-To-Repeat:\n");
        !           312:        fprintf(fp, "\t<code/input/activities to reproduce the problem (multiple lines)>\n");
        !           313:        fprintf(fp, ">Fix:\n");
        !           314:        fprintf(fp, "\t<how to correct or work around the problem, if known (multiple lines)>\n");
        !           315: }