From 5ae6585fed5562f798fedc89869f8bfdb41e12b3 Mon Sep 17 00:00:00 2001 From: ray Date: Fri, 23 Mar 2007 01:47:11 +0000 Subject: Import public domain rewrite of sendbug, written by Ray Lai. =) Replaces GNU sendbug/sendpr, the wonderful shell script that had trouble dealing with signals, behaved differently depending on what file it read upon startup, and suffered from issues plaguing most large shell scripts. OK deraadt@. --- usr.bin/sendbug/sendbug.c | 315 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 usr.bin/sendbug/sendbug.c (limited to 'usr.bin/sendbug/sendbug.c') diff --git a/usr.bin/sendbug/sendbug.c b/usr.bin/sendbug/sendbug.c new file mode 100644 index 00000000000..aeac2dcd9bd --- /dev/null +++ b/usr.bin/sendbug/sendbug.c @@ -0,0 +1,315 @@ +/* $OpenBSD: sendbug.c,v 1.1.1.1 2007/03/23 01:47:11 ray Exp $ */ + +/* + * Written by Ray Lai . + * Public domain. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atomicio.h" + +int init(void); +int prompt(void); +int send_file(const char *, int dst); +int sendmail(const char *); +void template(FILE *); + +struct passwd *pw; +const char *categories = "system user library documentation ports kernel " + "alpha amd64 arm i386 m68k m88k mips ppc sgi sparc sparc64 vax"; +char os[BUFSIZ], rel[BUFSIZ], mach[BUFSIZ]; +char *fullname; + +int +main(int argc, char *argv[]) +{ + struct stat sb; + FILE *fp; + const char *editor, *tmpdir; + char *tmppath = NULL; + time_t mtime; + int c, fd, ret = 1; + + if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') + tmpdir = _PATH_TMP; + if (asprintf(&tmppath, "%s/p.XXXXXXXXXX", tmpdir) == -1) { + warn("asprintf"); + goto quit; + } + if ((fd = mkstemp(tmppath)) == -1) + err(1, "mkstemp"); + if ((fp = fdopen(fd, "w+")) == NULL) { + warn("fdopen"); + goto cleanup; + } + + if (init() == -1) + goto cleanup; + + template(fp); + + if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF) { + warn("error creating template"); + goto cleanup; + } + mtime = sb.st_mtime; + + edit: + if ((editor = getenv("EDITOR")) == NULL) + editor = "vi"; + switch (fork()) { + case -1: + warn("fork"); + goto cleanup; + case 0: + execlp(editor, editor, tmppath, NULL); + err(1, "execlp"); + default: + wait(NULL); + break; + } + + if (stat(tmppath, &sb) == -1) { + warn("stat"); + goto cleanup; + } + if (mtime == sb.st_mtime) { + warnx("report unchanged, nothing sent"); + goto cleanup; + } + + prompt: + c = prompt(); + switch (c) { + case 'a': case EOF: + warnx("unsent report in %s", tmppath); + goto quit; + case 'e': + goto edit; + case 's': + if (sendmail(tmppath) == -1) + goto quit; + break; + default: + goto prompt; + } + + ret = 0; + + cleanup: + if (tmppath && unlink(tmppath) == -1) + warn("unlink"); + + quit: + return (ret); +} + +int +prompt(void) +{ + int c, ret; + + fpurge(stdin); + fprintf(stderr, "a)bort, e)dit, or s)end: "); + fflush(stderr); + ret = getchar(); + if (ret == EOF || ret == '\n') + return (ret); + do { + c = getchar(); + } while (c != EOF && c != '\n'); + return (ret); +} + +int +sendmail(const char *tmppath) +{ + int filedes[2]; + + if (pipe(filedes) == -1) { + warn("pipe: unsent report in %s", tmppath); + return (-1); + } + switch (fork()) { + case -1: + warn("fork error: unsent report in %s", + tmppath); + return (-1); + case 0: + close(filedes[1]); + if (dup2(filedes[0], STDIN_FILENO) == -1) { + warn("dup2 error: unsent report in %s", + tmppath); + return (-1); + } + close(filedes[0]); + execl("/usr/sbin/sendmail", "sendmail", + "-oi", "-t", NULL); + warn("sendmail error: unsent report in %s", + tmppath); + return (-1); + default: + close(filedes[0]); + /* Pipe into sendmail. */ + if (send_file(tmppath, filedes[1]) == -1) { + warn("send_file error: unsent report in %s", + tmppath); + return (-1); + } + close(filedes[1]); + wait(NULL); + break; + } + return (0); +} + +int +init(void) +{ + size_t len; + int sysname[2]; + + if ((pw = getpwuid(getuid())) == NULL) { + warn("getpwuid"); + return (-1); + } + + /* Get full name. */ + len = strcspn(pw->pw_gecos, ","); + if ((fullname = malloc(len + 1)) == NULL) { + warn("malloc"); + return (-1); + } + memcpy(fullname, pw->pw_gecos, len); + fullname[len] = '\0'; + + sysname[0] = CTL_KERN; + sysname[1] = KERN_OSTYPE; + len = sizeof(os) - 1; + if (sysctl(sysname, 2, &os, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + sysname[0] = CTL_KERN; + sysname[1] = KERN_OSRELEASE; + len = sizeof(rel) - 1; + if (sysctl(sysname, 2, &rel, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + sysname[0] = CTL_HW; + sysname[1] = HW_MACHINE; + len = sizeof(mach) - 1; + if (sysctl(sysname, 2, &mach, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + return (0); +} + +int +send_file(const char *file, int dst) +{ + FILE *fp; + char *buf; + size_t len; + int blank = 0; + + if ((fp = fopen(file, "r")) == NULL) + return (-1); + while ((buf = fgetln(fp, &len))) { + /* Skip lines starting with "SENDBUG". */ + if (len >= sizeof("SENDBUG") - 1 && + memcmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0) + continue; + if (len == 1 && buf[0] == '\n') + blank = 1; + /* Skip comments, but only if we encountered a blank line. */ + while (len) { + char *sp, *ep = NULL; + size_t copylen; + + if (blank && (sp = memchr(buf, '<', len)) != NULL) + ep = memchr(sp, '>', len - (sp - buf + 1)); + /* Length of string before comment. */ + copylen = ep ? sp - buf : len; + if (atomicio(vwrite, dst, buf, copylen) != copylen) { + int saved_errno = errno; + + fclose(fp); + errno = saved_errno; + return (-1); + } + if (!ep) + break; + /* Skip comment. */ + len -= ep - buf + 1; + buf = ep + 1; + } + } + fclose(fp); + return (0); +} + +void +template(FILE *fp) +{ + fprintf(fp, "SENDBUG: -*- sendbug -*-\n"); + fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will be removed automatically, as\n"); + fprintf(fp, "SENDBUG: will all comments (text enclosed in `<' and `>'). \n"); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "SENDBUG: Choose from the following categories:\n"); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "SENDBUG: %s\n", categories); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "To: %s\n", "gnats@openbsd.org"); + fprintf(fp, "Subject: \n"); + fprintf(fp, "From: %s\n", pw->pw_name); + fprintf(fp, "Cc: \n"); + fprintf(fp, "Reply-To: %s\n", pw->pw_name); + fprintf(fp, "X-sendbug-version: 4.2\n"); + fprintf(fp, "\n"); + fprintf(fp, "\n"); + fprintf(fp, ">Submitter-Id:\tnet\n"); + fprintf(fp, ">Originator:\t%s\n", fullname); + fprintf(fp, ">Organization:\n"); + fprintf(fp, "net\n"); + fprintf(fp, ">Synopsis:\t\n"); + fprintf(fp, ">Severity:\t<[ non-critical | serious | critical ] (one line)>\n"); + fprintf(fp, ">Priority:\t<[ low | medium | high ] (one line)>\n"); + fprintf(fp, ">Category:\t\n"); + fprintf(fp, ">Class:\t\t<[ sw-bug | doc-bug | change-request | support ] (one line)>\n"); + fprintf(fp, ">Release:\t\n"); + fprintf(fp, ">Environment:\n"); + fprintf(fp, "\t\n"); + fprintf(fp, "\tSystem : %s %s\n", os, rel); + fprintf(fp, "\tArchitecture: %s.%s\n", os, mach); + fprintf(fp, "\tMachine : %s\n", mach); + fprintf(fp, ">Description:\n"); + fprintf(fp, "\t\n"); + fprintf(fp, ">How-To-Repeat:\n"); + fprintf(fp, "\t\n"); + fprintf(fp, ">Fix:\n"); + fprintf(fp, "\t\n"); +} -- cgit v1.2.3-59-g8ed1b