1*2aeb6b04Sderaadt /* $OpenBSD: sendbug.c,v 1.78 2017/08/21 21:41:13 deraadt Exp $ */ 25ae6585fSray 35ae6585fSray /* 45ae6585fSray * Written by Ray Lai <ray@cyth.net>. 55ae6585fSray * Public domain. 65ae6585fSray */ 75ae6585fSray 85ae6585fSray #include <sys/types.h> 95ae6585fSray #include <sys/stat.h> 105ae6585fSray #include <sys/sysctl.h> 115ae6585fSray #include <sys/wait.h> 125ae6585fSray 1349d07c37Sray #include <ctype.h> 145ae6585fSray #include <err.h> 155ae6585fSray #include <errno.h> 165ae6585fSray #include <fcntl.h> 175ae6585fSray #include <limits.h> 185ae6585fSray #include <paths.h> 195ae6585fSray #include <pwd.h> 204b9386a8Sderaadt #include <signal.h> 215ae6585fSray #include <stdio.h> 225ae6585fSray #include <stdlib.h> 235ae6585fSray #include <string.h> 245ae6585fSray #include <unistd.h> 255ae6585fSray 265ae6585fSray #include "atomicio.h" 275ae6585fSray 287d2774c0Sray #define _PATH_DMESG "/var/run/dmesg.boot" 2951cd2972Sray #define DMESG_START "OpenBSD " 308ef3815aSray #define BEGIN64 "begin-base64 " 318ef3815aSray #define END64 "====" 327d2774c0Sray 3363e56b06Sjca void checkfile(const char *); 348ef3815aSray void debase(void); 356c4efebfSray void dmesg(FILE *); 364c385748Sray int editit(const char *); 378ef3815aSray void hwdump(FILE *); 38b2e65daaStedu void init(void); 39e9d79a51Sray int matchline(const char *, const char *, size_t); 405ae6585fSray int prompt(void); 410690c094Sray int send_file(const char *, int); 425ae6585fSray int sendmail(const char *); 435ae6585fSray void template(FILE *); 44d070c508Ssthen void usbdevs(FILE *); 455ae6585fSray 46580747f8Sray const char *categories = "system user library documentation kernel " 47fbe7d4c0Smiod "alpha amd64 arm hppa i386 m88k mips64 powerpc sh sparc sparc64 vax"; 48c952560cSray const char *comment[] = { 49c952560cSray "<synopsis of the problem (one line)>", 50580747f8Sray "<PR category (one line)>", 51c952560cSray "<precise description of the problem (multiple lines)>", 52c952560cSray "<code/input/activities to reproduce the problem (multiple lines)>", 53c952560cSray "<how to correct or work around the problem, if known (multiple lines)>" 54c952560cSray }; 55823e89efSderaadt 56823e89efSderaadt struct passwd *pw; 57e051e8faSderaadt char os[BUFSIZ], rel[BUFSIZ], mach[BUFSIZ], details[BUFSIZ]; 582a3a373bSderaadt const char *tmpdir = _PATH_TMP; 596e192cfdSray char *tmppath; 605eb46beaSderaadt int Dflag, Pflag, wantcleanup; 61823e89efSderaadt 62b2e65daaStedu __dead void 63903e61cbSderaadt usage(void) 64903e61cbSderaadt { 65946adaceSray extern char *__progname; 66946adaceSray 6723243dd5Sderaadt fprintf(stderr, "usage: %s [-DEP]\n", __progname); 68b2e65daaStedu exit(1); 69903e61cbSderaadt } 70903e61cbSderaadt 71b2e65daaStedu void 72b2e65daaStedu cleanup() 73b2e65daaStedu { 74b2e65daaStedu if (wantcleanup && tmppath && unlink(tmppath) == -1) 75b2e65daaStedu warn("unlink"); 76b2e65daaStedu } 77b2e65daaStedu 78b2e65daaStedu 795ae6585fSray int 805ae6585fSray main(int argc, char *argv[]) 815ae6585fSray { 82aad8b29bSray int ch, c, fd, ret = 1; 8370dfcc75Sderaadt struct stat sb; 84f4348cb9Sderaadt char *pr_form; 8570dfcc75Sderaadt time_t mtime; 8670dfcc75Sderaadt FILE *fp; 875ae6585fSray 88ecfe3494Sderaadt if (pledge("stdio rpath wpath cpath tmppath getpw proc exec", NULL) == -1) 899a244d0bSderaadt err(1, "pledge"); 909a244d0bSderaadt 9123243dd5Sderaadt while ((ch = getopt(argc, argv, "DEP")) != -1) 92903e61cbSderaadt switch (ch) { 937d2774c0Sray case 'D': 947d2774c0Sray Dflag = 1; 957d2774c0Sray break; 968ef3815aSray case 'E': 978ef3815aSray debase(); 988ef3815aSray exit(0); 99903e61cbSderaadt case 'P': 1005eb46beaSderaadt Pflag = 1; 1015eb46beaSderaadt break; 102903e61cbSderaadt default: 103903e61cbSderaadt usage(); 104903e61cbSderaadt } 1057d2774c0Sray argc -= optind; 1067d2774c0Sray argv += optind; 107903e61cbSderaadt 108f76e53adSray if (argc > 0) 109903e61cbSderaadt usage(); 110903e61cbSderaadt 1115eb46beaSderaadt if (Pflag) { 1125eb46beaSderaadt init(); 1135eb46beaSderaadt template(stdout); 1145eb46beaSderaadt exit(0); 1155eb46beaSderaadt } 1165eb46beaSderaadt 117795a8b97Sray if (asprintf(&tmppath, "%s%sp.XXXXXXXXXX", tmpdir, 118f4348cb9Sderaadt tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1) 119b2e65daaStedu err(1, "asprintf"); 1205ae6585fSray if ((fd = mkstemp(tmppath)) == -1) 1215ae6585fSray err(1, "mkstemp"); 122b2e65daaStedu wantcleanup = 1; 123b2e65daaStedu atexit(cleanup); 124f4348cb9Sderaadt if ((fp = fdopen(fd, "w+")) == NULL) 125b2e65daaStedu err(1, "fdopen"); 1265ae6585fSray 127b2e65daaStedu init(); 1285ae6585fSray 1294ff3398aSderaadt pr_form = getenv("PR_FORM"); 1304ff3398aSderaadt if (pr_form) { 1314ff3398aSderaadt char buf[BUFSIZ]; 1324ff3398aSderaadt size_t len; 1334ff3398aSderaadt FILE *frfp; 1344ff3398aSderaadt 1354ff3398aSderaadt frfp = fopen(pr_form, "r"); 1364ff3398aSderaadt if (frfp == NULL) { 137946adaceSray warn("can't seem to read your template file " 138946adaceSray "(`%s'), ignoring PR_FORM", pr_form); 1394ff3398aSderaadt template(fp); 1404ff3398aSderaadt } else { 1414ff3398aSderaadt while (!feof(frfp)) { 1424ff3398aSderaadt len = fread(buf, 1, sizeof buf, frfp); 1434ff3398aSderaadt if (len == 0) 1444ff3398aSderaadt break; 1454ff3398aSderaadt if (fwrite(buf, 1, len, fp) != len) 1464ff3398aSderaadt break; 1474ff3398aSderaadt } 1484ff3398aSderaadt fclose(frfp); 1494ff3398aSderaadt } 150aad8b29bSray } else 1515ae6585fSray template(fp); 1525ae6585fSray 153f4348cb9Sderaadt if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF) 154b2e65daaStedu err(1, "error creating template"); 1555ae6585fSray mtime = sb.st_mtime; 1565ae6585fSray 1575ae6585fSray edit: 1583bdb63c6Sray if (editit(tmppath) == -1) 159648f0ffcSray err(1, "error running editor"); 1605ae6585fSray 161f4348cb9Sderaadt if (stat(tmppath, &sb) == -1) 162b2e65daaStedu err(1, "stat"); 163f4348cb9Sderaadt if (mtime == sb.st_mtime) 164b2e65daaStedu errx(1, "report unchanged, nothing sent"); 1655ae6585fSray 1665ae6585fSray prompt: 16763e56b06Sjca checkfile(tmppath); 1685ae6585fSray c = prompt(); 1695ae6585fSray switch (c) { 1705711e205Sderaadt case 'a': 1715711e205Sderaadt case EOF: 172b2e65daaStedu wantcleanup = 0; 173b2e65daaStedu errx(1, "unsent report in %s", tmppath); 1745ae6585fSray case 'e': 1755ae6585fSray goto edit; 1765ae6585fSray case 's': 1775ae6585fSray if (sendmail(tmppath) == -1) 1785ae6585fSray goto quit; 1795ae6585fSray break; 1805ae6585fSray default: 1815ae6585fSray goto prompt; 1825ae6585fSray } 1835ae6585fSray 1845ae6585fSray ret = 0; 1855ae6585fSray quit: 1865ae6585fSray return (ret); 1875ae6585fSray } 1885ae6585fSray 1896c4efebfSray void 1906c4efebfSray dmesg(FILE *fp) 1916c4efebfSray { 1926c4efebfSray char buf[BUFSIZ]; 1936c4efebfSray FILE *dfp; 1946c4efebfSray off_t offset = -1; 1956c4efebfSray 1966c4efebfSray dfp = fopen(_PATH_DMESG, "r"); 1976c4efebfSray if (dfp == NULL) { 1986c4efebfSray warn("can't read dmesg"); 1996c4efebfSray return; 2006c4efebfSray } 2016c4efebfSray 20251cd2972Sray /* Find last dmesg. */ 2036c4efebfSray for (;;) { 2046c4efebfSray off_t o; 2056c4efebfSray 2066c4efebfSray o = ftello(dfp); 2076c4efebfSray if (fgets(buf, sizeof(buf), dfp) == NULL) 2086c4efebfSray break; 20951cd2972Sray if (!strncmp(DMESG_START, buf, sizeof(DMESG_START) - 1)) 2106c4efebfSray offset = o; 2116c4efebfSray } 2126c4efebfSray if (offset != -1) { 2136c4efebfSray size_t len; 2146c4efebfSray 2156c4efebfSray clearerr(dfp); 2166c4efebfSray fseeko(dfp, offset, SEEK_SET); 2176c4efebfSray while (offset != -1 && !feof(dfp)) { 2186c4efebfSray len = fread(buf, 1, sizeof buf, dfp); 2196c4efebfSray if (len == 0) 2206c4efebfSray break; 2216c4efebfSray if (fwrite(buf, 1, len, fp) != len) 2226c4efebfSray break; 2236c4efebfSray } 2246c4efebfSray } 2256c4efebfSray fclose(dfp); 2266c4efebfSray } 2276c4efebfSray 228d070c508Ssthen void 229d070c508Ssthen usbdevs(FILE *ofp) 230d070c508Ssthen { 231d070c508Ssthen char buf[BUFSIZ]; 232d070c508Ssthen FILE *ifp; 233d070c508Ssthen size_t len; 234d070c508Ssthen 235d070c508Ssthen if ((ifp = popen("usbdevs -v", "r")) != NULL) { 236d070c508Ssthen while (!feof(ifp)) { 237d070c508Ssthen len = fread(buf, 1, sizeof buf, ifp); 238d070c508Ssthen if (len == 0) 239d070c508Ssthen break; 240d070c508Ssthen if (fwrite(buf, 1, len, ofp) != len) 241d070c508Ssthen break; 242d070c508Ssthen } 243d070c508Ssthen pclose(ifp); 244d070c508Ssthen } 245c025b898Ssthen } 246d070c508Ssthen 2473bdb63c6Sray /* 2483bdb63c6Sray * Execute an editor on the specified pathname, which is interpreted 2493bdb63c6Sray * from the shell. This means flags may be included. 2503bdb63c6Sray * 2513bdb63c6Sray * Returns -1 on error, or the exit value on success. 2523bdb63c6Sray */ 2534b9386a8Sderaadt int 2544c385748Sray editit(const char *pathname) 2554b9386a8Sderaadt { 256f4348cb9Sderaadt char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; 25743316b18Sderaadt sig_t sighup, sigint, sigquit, sigchld; 2584c385748Sray pid_t pid; 25943316b18Sderaadt int saved_errno, st, ret = -1; 2604b9386a8Sderaadt 261c8a426adSray ed = getenv("VISUAL"); 262c8a426adSray if (ed == NULL || ed[0] == '\0') 263c8a426adSray ed = getenv("EDITOR"); 264c8a426adSray if (ed == NULL || ed[0] == '\0') 2654b9386a8Sderaadt ed = _PATH_VI; 266292bd7edSray if (asprintf(&p, "%s %s", ed, pathname) == -1) 2678af53ff7Sray return (-1); 2684b9386a8Sderaadt argp[2] = p; 2694b9386a8Sderaadt 2708ec2d82eSray sighup = signal(SIGHUP, SIG_IGN); 2718ec2d82eSray sigint = signal(SIGINT, SIG_IGN); 2728ec2d82eSray sigquit = signal(SIGQUIT, SIG_IGN); 27343316b18Sderaadt sigchld = signal(SIGCHLD, SIG_DFL); 274ae6b53b5Sray if ((pid = fork()) == -1) 2753cf7ad38Sray goto fail; 2764b9386a8Sderaadt if (pid == 0) { 2774b9386a8Sderaadt execv(_PATH_BSHELL, argp); 2784b9386a8Sderaadt _exit(127); 2794b9386a8Sderaadt } 280*2aeb6b04Sderaadt while (waitpid(pid, &st, 0) == -1) { 2813cf7ad38Sray if (errno != EINTR) 2823cf7ad38Sray goto fail; 283*2aeb6b04Sderaadt } 28443316b18Sderaadt if (!WIFEXITED(st)) 2853bdb63c6Sray errno = EINTR; 28643316b18Sderaadt else 28743316b18Sderaadt ret = WEXITSTATUS(st); 2883cf7ad38Sray 2893cf7ad38Sray fail: 2903cf7ad38Sray saved_errno = errno; 2913cf7ad38Sray (void)signal(SIGHUP, sighup); 2923cf7ad38Sray (void)signal(SIGINT, sigint); 2933cf7ad38Sray (void)signal(SIGQUIT, sigquit); 29443316b18Sderaadt (void)signal(SIGCHLD, sigchld); 2953cf7ad38Sray free(p); 2963cf7ad38Sray errno = saved_errno; 29743316b18Sderaadt return (ret); 2984b9386a8Sderaadt } 299b2e65daaStedu 3005ae6585fSray int 3015ae6585fSray prompt(void) 3025ae6585fSray { 3035ae6585fSray int c, ret; 3045ae6585fSray 3055ae6585fSray fpurge(stdin); 3065ae6585fSray fprintf(stderr, "a)bort, e)dit, or s)end: "); 3075ae6585fSray fflush(stderr); 3085ae6585fSray ret = getchar(); 3095ae6585fSray if (ret == EOF || ret == '\n') 3105ae6585fSray return (ret); 3115ae6585fSray do { 3125ae6585fSray c = getchar(); 3135ae6585fSray } while (c != EOF && c != '\n'); 3145ae6585fSray return (ret); 3155ae6585fSray } 3165ae6585fSray 3175ae6585fSray int 318292bd7edSray sendmail(const char *pathname) 3195ae6585fSray { 3205ae6585fSray int filedes[2]; 321*2aeb6b04Sderaadt pid_t pid; 3225ae6585fSray 3235ae6585fSray if (pipe(filedes) == -1) { 324292bd7edSray warn("pipe: unsent report in %s", pathname); 3255ae6585fSray return (-1); 3265ae6585fSray } 327*2aeb6b04Sderaadt switch ((pid = fork())) { 3285ae6585fSray case -1: 3295ae6585fSray warn("fork error: unsent report in %s", 330292bd7edSray pathname); 3315ae6585fSray return (-1); 3325ae6585fSray case 0: 3335ae6585fSray close(filedes[1]); 3345ae6585fSray if (dup2(filedes[0], STDIN_FILENO) == -1) { 3355ae6585fSray warn("dup2 error: unsent report in %s", 336292bd7edSray pathname); 3375ae6585fSray return (-1); 3385ae6585fSray } 3395ae6585fSray close(filedes[0]); 3406530cc94Schl execl(_PATH_SENDMAIL, "sendmail", 34153408464Skrw "-oi", "-t", (char *)NULL); 3425ae6585fSray warn("sendmail error: unsent report in %s", 343292bd7edSray pathname); 3445ae6585fSray return (-1); 3455ae6585fSray default: 3465ae6585fSray close(filedes[0]); 3475ae6585fSray /* Pipe into sendmail. */ 348292bd7edSray if (send_file(pathname, filedes[1]) == -1) { 3495ae6585fSray warn("send_file error: unsent report in %s", 350292bd7edSray pathname); 3515ae6585fSray return (-1); 3525ae6585fSray } 3535ae6585fSray close(filedes[1]); 354*2aeb6b04Sderaadt while (waitpid(pid, NULL, 0) == -1) { 355*2aeb6b04Sderaadt if (errno != EINTR) 356*2aeb6b04Sderaadt break; 357*2aeb6b04Sderaadt } 3585ae6585fSray break; 3595ae6585fSray } 3605ae6585fSray return (0); 3615ae6585fSray } 3625ae6585fSray 363b2e65daaStedu void 3645ae6585fSray init(void) 3655ae6585fSray { 3666e192cfdSray size_t len; 367f4348cb9Sderaadt int sysname[2]; 3686e192cfdSray char *cp; 3695ae6585fSray 370f4348cb9Sderaadt if ((pw = getpwuid(getuid())) == NULL) 371b2e65daaStedu err(1, "getpwuid"); 3725ae6585fSray 3735ae6585fSray sysname[0] = CTL_KERN; 3745ae6585fSray sysname[1] = KERN_OSTYPE; 3755ae6585fSray len = sizeof(os) - 1; 376f4348cb9Sderaadt if (sysctl(sysname, 2, &os, &len, NULL, 0) == -1) 377b2e65daaStedu err(1, "sysctl"); 3785ae6585fSray 3795ae6585fSray sysname[0] = CTL_KERN; 3805ae6585fSray sysname[1] = KERN_OSRELEASE; 3815ae6585fSray len = sizeof(rel) - 1; 382f4348cb9Sderaadt if (sysctl(sysname, 2, &rel, &len, NULL, 0) == -1) 383b2e65daaStedu err(1, "sysctl"); 3845ae6585fSray 385e051e8faSderaadt sysname[0] = CTL_KERN; 386e051e8faSderaadt sysname[1] = KERN_VERSION; 387e051e8faSderaadt len = sizeof(details) - 1; 388f4348cb9Sderaadt if (sysctl(sysname, 2, &details, &len, NULL, 0) == -1) 389e051e8faSderaadt err(1, "sysctl"); 390e051e8faSderaadt 391e051e8faSderaadt cp = strchr(details, '\n'); 392e051e8faSderaadt if (cp) { 393e051e8faSderaadt cp++; 394e051e8faSderaadt if (*cp) 395e051e8faSderaadt *cp++ = '\t'; 396e051e8faSderaadt if (*cp) 397e051e8faSderaadt *cp++ = '\t'; 398e051e8faSderaadt if (*cp) 399e051e8faSderaadt *cp++ = '\t'; 400e051e8faSderaadt } 401e051e8faSderaadt 4025ae6585fSray sysname[0] = CTL_HW; 4035ae6585fSray sysname[1] = HW_MACHINE; 4045ae6585fSray len = sizeof(mach) - 1; 405f4348cb9Sderaadt if (sysctl(sysname, 2, &mach, &len, NULL, 0) == -1) 406b2e65daaStedu err(1, "sysctl"); 4075ae6585fSray } 4085ae6585fSray 4095ae6585fSray int 4105ae6585fSray send_file(const char *file, int dst) 4115ae6585fSray { 41270dfcc75Sderaadt size_t len; 41354cc23aeSray char *buf, *lbuf; 41470dfcc75Sderaadt FILE *fp; 41554cc23aeSray int rval = -1, saved_errno; 4165ae6585fSray 4175ae6585fSray if ((fp = fopen(file, "r")) == NULL) 4185ae6585fSray return (-1); 41954cc23aeSray lbuf = NULL; 4205ae6585fSray while ((buf = fgetln(fp, &len))) { 421b2c335bbSray if (buf[len - 1] == '\n') { 42254cc23aeSray buf[len - 1] = '\0'; 423b2c335bbSray --len; 424b2c335bbSray } else { 42554cc23aeSray /* EOF without EOL, copy and add the NUL */ 42654cc23aeSray if ((lbuf = malloc(len + 1)) == NULL) 42754cc23aeSray goto end; 42854cc23aeSray memcpy(lbuf, buf, len); 42954cc23aeSray lbuf[len] = '\0'; 43054cc23aeSray buf = lbuf; 43154cc23aeSray } 43254cc23aeSray 4335ae6585fSray /* Skip lines starting with "SENDBUG". */ 43454cc23aeSray if (strncmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0) 4355ae6585fSray continue; 4365ae6585fSray while (len) { 437e051e8faSderaadt char *sp = NULL, *ep = NULL; 4385ae6585fSray size_t copylen; 4395ae6585fSray 44054cc23aeSray if ((sp = strchr(buf, '<')) != NULL) { 44154cc23aeSray size_t i; 44254cc23aeSray 44354cc23aeSray for (i = 0; i < sizeof(comment) / sizeof(*comment); ++i) { 44454cc23aeSray size_t commentlen = strlen(comment[i]); 44554cc23aeSray 44654cc23aeSray if (strncmp(sp, comment[i], commentlen) == 0) { 44754cc23aeSray ep = sp + commentlen - 1; 44854cc23aeSray break; 44954cc23aeSray } 45054cc23aeSray } 45154cc23aeSray } 4525ae6585fSray /* Length of string before comment. */ 4538cf86b71Sray if (ep) 4548cf86b71Sray copylen = sp - buf; 4558cf86b71Sray else 4568cf86b71Sray copylen = len; 457b2c335bbSray if (atomicio(vwrite, dst, buf, copylen) != copylen) 45854cc23aeSray goto end; 4595ae6585fSray if (!ep) 4605ae6585fSray break; 4615ae6585fSray /* Skip comment. */ 4625ae6585fSray len -= ep - buf + 1; 4635ae6585fSray buf = ep + 1; 4645ae6585fSray } 465b2c335bbSray if (atomicio(vwrite, dst, "\n", 1) != 1) 466b2c335bbSray goto end; 4675ae6585fSray } 46854cc23aeSray rval = 0; 46954cc23aeSray end: 47054cc23aeSray saved_errno = errno; 47154cc23aeSray free(lbuf); 4725ae6585fSray fclose(fp); 47354cc23aeSray errno = saved_errno; 47454cc23aeSray return (rval); 4755ae6585fSray } 4765ae6585fSray 477fad7ccdbSray /* 478fad7ccdbSray * Does line start with `s' and end with non-comment and non-whitespace? 479e9d79a51Sray * Note: Does not treat `line' as a C string. 480fad7ccdbSray */ 481fad7ccdbSray int 482e9d79a51Sray matchline(const char *s, const char *line, size_t linelen) 483fad7ccdbSray { 484fad7ccdbSray size_t slen; 485c952560cSray int iscomment; 486fad7ccdbSray 487fad7ccdbSray slen = strlen(s); 488fad7ccdbSray /* Is line shorter than string? */ 489fad7ccdbSray if (linelen <= slen) 490fad7ccdbSray return (0); 491fad7ccdbSray /* Does line start with string? */ 492fad7ccdbSray if (memcmp(line, s, slen) != 0) 493fad7ccdbSray return (0); 494fad7ccdbSray /* Does line contain anything but comments and whitespace? */ 495fad7ccdbSray line += slen; 496fad7ccdbSray linelen -= slen; 497c952560cSray iscomment = 0; 498fad7ccdbSray while (linelen) { 499c952560cSray if (iscomment) { 500fad7ccdbSray if (*line == '>') 501c952560cSray iscomment = 0; 502fad7ccdbSray } else if (*line == '<') 503c952560cSray iscomment = 1; 504e9d79a51Sray else if (!isspace((unsigned char)*line)) 505fad7ccdbSray return (1); 506fad7ccdbSray ++line; 507fad7ccdbSray --linelen; 508fad7ccdbSray } 509fad7ccdbSray return (0); 510fad7ccdbSray } 511fad7ccdbSray 512fad7ccdbSray /* 513fad7ccdbSray * Are all required fields filled out? 514fad7ccdbSray */ 51563e56b06Sjca void 516fad7ccdbSray checkfile(const char *pathname) 517fad7ccdbSray { 518fad7ccdbSray FILE *fp; 519fad7ccdbSray size_t len; 5202dbd25f1Sjca int category = 0, synopsis = 0, subject = 0; 521fad7ccdbSray char *buf; 522fad7ccdbSray 523fad7ccdbSray if ((fp = fopen(pathname, "r")) == NULL) { 524fad7ccdbSray warn("%s", pathname); 52563e56b06Sjca return; 526fad7ccdbSray } 527fad7ccdbSray while ((buf = fgetln(fp, &len))) { 528580747f8Sray if (matchline(">Category:", buf, len)) 529580747f8Sray category = 1; 530580747f8Sray else if (matchline(">Synopsis:", buf, len)) 531580747f8Sray synopsis = 1; 5322dbd25f1Sjca else if (matchline("Subject:", buf, len)) 5332dbd25f1Sjca subject = 1; 534fad7ccdbSray } 535fad7ccdbSray fclose(fp); 5362dbd25f1Sjca if (!category || !synopsis || !subject) { 53763e56b06Sjca fprintf(stderr, "Some fields are blank, please fill them in: "); 5382dbd25f1Sjca if (!subject) 5392dbd25f1Sjca fprintf(stderr, "Subject "); 54063e56b06Sjca if (!synopsis) 54163e56b06Sjca fprintf(stderr, "Synopsis "); 54263e56b06Sjca if (!category) 54363e56b06Sjca fprintf(stderr, "Category "); 54463e56b06Sjca fputc('\n', stderr); 54563e56b06Sjca } 546fad7ccdbSray } 547fad7ccdbSray 5485ae6585fSray void 5495ae6585fSray template(FILE *fp) 5505ae6585fSray { 5515ae6585fSray fprintf(fp, "SENDBUG: -*- sendbug -*-\n"); 552f4348cb9Sderaadt fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will" 55354cc23aeSray " be removed automatically.\n"); 5545ae6585fSray fprintf(fp, "SENDBUG:\n"); 555580747f8Sray fprintf(fp, "SENDBUG: Choose from the following categories:\n"); 556580747f8Sray fprintf(fp, "SENDBUG:\n"); 557580747f8Sray fprintf(fp, "SENDBUG: %s\n", categories); 558580747f8Sray fprintf(fp, "SENDBUG:\n"); 559580747f8Sray fprintf(fp, "SENDBUG:\n"); 5608e180d99Sphessler fprintf(fp, "To: %s\n", "bugs@openbsd.org"); 5615ae6585fSray fprintf(fp, "Subject: \n"); 5625ae6585fSray fprintf(fp, "From: %s\n", pw->pw_name); 563d23b3302Sray fprintf(fp, "Cc: %s\n", pw->pw_name); 5645ae6585fSray fprintf(fp, "Reply-To: %s\n", pw->pw_name); 5655ae6585fSray fprintf(fp, "\n"); 566c952560cSray fprintf(fp, ">Synopsis:\t%s\n", comment[0]); 567580747f8Sray fprintf(fp, ">Category:\t%s\n", comment[1]); 5685ae6585fSray fprintf(fp, ">Environment:\n"); 5695ae6585fSray fprintf(fp, "\tSystem : %s %s\n", os, rel); 570e051e8faSderaadt fprintf(fp, "\tDetails : %s\n", details); 5715ae6585fSray fprintf(fp, "\tArchitecture: %s.%s\n", os, mach); 5725ae6585fSray fprintf(fp, "\tMachine : %s\n", mach); 5735ae6585fSray fprintf(fp, ">Description:\n"); 57422970bc8Sray fprintf(fp, "\t%s\n", comment[2]); 575580747f8Sray fprintf(fp, ">How-To-Repeat:\n"); 57622970bc8Sray fprintf(fp, "\t%s\n", comment[3]); 577580747f8Sray fprintf(fp, ">Fix:\n"); 578580747f8Sray fprintf(fp, "\t%s\n", comment[4]); 579aad8b29bSray 5808ef3815aSray if (!Dflag) { 5818ef3815aSray int root; 5828ef3815aSray 5838ef3815aSray fprintf(fp, "\n"); 5848ef3815aSray root = !geteuid(); 5858ef3815aSray if (!root) 5868ef3815aSray fprintf(fp, "SENDBUG: Run sendbug as root " 5878ef3815aSray "if this is an ACPI report!\n"); 588d070c508Ssthen fprintf(fp, "SENDBUG: dmesg%s and usbdevs are attached.\n" 589d070c508Ssthen "SENDBUG: Feel free to delete or use the -D flag if they " 590d070c508Ssthen "contain sensitive information.\n", 591d070c508Ssthen root ? ", pcidump, acpidump" : ""); 5928ef3815aSray fputs("\ndmesg:\n", fp); 593aad8b29bSray dmesg(fp); 594d070c508Ssthen fputs("\nusbdevs:\n", fp); 595d070c508Ssthen usbdevs(fp); 5968ef3815aSray if (root) 5978ef3815aSray hwdump(fp); 5988ef3815aSray } 5998ef3815aSray } 6008ef3815aSray 6018ef3815aSray void 6028ef3815aSray hwdump(FILE *ofp) 6038ef3815aSray { 6048ef3815aSray char buf[BUFSIZ]; 6058ef3815aSray FILE *ifp; 6068ef3815aSray char *cmd, *acpidir; 6078ef3815aSray size_t len; 6088ef3815aSray 6098ef3815aSray if (asprintf(&acpidir, "%s%sp.XXXXXXXXXX", tmpdir, 6108ef3815aSray tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1) 6118ef3815aSray err(1, "asprintf"); 6128ef3815aSray if (mkdtemp(acpidir) == NULL) 6138ef3815aSray err(1, "mkdtemp"); 6148ef3815aSray 6158ef3815aSray if (asprintf(&cmd, "echo \"\\npcidump:\"; pcidump -xxv; " 6164116c254Skettenis "echo \"\\nacpidump:\"; cd %s && cp /var/db/acpi/* .; " 6178ef3815aSray "for i in *; do b64encode $i $i; done; rm -rf %s", 6184116c254Skettenis acpidir, acpidir) == -1) 6198ef3815aSray err(1, "asprintf"); 6208ef3815aSray 6218ef3815aSray if ((ifp = popen(cmd, "r")) != NULL) { 6228ef3815aSray while (!feof(ifp)) { 6238ef3815aSray len = fread(buf, 1, sizeof buf, ifp); 6248ef3815aSray if (len == 0) 6258ef3815aSray break; 6268ef3815aSray if (fwrite(buf, 1, len, ofp) != len) 6278ef3815aSray break; 6288ef3815aSray } 629aadec989Sderaadt pclose(ifp); 630c025b898Ssthen } 6318ef3815aSray free(cmd); 632aadec989Sderaadt free(acpidir); 6338ef3815aSray } 6348ef3815aSray 6358ef3815aSray void 6368ef3815aSray debase(void) 6378ef3815aSray { 6388ef3815aSray char buf[BUFSIZ]; 6398ef3815aSray FILE *fp = NULL; 6408ef3815aSray size_t len; 6418ef3815aSray 6428ef3815aSray while (fgets(buf, sizeof(buf), stdin) != NULL) { 6438ef3815aSray len = strlen(buf); 6448ef3815aSray if (!strncmp(buf, BEGIN64, sizeof(BEGIN64) - 1)) { 6458ef3815aSray if (fp) 6468ef3815aSray errx(1, "double begin"); 6478ef3815aSray fp = popen("b64decode", "w"); 6488ef3815aSray if (!fp) 6498ef3815aSray errx(1, "popen b64decode"); 6508ef3815aSray } 6518ef3815aSray if (fp && fwrite(buf, 1, len, fp) != len) 6528ef3815aSray errx(1, "pipe error"); 6538ef3815aSray if (!strncmp(buf, END64, sizeof(END64) - 1)) { 6548ef3815aSray if (pclose(fp) == -1) 6558ef3815aSray errx(1, "pclose b64decode"); 6568ef3815aSray fp = NULL; 6578ef3815aSray } 6588ef3815aSray } 6595ae6585fSray } 660