1*c025b898Ssthen /* $OpenBSD: sendbug.c,v 1.66 2010/04/20 21:33:25 sthen Exp $ */ 25ae6585fSray 35ae6585fSray /* 45ae6585fSray * Written by Ray Lai <ray@cyth.net>. 55ae6585fSray * Public domain. 65ae6585fSray */ 75ae6585fSray 85ae6585fSray #include <sys/types.h> 95ae6585fSray #include <sys/param.h> 105ae6585fSray #include <sys/stat.h> 115ae6585fSray #include <sys/sysctl.h> 125ae6585fSray #include <sys/wait.h> 135ae6585fSray 1449d07c37Sray #include <ctype.h> 155ae6585fSray #include <err.h> 165ae6585fSray #include <errno.h> 175ae6585fSray #include <fcntl.h> 185ae6585fSray #include <limits.h> 195ae6585fSray #include <paths.h> 205ae6585fSray #include <pwd.h> 214b9386a8Sderaadt #include <signal.h> 225ae6585fSray #include <stdio.h> 235ae6585fSray #include <stdlib.h> 245ae6585fSray #include <string.h> 255ae6585fSray #include <unistd.h> 265ae6585fSray 275ae6585fSray #include "atomicio.h" 285ae6585fSray 297d2774c0Sray #define _PATH_DMESG "/var/run/dmesg.boot" 3051cd2972Sray #define DMESG_START "OpenBSD " 318ef3815aSray #define BEGIN64 "begin-base64 " 328ef3815aSray #define END64 "====" 337d2774c0Sray 34fad7ccdbSray int checkfile(const char *); 358ef3815aSray void debase(void); 366c4efebfSray void dmesg(FILE *); 374c385748Sray int editit(const char *); 388ef3815aSray void hwdump(FILE *); 39b2e65daaStedu void init(void); 40e9d79a51Sray int matchline(const char *, const char *, size_t); 415ae6585fSray int prompt(void); 420690c094Sray int send_file(const char *, int); 435ae6585fSray int sendmail(const char *); 445ae6585fSray void template(FILE *); 45d070c508Ssthen void usbdevs(FILE *); 465ae6585fSray 47580747f8Sray const char *categories = "system user library documentation kernel " 48580747f8Sray "alpha amd64 arm hppa i386 m68k m88k mips64 powerpc sh sparc sparc64 vax"; 49823e89efSderaadt char *version = "4.2"; 50c952560cSray const char *comment[] = { 51c952560cSray "<synopsis of the problem (one line)>", 52580747f8Sray "<PR category (one line)>", 53c952560cSray "<precise description of the problem (multiple lines)>", 54c952560cSray "<code/input/activities to reproduce the problem (multiple lines)>", 55c952560cSray "<how to correct or work around the problem, if known (multiple lines)>" 56c952560cSray }; 57823e89efSderaadt 58823e89efSderaadt struct passwd *pw; 59e051e8faSderaadt char os[BUFSIZ], rel[BUFSIZ], mach[BUFSIZ], details[BUFSIZ]; 608ef3815aSray const char *tmpdir; 616e192cfdSray char *tmppath; 625eb46beaSderaadt int Dflag, Pflag, wantcleanup; 63823e89efSderaadt 64b2e65daaStedu __dead void 65903e61cbSderaadt usage(void) 66903e61cbSderaadt { 67946adaceSray extern char *__progname; 68946adaceSray 698ef3815aSray fprintf(stderr, "usage: %s [-DEPV]\n", __progname); 70b2e65daaStedu exit(1); 71903e61cbSderaadt } 72903e61cbSderaadt 73b2e65daaStedu void 74b2e65daaStedu cleanup() 75b2e65daaStedu { 76b2e65daaStedu if (wantcleanup && tmppath && unlink(tmppath) == -1) 77b2e65daaStedu warn("unlink"); 78b2e65daaStedu } 79b2e65daaStedu 80b2e65daaStedu 815ae6585fSray int 825ae6585fSray main(int argc, char *argv[]) 835ae6585fSray { 84aad8b29bSray int ch, c, fd, ret = 1; 8570dfcc75Sderaadt struct stat sb; 86f4348cb9Sderaadt char *pr_form; 8770dfcc75Sderaadt time_t mtime; 8870dfcc75Sderaadt FILE *fp; 895ae6585fSray 908ef3815aSray while ((ch = getopt(argc, argv, "DEPV")) != -1) 91903e61cbSderaadt switch (ch) { 927d2774c0Sray case 'D': 937d2774c0Sray Dflag = 1; 947d2774c0Sray break; 958ef3815aSray case 'E': 968ef3815aSray debase(); 978ef3815aSray exit(0); 98903e61cbSderaadt case 'P': 995eb46beaSderaadt Pflag = 1; 1005eb46beaSderaadt break; 1015711e205Sderaadt case 'V': 1025711e205Sderaadt printf("%s\n", version); 1035711e205Sderaadt exit(0); 104903e61cbSderaadt default: 105903e61cbSderaadt usage(); 106903e61cbSderaadt } 1077d2774c0Sray argc -= optind; 1087d2774c0Sray argv += optind; 109903e61cbSderaadt 110f76e53adSray if (argc > 0) 111903e61cbSderaadt usage(); 112903e61cbSderaadt 113f89edd4bSderaadt if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') 114f89edd4bSderaadt tmpdir = _PATH_TMP; 115f89edd4bSderaadt 1165eb46beaSderaadt if (Pflag) { 1175eb46beaSderaadt init(); 1185eb46beaSderaadt template(stdout); 1195eb46beaSderaadt exit(0); 1205eb46beaSderaadt } 1215eb46beaSderaadt 122795a8b97Sray if (asprintf(&tmppath, "%s%sp.XXXXXXXXXX", tmpdir, 123f4348cb9Sderaadt tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1) 124b2e65daaStedu err(1, "asprintf"); 1255ae6585fSray if ((fd = mkstemp(tmppath)) == -1) 1265ae6585fSray err(1, "mkstemp"); 127b2e65daaStedu wantcleanup = 1; 128b2e65daaStedu atexit(cleanup); 129f4348cb9Sderaadt if ((fp = fdopen(fd, "w+")) == NULL) 130b2e65daaStedu err(1, "fdopen"); 1315ae6585fSray 132b2e65daaStedu init(); 1335ae6585fSray 1344ff3398aSderaadt pr_form = getenv("PR_FORM"); 1354ff3398aSderaadt if (pr_form) { 1364ff3398aSderaadt char buf[BUFSIZ]; 1374ff3398aSderaadt size_t len; 1384ff3398aSderaadt FILE *frfp; 1394ff3398aSderaadt 1404ff3398aSderaadt frfp = fopen(pr_form, "r"); 1414ff3398aSderaadt if (frfp == NULL) { 142946adaceSray warn("can't seem to read your template file " 143946adaceSray "(`%s'), ignoring PR_FORM", pr_form); 1444ff3398aSderaadt template(fp); 1454ff3398aSderaadt } else { 1464ff3398aSderaadt while (!feof(frfp)) { 1474ff3398aSderaadt len = fread(buf, 1, sizeof buf, frfp); 1484ff3398aSderaadt if (len == 0) 1494ff3398aSderaadt break; 1504ff3398aSderaadt if (fwrite(buf, 1, len, fp) != len) 1514ff3398aSderaadt break; 1524ff3398aSderaadt } 1534ff3398aSderaadt fclose(frfp); 1544ff3398aSderaadt } 155aad8b29bSray } else 1565ae6585fSray template(fp); 1575ae6585fSray 158f4348cb9Sderaadt if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF) 159b2e65daaStedu err(1, "error creating template"); 1605ae6585fSray mtime = sb.st_mtime; 1615ae6585fSray 1625ae6585fSray edit: 1633bdb63c6Sray if (editit(tmppath) == -1) 164648f0ffcSray err(1, "error running editor"); 1655ae6585fSray 166f4348cb9Sderaadt if (stat(tmppath, &sb) == -1) 167b2e65daaStedu err(1, "stat"); 168f4348cb9Sderaadt if (mtime == sb.st_mtime) 169b2e65daaStedu errx(1, "report unchanged, nothing sent"); 1705ae6585fSray 1715ae6585fSray prompt: 172fad7ccdbSray if (!checkfile(tmppath)) 173fad7ccdbSray fprintf(stderr, "fields are blank, must be filled in\n"); 1745ae6585fSray c = prompt(); 1755ae6585fSray switch (c) { 1765711e205Sderaadt case 'a': 1775711e205Sderaadt case EOF: 178b2e65daaStedu wantcleanup = 0; 179b2e65daaStedu errx(1, "unsent report in %s", tmppath); 1805ae6585fSray case 'e': 1815ae6585fSray goto edit; 1825ae6585fSray case 's': 1835ae6585fSray if (sendmail(tmppath) == -1) 1845ae6585fSray goto quit; 1855ae6585fSray break; 1865ae6585fSray default: 1875ae6585fSray goto prompt; 1885ae6585fSray } 1895ae6585fSray 1905ae6585fSray ret = 0; 1915ae6585fSray quit: 1925ae6585fSray return (ret); 1935ae6585fSray } 1945ae6585fSray 1956c4efebfSray void 1966c4efebfSray dmesg(FILE *fp) 1976c4efebfSray { 1986c4efebfSray char buf[BUFSIZ]; 1996c4efebfSray FILE *dfp; 2006c4efebfSray off_t offset = -1; 2016c4efebfSray 2026c4efebfSray dfp = fopen(_PATH_DMESG, "r"); 2036c4efebfSray if (dfp == NULL) { 2046c4efebfSray warn("can't read dmesg"); 2056c4efebfSray return; 2066c4efebfSray } 2076c4efebfSray 20851cd2972Sray /* Find last dmesg. */ 2096c4efebfSray for (;;) { 2106c4efebfSray off_t o; 2116c4efebfSray 2126c4efebfSray o = ftello(dfp); 2136c4efebfSray if (fgets(buf, sizeof(buf), dfp) == NULL) 2146c4efebfSray break; 21551cd2972Sray if (!strncmp(DMESG_START, buf, sizeof(DMESG_START) - 1)) 2166c4efebfSray offset = o; 2176c4efebfSray } 2186c4efebfSray if (offset != -1) { 2196c4efebfSray size_t len; 2206c4efebfSray 2216c4efebfSray clearerr(dfp); 2226c4efebfSray fseeko(dfp, offset, SEEK_SET); 2236c4efebfSray while (offset != -1 && !feof(dfp)) { 2246c4efebfSray len = fread(buf, 1, sizeof buf, dfp); 2256c4efebfSray if (len == 0) 2266c4efebfSray break; 2276c4efebfSray if (fwrite(buf, 1, len, fp) != len) 2286c4efebfSray break; 2296c4efebfSray } 2306c4efebfSray } 2316c4efebfSray fclose(dfp); 2326c4efebfSray } 2336c4efebfSray 234d070c508Ssthen void 235d070c508Ssthen usbdevs(FILE *ofp) 236d070c508Ssthen { 237d070c508Ssthen char buf[BUFSIZ]; 238d070c508Ssthen FILE *ifp; 239d070c508Ssthen size_t len; 240d070c508Ssthen 241d070c508Ssthen if ((ifp = popen("usbdevs -v", "r")) != NULL) { 242d070c508Ssthen while (!feof(ifp)) { 243d070c508Ssthen len = fread(buf, 1, sizeof buf, ifp); 244d070c508Ssthen if (len == 0) 245d070c508Ssthen break; 246d070c508Ssthen if (fwrite(buf, 1, len, ofp) != len) 247d070c508Ssthen break; 248d070c508Ssthen } 249d070c508Ssthen pclose(ifp); 250d070c508Ssthen } 251*c025b898Ssthen } 252d070c508Ssthen 2533bdb63c6Sray /* 2543bdb63c6Sray * Execute an editor on the specified pathname, which is interpreted 2553bdb63c6Sray * from the shell. This means flags may be included. 2563bdb63c6Sray * 2573bdb63c6Sray * Returns -1 on error, or the exit value on success. 2583bdb63c6Sray */ 2594b9386a8Sderaadt int 2604c385748Sray editit(const char *pathname) 2614b9386a8Sderaadt { 262f4348cb9Sderaadt char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; 26343316b18Sderaadt sig_t sighup, sigint, sigquit, sigchld; 2644c385748Sray pid_t pid; 26543316b18Sderaadt int saved_errno, st, ret = -1; 2664b9386a8Sderaadt 267c8a426adSray ed = getenv("VISUAL"); 268c8a426adSray if (ed == NULL || ed[0] == '\0') 269c8a426adSray ed = getenv("EDITOR"); 270c8a426adSray if (ed == NULL || ed[0] == '\0') 2714b9386a8Sderaadt ed = _PATH_VI; 272292bd7edSray if (asprintf(&p, "%s %s", ed, pathname) == -1) 2738af53ff7Sray return (-1); 2744b9386a8Sderaadt argp[2] = p; 2754b9386a8Sderaadt 2768ec2d82eSray sighup = signal(SIGHUP, SIG_IGN); 2778ec2d82eSray sigint = signal(SIGINT, SIG_IGN); 2788ec2d82eSray sigquit = signal(SIGQUIT, SIG_IGN); 27943316b18Sderaadt sigchld = signal(SIGCHLD, SIG_DFL); 280ae6b53b5Sray if ((pid = fork()) == -1) 2813cf7ad38Sray goto fail; 2824b9386a8Sderaadt if (pid == 0) { 2834b9386a8Sderaadt execv(_PATH_BSHELL, argp); 2844b9386a8Sderaadt _exit(127); 2854b9386a8Sderaadt } 2863cf7ad38Sray while (waitpid(pid, &st, 0) == -1) 2873cf7ad38Sray if (errno != EINTR) 2883cf7ad38Sray goto fail; 28943316b18Sderaadt if (!WIFEXITED(st)) 2903bdb63c6Sray errno = EINTR; 29143316b18Sderaadt else 29243316b18Sderaadt ret = WEXITSTATUS(st); 2933cf7ad38Sray 2943cf7ad38Sray fail: 2953cf7ad38Sray saved_errno = errno; 2963cf7ad38Sray (void)signal(SIGHUP, sighup); 2973cf7ad38Sray (void)signal(SIGINT, sigint); 2983cf7ad38Sray (void)signal(SIGQUIT, sigquit); 29943316b18Sderaadt (void)signal(SIGCHLD, sigchld); 3003cf7ad38Sray free(p); 3013cf7ad38Sray errno = saved_errno; 30243316b18Sderaadt return (ret); 3034b9386a8Sderaadt } 304b2e65daaStedu 3055ae6585fSray int 3065ae6585fSray prompt(void) 3075ae6585fSray { 3085ae6585fSray int c, ret; 3095ae6585fSray 3105ae6585fSray fpurge(stdin); 3115ae6585fSray fprintf(stderr, "a)bort, e)dit, or s)end: "); 3125ae6585fSray fflush(stderr); 3135ae6585fSray ret = getchar(); 3145ae6585fSray if (ret == EOF || ret == '\n') 3155ae6585fSray return (ret); 3165ae6585fSray do { 3175ae6585fSray c = getchar(); 3185ae6585fSray } while (c != EOF && c != '\n'); 3195ae6585fSray return (ret); 3205ae6585fSray } 3215ae6585fSray 3225ae6585fSray int 323292bd7edSray sendmail(const char *pathname) 3245ae6585fSray { 3255ae6585fSray int filedes[2]; 3265ae6585fSray 3275ae6585fSray if (pipe(filedes) == -1) { 328292bd7edSray warn("pipe: unsent report in %s", pathname); 3295ae6585fSray return (-1); 3305ae6585fSray } 3315ae6585fSray switch (fork()) { 3325ae6585fSray case -1: 3335ae6585fSray warn("fork error: unsent report in %s", 334292bd7edSray pathname); 3355ae6585fSray return (-1); 3365ae6585fSray case 0: 3375ae6585fSray close(filedes[1]); 3385ae6585fSray if (dup2(filedes[0], STDIN_FILENO) == -1) { 3395ae6585fSray warn("dup2 error: unsent report in %s", 340292bd7edSray pathname); 3415ae6585fSray return (-1); 3425ae6585fSray } 3435ae6585fSray close(filedes[0]); 3446530cc94Schl execl(_PATH_SENDMAIL, "sendmail", 34570dfcc75Sderaadt "-oi", "-t", (void *)NULL); 3465ae6585fSray warn("sendmail error: unsent report in %s", 347292bd7edSray pathname); 3485ae6585fSray return (-1); 3495ae6585fSray default: 3505ae6585fSray close(filedes[0]); 3515ae6585fSray /* Pipe into sendmail. */ 352292bd7edSray if (send_file(pathname, filedes[1]) == -1) { 3535ae6585fSray warn("send_file error: unsent report in %s", 354292bd7edSray pathname); 3555ae6585fSray return (-1); 3565ae6585fSray } 3575ae6585fSray close(filedes[1]); 3585ae6585fSray wait(NULL); 3595ae6585fSray break; 3605ae6585fSray } 3615ae6585fSray return (0); 3625ae6585fSray } 3635ae6585fSray 364b2e65daaStedu void 3655ae6585fSray init(void) 3665ae6585fSray { 3676e192cfdSray size_t len; 368f4348cb9Sderaadt int sysname[2]; 3696e192cfdSray char *cp; 3705ae6585fSray 371f4348cb9Sderaadt if ((pw = getpwuid(getuid())) == NULL) 372b2e65daaStedu err(1, "getpwuid"); 3735ae6585fSray 3745ae6585fSray sysname[0] = CTL_KERN; 3755ae6585fSray sysname[1] = KERN_OSTYPE; 3765ae6585fSray len = sizeof(os) - 1; 377f4348cb9Sderaadt if (sysctl(sysname, 2, &os, &len, NULL, 0) == -1) 378b2e65daaStedu err(1, "sysctl"); 3795ae6585fSray 3805ae6585fSray sysname[0] = CTL_KERN; 3815ae6585fSray sysname[1] = KERN_OSRELEASE; 3825ae6585fSray len = sizeof(rel) - 1; 383f4348cb9Sderaadt if (sysctl(sysname, 2, &rel, &len, NULL, 0) == -1) 384b2e65daaStedu err(1, "sysctl"); 3855ae6585fSray 386e051e8faSderaadt sysname[0] = CTL_KERN; 387e051e8faSderaadt sysname[1] = KERN_VERSION; 388e051e8faSderaadt len = sizeof(details) - 1; 389f4348cb9Sderaadt if (sysctl(sysname, 2, &details, &len, NULL, 0) == -1) 390e051e8faSderaadt err(1, "sysctl"); 391e051e8faSderaadt 392e051e8faSderaadt cp = strchr(details, '\n'); 393e051e8faSderaadt if (cp) { 394e051e8faSderaadt cp++; 395e051e8faSderaadt if (*cp) 396e051e8faSderaadt *cp++ = '\t'; 397e051e8faSderaadt if (*cp) 398e051e8faSderaadt *cp++ = '\t'; 399e051e8faSderaadt if (*cp) 400e051e8faSderaadt *cp++ = '\t'; 401e051e8faSderaadt } 402e051e8faSderaadt 4035ae6585fSray sysname[0] = CTL_HW; 4045ae6585fSray sysname[1] = HW_MACHINE; 4055ae6585fSray len = sizeof(mach) - 1; 406f4348cb9Sderaadt if (sysctl(sysname, 2, &mach, &len, NULL, 0) == -1) 407b2e65daaStedu err(1, "sysctl"); 4085ae6585fSray } 4095ae6585fSray 4105ae6585fSray int 4115ae6585fSray send_file(const char *file, int dst) 4125ae6585fSray { 41370dfcc75Sderaadt size_t len; 41454cc23aeSray char *buf, *lbuf; 41570dfcc75Sderaadt FILE *fp; 41654cc23aeSray int rval = -1, saved_errno; 4175ae6585fSray 4185ae6585fSray if ((fp = fopen(file, "r")) == NULL) 4195ae6585fSray return (-1); 42054cc23aeSray lbuf = NULL; 4215ae6585fSray while ((buf = fgetln(fp, &len))) { 422b2c335bbSray if (buf[len - 1] == '\n') { 42354cc23aeSray buf[len - 1] = '\0'; 424b2c335bbSray --len; 425b2c335bbSray } else { 42654cc23aeSray /* EOF without EOL, copy and add the NUL */ 42754cc23aeSray if ((lbuf = malloc(len + 1)) == NULL) 42854cc23aeSray goto end; 42954cc23aeSray memcpy(lbuf, buf, len); 43054cc23aeSray lbuf[len] = '\0'; 43154cc23aeSray buf = lbuf; 43254cc23aeSray } 43354cc23aeSray 4345ae6585fSray /* Skip lines starting with "SENDBUG". */ 43554cc23aeSray if (strncmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0) 4365ae6585fSray continue; 4375ae6585fSray while (len) { 438e051e8faSderaadt char *sp = NULL, *ep = NULL; 4395ae6585fSray size_t copylen; 4405ae6585fSray 44154cc23aeSray if ((sp = strchr(buf, '<')) != NULL) { 44254cc23aeSray size_t i; 44354cc23aeSray 44454cc23aeSray for (i = 0; i < sizeof(comment) / sizeof(*comment); ++i) { 44554cc23aeSray size_t commentlen = strlen(comment[i]); 44654cc23aeSray 44754cc23aeSray if (strncmp(sp, comment[i], commentlen) == 0) { 44854cc23aeSray ep = sp + commentlen - 1; 44954cc23aeSray break; 45054cc23aeSray } 45154cc23aeSray } 45254cc23aeSray } 4535ae6585fSray /* Length of string before comment. */ 4548cf86b71Sray if (ep) 4558cf86b71Sray copylen = sp - buf; 4568cf86b71Sray else 4578cf86b71Sray copylen = len; 458b2c335bbSray if (atomicio(vwrite, dst, buf, copylen) != copylen) 45954cc23aeSray goto end; 4605ae6585fSray if (!ep) 4615ae6585fSray break; 4625ae6585fSray /* Skip comment. */ 4635ae6585fSray len -= ep - buf + 1; 4645ae6585fSray buf = ep + 1; 4655ae6585fSray } 466b2c335bbSray if (atomicio(vwrite, dst, "\n", 1) != 1) 467b2c335bbSray goto end; 4685ae6585fSray } 46954cc23aeSray rval = 0; 47054cc23aeSray end: 47154cc23aeSray saved_errno = errno; 47254cc23aeSray free(lbuf); 4735ae6585fSray fclose(fp); 47454cc23aeSray errno = saved_errno; 47554cc23aeSray return (rval); 4765ae6585fSray } 4775ae6585fSray 478fad7ccdbSray /* 479fad7ccdbSray * Does line start with `s' and end with non-comment and non-whitespace? 480e9d79a51Sray * Note: Does not treat `line' as a C string. 481fad7ccdbSray */ 482fad7ccdbSray int 483e9d79a51Sray matchline(const char *s, const char *line, size_t linelen) 484fad7ccdbSray { 485fad7ccdbSray size_t slen; 486c952560cSray int iscomment; 487fad7ccdbSray 488fad7ccdbSray slen = strlen(s); 489fad7ccdbSray /* Is line shorter than string? */ 490fad7ccdbSray if (linelen <= slen) 491fad7ccdbSray return (0); 492fad7ccdbSray /* Does line start with string? */ 493fad7ccdbSray if (memcmp(line, s, slen) != 0) 494fad7ccdbSray return (0); 495fad7ccdbSray /* Does line contain anything but comments and whitespace? */ 496fad7ccdbSray line += slen; 497fad7ccdbSray linelen -= slen; 498c952560cSray iscomment = 0; 499fad7ccdbSray while (linelen) { 500c952560cSray if (iscomment) { 501fad7ccdbSray if (*line == '>') 502c952560cSray iscomment = 0; 503fad7ccdbSray } else if (*line == '<') 504c952560cSray iscomment = 1; 505e9d79a51Sray else if (!isspace((unsigned char)*line)) 506fad7ccdbSray return (1); 507fad7ccdbSray ++line; 508fad7ccdbSray --linelen; 509fad7ccdbSray } 510fad7ccdbSray return (0); 511fad7ccdbSray } 512fad7ccdbSray 513fad7ccdbSray /* 514fad7ccdbSray * Are all required fields filled out? 515fad7ccdbSray */ 516fad7ccdbSray int 517fad7ccdbSray checkfile(const char *pathname) 518fad7ccdbSray { 519fad7ccdbSray FILE *fp; 520fad7ccdbSray size_t len; 521580747f8Sray int category = 0, synopsis = 0; 522fad7ccdbSray char *buf; 523fad7ccdbSray 524fad7ccdbSray if ((fp = fopen(pathname, "r")) == NULL) { 525fad7ccdbSray warn("%s", pathname); 526fad7ccdbSray return (0); 527fad7ccdbSray } 528fad7ccdbSray while ((buf = fgetln(fp, &len))) { 529580747f8Sray if (matchline(">Category:", buf, len)) 530580747f8Sray category = 1; 531580747f8Sray else if (matchline(">Synopsis:", buf, len)) 532580747f8Sray synopsis = 1; 533fad7ccdbSray } 534fad7ccdbSray fclose(fp); 535580747f8Sray return (category && synopsis); 536fad7ccdbSray } 537fad7ccdbSray 5385ae6585fSray void 5395ae6585fSray template(FILE *fp) 5405ae6585fSray { 5415ae6585fSray fprintf(fp, "SENDBUG: -*- sendbug -*-\n"); 542f4348cb9Sderaadt fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will" 54354cc23aeSray " be removed automatically.\n"); 5445ae6585fSray fprintf(fp, "SENDBUG:\n"); 545580747f8Sray fprintf(fp, "SENDBUG: Choose from the following categories:\n"); 546580747f8Sray fprintf(fp, "SENDBUG:\n"); 547580747f8Sray fprintf(fp, "SENDBUG: %s\n", categories); 548580747f8Sray fprintf(fp, "SENDBUG:\n"); 549580747f8Sray fprintf(fp, "SENDBUG:\n"); 5505ae6585fSray fprintf(fp, "To: %s\n", "gnats@openbsd.org"); 5515ae6585fSray fprintf(fp, "Subject: \n"); 5525ae6585fSray fprintf(fp, "From: %s\n", pw->pw_name); 553d23b3302Sray fprintf(fp, "Cc: %s\n", pw->pw_name); 5545ae6585fSray fprintf(fp, "Reply-To: %s\n", pw->pw_name); 5555ae6585fSray fprintf(fp, "\n"); 556c952560cSray fprintf(fp, ">Synopsis:\t%s\n", comment[0]); 557580747f8Sray fprintf(fp, ">Category:\t%s\n", comment[1]); 5585ae6585fSray fprintf(fp, ">Environment:\n"); 5595ae6585fSray fprintf(fp, "\tSystem : %s %s\n", os, rel); 560e051e8faSderaadt fprintf(fp, "\tDetails : %s\n", details); 5615ae6585fSray fprintf(fp, "\tArchitecture: %s.%s\n", os, mach); 5625ae6585fSray fprintf(fp, "\tMachine : %s\n", mach); 5635ae6585fSray fprintf(fp, ">Description:\n"); 56422970bc8Sray fprintf(fp, "\t%s\n", comment[2]); 565580747f8Sray fprintf(fp, ">How-To-Repeat:\n"); 56622970bc8Sray fprintf(fp, "\t%s\n", comment[3]); 567580747f8Sray fprintf(fp, ">Fix:\n"); 568580747f8Sray fprintf(fp, "\t%s\n", comment[4]); 569aad8b29bSray 5708ef3815aSray if (!Dflag) { 5718ef3815aSray int root; 5728ef3815aSray 5738ef3815aSray fprintf(fp, "\n"); 5748ef3815aSray root = !geteuid(); 5758ef3815aSray if (!root) 5768ef3815aSray fprintf(fp, "SENDBUG: Run sendbug as root " 5778ef3815aSray "if this is an ACPI report!\n"); 578d070c508Ssthen fprintf(fp, "SENDBUG: dmesg%s and usbdevs are attached.\n" 579d070c508Ssthen "SENDBUG: Feel free to delete or use the -D flag if they " 580d070c508Ssthen "contain sensitive information.\n", 581d070c508Ssthen root ? ", pcidump, acpidump" : ""); 5828ef3815aSray fputs("\ndmesg:\n", fp); 583aad8b29bSray dmesg(fp); 584d070c508Ssthen fputs("\nusbdevs:\n", fp); 585d070c508Ssthen usbdevs(fp); 5868ef3815aSray if (root) 5878ef3815aSray hwdump(fp); 5888ef3815aSray } 5898ef3815aSray } 5908ef3815aSray 5918ef3815aSray void 5928ef3815aSray hwdump(FILE *ofp) 5938ef3815aSray { 5948ef3815aSray char buf[BUFSIZ]; 5958ef3815aSray FILE *ifp; 5968ef3815aSray char *cmd, *acpidir; 5978ef3815aSray size_t len; 5988ef3815aSray 5998ef3815aSray if (gethostname(buf, sizeof(buf)) == -1) 6008ef3815aSray err(1, "gethostname"); 6018ef3815aSray buf[strcspn(buf, ".")] = '\0'; 6028ef3815aSray 6038ef3815aSray if (asprintf(&acpidir, "%s%sp.XXXXXXXXXX", tmpdir, 6048ef3815aSray tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1) 6058ef3815aSray err(1, "asprintf"); 6068ef3815aSray if (mkdtemp(acpidir) == NULL) 6078ef3815aSray err(1, "mkdtemp"); 6088ef3815aSray 6098ef3815aSray if (asprintf(&cmd, "echo \"\\npcidump:\"; pcidump -xxv; " 6108ef3815aSray "echo \"\\nacpidump:\"; cd %s && acpidump -o %s; " 6118ef3815aSray "for i in *; do b64encode $i $i; done; rm -rf %s", 6128ef3815aSray acpidir, buf, acpidir) == -1) 6138ef3815aSray err(1, "asprintf"); 6148ef3815aSray 6158ef3815aSray if ((ifp = popen(cmd, "r")) != NULL) { 6168ef3815aSray while (!feof(ifp)) { 6178ef3815aSray len = fread(buf, 1, sizeof buf, ifp); 6188ef3815aSray if (len == 0) 6198ef3815aSray break; 6208ef3815aSray if (fwrite(buf, 1, len, ofp) != len) 6218ef3815aSray break; 6228ef3815aSray } 623aadec989Sderaadt pclose(ifp); 624*c025b898Ssthen } 6258ef3815aSray free(cmd); 626aadec989Sderaadt free(acpidir); 6278ef3815aSray } 6288ef3815aSray 6298ef3815aSray void 6308ef3815aSray debase(void) 6318ef3815aSray { 6328ef3815aSray char buf[BUFSIZ]; 6338ef3815aSray FILE *fp = NULL; 6348ef3815aSray size_t len; 6358ef3815aSray 6368ef3815aSray while (fgets(buf, sizeof(buf), stdin) != NULL) { 6378ef3815aSray len = strlen(buf); 6388ef3815aSray if (!strncmp(buf, BEGIN64, sizeof(BEGIN64) - 1)) { 6398ef3815aSray if (fp) 6408ef3815aSray errx(1, "double begin"); 6418ef3815aSray fp = popen("b64decode", "w"); 6428ef3815aSray if (!fp) 6438ef3815aSray errx(1, "popen b64decode"); 6448ef3815aSray } 6458ef3815aSray if (fp && fwrite(buf, 1, len, fp) != len) 6468ef3815aSray errx(1, "pipe error"); 6478ef3815aSray if (!strncmp(buf, END64, sizeof(END64) - 1)) { 6488ef3815aSray if (pclose(fp) == -1) 6498ef3815aSray errx(1, "pclose b64decode"); 6508ef3815aSray fp = NULL; 6518ef3815aSray } 6528ef3815aSray } 6535ae6585fSray } 654