Bug Summary

File:src/usr.bin/sendbug/sendbug.c
Warning:line 106, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sendbug.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/sendbug/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/sendbug/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/sendbug/sendbug.c
1/* $OpenBSD: sendbug.c,v 1.78 2017/08/21 21:41:13 deraadt Exp $ */
2
3/*
4 * Written by Ray Lai <ray@cyth.net>.
5 * Public domain.
6 */
7
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/sysctl.h>
11#include <sys/wait.h>
12
13#include <ctype.h>
14#include <err.h>
15#include <errno(*__errno()).h>
16#include <fcntl.h>
17#include <limits.h>
18#include <paths.h>
19#include <pwd.h>
20#include <signal.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "atomicio.h"
27
28#define _PATH_DMESG"/var/run/dmesg.boot" "/var/run/dmesg.boot"
29#define DMESG_START"OpenBSD " "OpenBSD "
30#define BEGIN64"begin-base64 " "begin-base64 "
31#define END64"====" "===="
32
33void checkfile(const char *);
34void debase(void);
35void dmesg(FILE *);
36int editit(const char *);
37void hwdump(FILE *);
38void init(void);
39int matchline(const char *, const char *, size_t);
40int prompt(void);
41int send_file(const char *, int);
42int sendmail(const char *);
43void template(FILE *);
44void usbdevs(FILE *);
45
46const char *categories = "system user library documentation kernel "
47 "alpha amd64 arm hppa i386 m88k mips64 powerpc sh sparc sparc64 vax";
48const char *comment[] = {
49 "<synopsis of the problem (one line)>",
50 "<PR category (one line)>",
51 "<precise description of the problem (multiple lines)>",
52 "<code/input/activities to reproduce the problem (multiple lines)>",
53 "<how to correct or work around the problem, if known (multiple lines)>"
54};
55
56struct passwd *pw;
57char os[BUFSIZ1024], rel[BUFSIZ1024], mach[BUFSIZ1024], details[BUFSIZ1024];
58const char *tmpdir = _PATH_TMP"/tmp/";
59char *tmppath;
60int Dflag, Pflag, wantcleanup;
61
62__dead__attribute__((__noreturn__)) void
63usage(void)
64{
65 extern char *__progname;
66
67 fprintf(stderr(&__sF[2]), "usage: %s [-DEP]\n", __progname);
68 exit(1);
69}
70
71void
72cleanup()
73{
74 if (wantcleanup && tmppath && unlink(tmppath) == -1)
75 warn("unlink");
76}
77
78
79int
80main(int argc, char *argv[])
81{
82 int ch, c, fd, ret = 1;
83 struct stat sb;
84 char *pr_form;
85 time_t mtime;
86 FILE *fp;
87
88 if (pledge("stdio rpath wpath cpath tmppath getpw proc exec", NULL((void *)0)) == -1)
89 err(1, "pledge");
90
91 while ((ch = getopt(argc, argv, "DEP")) != -1)
92 switch (ch) {
93 case 'D':
94 Dflag = 1;
95 break;
96 case 'E':
97 debase();
98 exit(0);
99 case 'P':
100 Pflag = 1;
101 break;
102 default:
103 usage();
104 }
105 argc -= optind;
106 argv += optind;
Value stored to 'argv' is never read
107
108 if (argc > 0)
109 usage();
110
111 if (Pflag) {
112 init();
113 template(stdout(&__sF[1]));
114 exit(0);
115 }
116
117 if (asprintf(&tmppath, "%s%sp.XXXXXXXXXX", tmpdir,
118 tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1)
119 err(1, "asprintf");
120 if ((fd = mkstemp(tmppath)) == -1)
121 err(1, "mkstemp");
122 wantcleanup = 1;
123 atexit(cleanup);
124 if ((fp = fdopen(fd, "w+")) == NULL((void *)0))
125 err(1, "fdopen");
126
127 init();
128
129 pr_form = getenv("PR_FORM");
130 if (pr_form) {
131 char buf[BUFSIZ1024];
132 size_t len;
133 FILE *frfp;
134
135 frfp = fopen(pr_form, "r");
136 if (frfp == NULL((void *)0)) {
137 warn("can't seem to read your template file "
138 "(`%s'), ignoring PR_FORM", pr_form);
139 template(fp);
140 } else {
141 while (!feof(frfp)(!__isthreaded ? (((frfp)->_flags & 0x0020) != 0) : (feof
)(frfp))
) {
142 len = fread(buf, 1, sizeof buf, frfp);
143 if (len == 0)
144 break;
145 if (fwrite(buf, 1, len, fp) != len)
146 break;
147 }
148 fclose(frfp);
149 }
150 } else
151 template(fp);
152
153 if (fflush(fp) == EOF(-1) || fstat(fd, &sb) == -1 || fclose(fp) == EOF(-1))
154 err(1, "error creating template");
155 mtime = sb.st_mtimest_mtim.tv_sec;
156
157 edit:
158 if (editit(tmppath) == -1)
159 err(1, "error running editor");
160
161 if (stat(tmppath, &sb) == -1)
162 err(1, "stat");
163 if (mtime == sb.st_mtimest_mtim.tv_sec)
164 errx(1, "report unchanged, nothing sent");
165
166 prompt:
167 checkfile(tmppath);
168 c = prompt();
169 switch (c) {
170 case 'a':
171 case EOF(-1):
172 wantcleanup = 0;
173 errx(1, "unsent report in %s", tmppath);
174 case 'e':
175 goto edit;
176 case 's':
177 if (sendmail(tmppath) == -1)
178 goto quit;
179 break;
180 default:
181 goto prompt;
182 }
183
184 ret = 0;
185quit:
186 return (ret);
187}
188
189void
190dmesg(FILE *fp)
191{
192 char buf[BUFSIZ1024];
193 FILE *dfp;
194 off_t offset = -1;
195
196 dfp = fopen(_PATH_DMESG"/var/run/dmesg.boot", "r");
197 if (dfp == NULL((void *)0)) {
198 warn("can't read dmesg");
199 return;
200 }
201
202 /* Find last dmesg. */
203 for (;;) {
204 off_t o;
205
206 o = ftello(dfp);
207 if (fgets(buf, sizeof(buf), dfp) == NULL((void *)0))
208 break;
209 if (!strncmp(DMESG_START"OpenBSD ", buf, sizeof(DMESG_START"OpenBSD ") - 1))
210 offset = o;
211 }
212 if (offset != -1) {
213 size_t len;
214
215 clearerr(dfp)(!__isthreaded ? ((void)((dfp)->_flags &= ~(0x0040|0x0020
))) : (clearerr)(dfp))
;
216 fseeko(dfp, offset, SEEK_SET0);
217 while (offset != -1 && !feof(dfp)(!__isthreaded ? (((dfp)->_flags & 0x0020) != 0) : (feof
)(dfp))
) {
218 len = fread(buf, 1, sizeof buf, dfp);
219 if (len == 0)
220 break;
221 if (fwrite(buf, 1, len, fp) != len)
222 break;
223 }
224 }
225 fclose(dfp);
226}
227
228void
229usbdevs(FILE *ofp)
230{
231 char buf[BUFSIZ1024];
232 FILE *ifp;
233 size_t len;
234
235 if ((ifp = popen("usbdevs -v", "r")) != NULL((void *)0)) {
236 while (!feof(ifp)(!__isthreaded ? (((ifp)->_flags & 0x0020) != 0) : (feof
)(ifp))
) {
237 len = fread(buf, 1, sizeof buf, ifp);
238 if (len == 0)
239 break;
240 if (fwrite(buf, 1, len, ofp) != len)
241 break;
242 }
243 pclose(ifp);
244 }
245}
246
247/*
248 * Execute an editor on the specified pathname, which is interpreted
249 * from the shell. This means flags may be included.
250 *
251 * Returns -1 on error, or the exit value on success.
252 */
253int
254editit(const char *pathname)
255{
256 char *argp[] = {"sh", "-c", NULL((void *)0), NULL((void *)0)}, *ed, *p;
257 sig_t sighup, sigint, sigquit, sigchld;
258 pid_t pid;
259 int saved_errno, st, ret = -1;
260
261 ed = getenv("VISUAL");
262 if (ed == NULL((void *)0) || ed[0] == '\0')
263 ed = getenv("EDITOR");
264 if (ed == NULL((void *)0) || ed[0] == '\0')
265 ed = _PATH_VI"/usr/bin/vi";
266 if (asprintf(&p, "%s %s", ed, pathname) == -1)
267 return (-1);
268 argp[2] = p;
269
270 sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1);
271 sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1);
272 sigquit = signal(SIGQUIT3, SIG_IGN(void (*)(int))1);
273 sigchld = signal(SIGCHLD20, SIG_DFL(void (*)(int))0);
274 if ((pid = fork()) == -1)
275 goto fail;
276 if (pid == 0) {
277 execv(_PATH_BSHELL"/bin/sh", argp);
278 _exit(127);
279 }
280 while (waitpid(pid, &st, 0) == -1) {
281 if (errno(*__errno()) != EINTR4)
282 goto fail;
283 }
284 if (!WIFEXITED(st)(((st) & 0177) == 0))
285 errno(*__errno()) = EINTR4;
286 else
287 ret = WEXITSTATUS(st)(int)(((unsigned)(st) >> 8) & 0xff);
288
289 fail:
290 saved_errno = errno(*__errno());
291 (void)signal(SIGHUP1, sighup);
292 (void)signal(SIGINT2, sigint);
293 (void)signal(SIGQUIT3, sigquit);
294 (void)signal(SIGCHLD20, sigchld);
295 free(p);
296 errno(*__errno()) = saved_errno;
297 return (ret);
298}
299
300int
301prompt(void)
302{
303 int c, ret;
304
305 fpurge(stdin(&__sF[0]));
306 fprintf(stderr(&__sF[2]), "a)bort, e)dit, or s)end: ");
307 fflush(stderr(&__sF[2]));
308 ret = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
309 if (ret == EOF(-1) || ret == '\n')
310 return (ret);
311 do {
312 c = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
313 } while (c != EOF(-1) && c != '\n');
314 return (ret);
315}
316
317int
318sendmail(const char *pathname)
319{
320 int filedes[2];
321 pid_t pid;
322
323 if (pipe(filedes) == -1) {
324 warn("pipe: unsent report in %s", pathname);
325 return (-1);
326 }
327 switch ((pid = fork())) {
328 case -1:
329 warn("fork error: unsent report in %s",
330 pathname);
331 return (-1);
332 case 0:
333 close(filedes[1]);
334 if (dup2(filedes[0], STDIN_FILENO0) == -1) {
335 warn("dup2 error: unsent report in %s",
336 pathname);
337 return (-1);
338 }
339 close(filedes[0]);
340 execl(_PATH_SENDMAIL"/usr/sbin/sendmail", "sendmail",
341 "-oi", "-t", (char *)NULL((void *)0));
342 warn("sendmail error: unsent report in %s",
343 pathname);
344 return (-1);
345 default:
346 close(filedes[0]);
347 /* Pipe into sendmail. */
348 if (send_file(pathname, filedes[1]) == -1) {
349 warn("send_file error: unsent report in %s",
350 pathname);
351 return (-1);
352 }
353 close(filedes[1]);
354 while (waitpid(pid, NULL((void *)0), 0) == -1) {
355 if (errno(*__errno()) != EINTR4)
356 break;
357 }
358 break;
359 }
360 return (0);
361}
362
363void
364init(void)
365{
366 size_t len;
367 int sysname[2];
368 char *cp;
369
370 if ((pw = getpwuid(getuid())) == NULL((void *)0))
371 err(1, "getpwuid");
372
373 sysname[0] = CTL_KERN1;
374 sysname[1] = KERN_OSTYPE1;
375 len = sizeof(os) - 1;
376 if (sysctl(sysname, 2, &os, &len, NULL((void *)0), 0) == -1)
377 err(1, "sysctl");
378
379 sysname[0] = CTL_KERN1;
380 sysname[1] = KERN_OSRELEASE2;
381 len = sizeof(rel) - 1;
382 if (sysctl(sysname, 2, &rel, &len, NULL((void *)0), 0) == -1)
383 err(1, "sysctl");
384
385 sysname[0] = CTL_KERN1;
386 sysname[1] = KERN_VERSION4;
387 len = sizeof(details) - 1;
388 if (sysctl(sysname, 2, &details, &len, NULL((void *)0), 0) == -1)
389 err(1, "sysctl");
390
391 cp = strchr(details, '\n');
392 if (cp) {
393 cp++;
394 if (*cp)
395 *cp++ = '\t';
396 if (*cp)
397 *cp++ = '\t';
398 if (*cp)
399 *cp++ = '\t';
400 }
401
402 sysname[0] = CTL_HW6;
403 sysname[1] = HW_MACHINE1;
404 len = sizeof(mach) - 1;
405 if (sysctl(sysname, 2, &mach, &len, NULL((void *)0), 0) == -1)
406 err(1, "sysctl");
407}
408
409int
410send_file(const char *file, int dst)
411{
412 size_t len;
413 char *buf, *lbuf;
414 FILE *fp;
415 int rval = -1, saved_errno;
416
417 if ((fp = fopen(file, "r")) == NULL((void *)0))
418 return (-1);
419 lbuf = NULL((void *)0);
420 while ((buf = fgetln(fp, &len))) {
421 if (buf[len - 1] == '\n') {
422 buf[len - 1] = '\0';
423 --len;
424 } else {
425 /* EOF without EOL, copy and add the NUL */
426 if ((lbuf = malloc(len + 1)) == NULL((void *)0))
427 goto end;
428 memcpy(lbuf, buf, len);
429 lbuf[len] = '\0';
430 buf = lbuf;
431 }
432
433 /* Skip lines starting with "SENDBUG". */
434 if (strncmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0)
435 continue;
436 while (len) {
437 char *sp = NULL((void *)0), *ep = NULL((void *)0);
438 size_t copylen;
439
440 if ((sp = strchr(buf, '<')) != NULL((void *)0)) {
441 size_t i;
442
443 for (i = 0; i < sizeof(comment) / sizeof(*comment); ++i) {
444 size_t commentlen = strlen(comment[i]);
445
446 if (strncmp(sp, comment[i], commentlen) == 0) {
447 ep = sp + commentlen - 1;
448 break;
449 }
450 }
451 }
452 /* Length of string before comment. */
453 if (ep)
454 copylen = sp - buf;
455 else
456 copylen = len;
457 if (atomicio(vwrite(ssize_t (*)(int, void *, size_t))write, dst, buf, copylen) != copylen)
458 goto end;
459 if (!ep)
460 break;
461 /* Skip comment. */
462 len -= ep - buf + 1;
463 buf = ep + 1;
464 }
465 if (atomicio(vwrite(ssize_t (*)(int, void *, size_t))write, dst, "\n", 1) != 1)
466 goto end;
467 }
468 rval = 0;
469 end:
470 saved_errno = errno(*__errno());
471 free(lbuf);
472 fclose(fp);
473 errno(*__errno()) = saved_errno;
474 return (rval);
475}
476
477/*
478 * Does line start with `s' and end with non-comment and non-whitespace?
479 * Note: Does not treat `line' as a C string.
480 */
481int
482matchline(const char *s, const char *line, size_t linelen)
483{
484 size_t slen;
485 int iscomment;
486
487 slen = strlen(s);
488 /* Is line shorter than string? */
489 if (linelen <= slen)
490 return (0);
491 /* Does line start with string? */
492 if (memcmp(line, s, slen) != 0)
493 return (0);
494 /* Does line contain anything but comments and whitespace? */
495 line += slen;
496 linelen -= slen;
497 iscomment = 0;
498 while (linelen) {
499 if (iscomment) {
500 if (*line == '>')
501 iscomment = 0;
502 } else if (*line == '<')
503 iscomment = 1;
504 else if (!isspace((unsigned char)*line))
505 return (1);
506 ++line;
507 --linelen;
508 }
509 return (0);
510}
511
512/*
513 * Are all required fields filled out?
514 */
515void
516checkfile(const char *pathname)
517{
518 FILE *fp;
519 size_t len;
520 int category = 0, synopsis = 0, subject = 0;
521 char *buf;
522
523 if ((fp = fopen(pathname, "r")) == NULL((void *)0)) {
524 warn("%s", pathname);
525 return;
526 }
527 while ((buf = fgetln(fp, &len))) {
528 if (matchline(">Category:", buf, len))
529 category = 1;
530 else if (matchline(">Synopsis:", buf, len))
531 synopsis = 1;
532 else if (matchline("Subject:", buf, len))
533 subject = 1;
534 }
535 fclose(fp);
536 if (!category || !synopsis || !subject) {
537 fprintf(stderr(&__sF[2]), "Some fields are blank, please fill them in: ");
538 if (!subject)
539 fprintf(stderr(&__sF[2]), "Subject ");
540 if (!synopsis)
541 fprintf(stderr(&__sF[2]), "Synopsis ");
542 if (!category)
543 fprintf(stderr(&__sF[2]), "Category ");
544 fputc('\n', stderr(&__sF[2]));
545 }
546}
547
548void
549template(FILE *fp)
550{
551 fprintf(fp, "SENDBUG: -*- sendbug -*-\n");
552 fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will"
553 " be removed automatically.\n");
554 fprintf(fp, "SENDBUG:\n");
555 fprintf(fp, "SENDBUG: Choose from the following categories:\n");
556 fprintf(fp, "SENDBUG:\n");
557 fprintf(fp, "SENDBUG: %s\n", categories);
558 fprintf(fp, "SENDBUG:\n");
559 fprintf(fp, "SENDBUG:\n");
560 fprintf(fp, "To: %s\n", "bugs@openbsd.org");
561 fprintf(fp, "Subject: \n");
562 fprintf(fp, "From: %s\n", pw->pw_name);
563 fprintf(fp, "Cc: %s\n", pw->pw_name);
564 fprintf(fp, "Reply-To: %s\n", pw->pw_name);
565 fprintf(fp, "\n");
566 fprintf(fp, ">Synopsis:\t%s\n", comment[0]);
567 fprintf(fp, ">Category:\t%s\n", comment[1]);
568 fprintf(fp, ">Environment:\n");
569 fprintf(fp, "\tSystem : %s %s\n", os, rel);
570 fprintf(fp, "\tDetails : %s\n", details);
571 fprintf(fp, "\tArchitecture: %s.%s\n", os, mach);
572 fprintf(fp, "\tMachine : %s\n", mach);
573 fprintf(fp, ">Description:\n");
574 fprintf(fp, "\t%s\n", comment[2]);
575 fprintf(fp, ">How-To-Repeat:\n");
576 fprintf(fp, "\t%s\n", comment[3]);
577 fprintf(fp, ">Fix:\n");
578 fprintf(fp, "\t%s\n", comment[4]);
579
580 if (!Dflag) {
581 int root;
582
583 fprintf(fp, "\n");
584 root = !geteuid();
585 if (!root)
586 fprintf(fp, "SENDBUG: Run sendbug as root "
587 "if this is an ACPI report!\n");
588 fprintf(fp, "SENDBUG: dmesg%s and usbdevs are attached.\n"
589 "SENDBUG: Feel free to delete or use the -D flag if they "
590 "contain sensitive information.\n",
591 root ? ", pcidump, acpidump" : "");
592 fputs("\ndmesg:\n", fp);
593 dmesg(fp);
594 fputs("\nusbdevs:\n", fp);
595 usbdevs(fp);
596 if (root)
597 hwdump(fp);
598 }
599}
600
601void
602hwdump(FILE *ofp)
603{
604 char buf[BUFSIZ1024];
605 FILE *ifp;
606 char *cmd, *acpidir;
607 size_t len;
608
609 if (asprintf(&acpidir, "%s%sp.XXXXXXXXXX", tmpdir,
610 tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1)
611 err(1, "asprintf");
612 if (mkdtemp(acpidir) == NULL((void *)0))
613 err(1, "mkdtemp");
614
615 if (asprintf(&cmd, "echo \"\\npcidump:\"; pcidump -xxv; "
616 "echo \"\\nacpidump:\"; cd %s && cp /var/db/acpi/* .; "
617 "for i in *; do b64encode $i $i; done; rm -rf %s",
618 acpidir, acpidir) == -1)
619 err(1, "asprintf");
620
621 if ((ifp = popen(cmd, "r")) != NULL((void *)0)) {
622 while (!feof(ifp)(!__isthreaded ? (((ifp)->_flags & 0x0020) != 0) : (feof
)(ifp))
) {
623 len = fread(buf, 1, sizeof buf, ifp);
624 if (len == 0)
625 break;
626 if (fwrite(buf, 1, len, ofp) != len)
627 break;
628 }
629 pclose(ifp);
630 }
631 free(cmd);
632 free(acpidir);
633}
634
635void
636debase(void)
637{
638 char buf[BUFSIZ1024];
639 FILE *fp = NULL((void *)0);
640 size_t len;
641
642 while (fgets(buf, sizeof(buf), stdin(&__sF[0])) != NULL((void *)0)) {
643 len = strlen(buf);
644 if (!strncmp(buf, BEGIN64"begin-base64 ", sizeof(BEGIN64"begin-base64 ") - 1)) {
645 if (fp)
646 errx(1, "double begin");
647 fp = popen("b64decode", "w");
648 if (!fp)
649 errx(1, "popen b64decode");
650 }
651 if (fp && fwrite(buf, 1, len, fp) != len)
652 errx(1, "pipe error");
653 if (!strncmp(buf, END64"====", sizeof(END64"====") - 1)) {
654 if (pclose(fp) == -1)
655 errx(1, "pclose b64decode");
656 fp = NULL((void *)0);
657 }
658 }
659}