Bug Summary

File:src/bin/ps/ps.c
Warning:line 255, column 2
Value stored to 'argc' 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 ps.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/bin/ps/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/bin/ps/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/bin/ps/ps.c
1/* $OpenBSD: ps.c,v 1.78 2021/12/01 18:21:23 deraadt Exp $ */
2/* $NetBSD: ps.c,v 1.15 1995/05/18 20:33:25 mycroft Exp $ */
3
4/*-
5 * Copyright (c) 1990, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h> /* NODEV */
34#include <sys/types.h>
35#include <sys/signal.h>
36#include <sys/sysctl.h>
37#include <sys/time.h>
38#include <sys/resource.h>
39#include <sys/proc.h>
40#include <sys/stat.h>
41#include <sys/ioctl.h>
42
43#include <ctype.h>
44#include <err.h>
45#include <errno(*__errno()).h>
46#include <fcntl.h>
47#include <kvm.h>
48#include <locale.h>
49#include <nlist.h>
50#include <paths.h>
51#include <pwd.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56#include <limits.h>
57
58#include "ps.h"
59
60extern char *__progname;
61
62struct varent *vhead;
63
64int eval; /* exit value */
65int sumrusage; /* -S */
66int termwidth; /* width of screen (0 == infinity) */
67int totwidth; /* calculated width of requested variables */
68
69int needcomm, needenv, neednlist, commandonly;
70
71enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
72
73static char *kludge_oldps_options(char *);
74static int pscomp(const void *, const void *);
75static void scanvars(void);
76static void usage(void);
77
78char dfmt[] = "pid tt state time command";
79char tfmt[] = "pid tid tt state time command";
80char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
81char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
82char o1[] = "pid";
83char o2[] = "tt state time command";
84char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
85char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
86
87kvm_t *kd;
88int kvm_sysctl_only;
89
90int
91main(int argc, char *argv[])
92{
93 struct kinfo_proc *kp, **kinfo;
94 struct varent *vent;
95 struct winsize ws;
96 dev_t ttydev;
97 pid_t pid;
98 uid_t uid;
99 int all, ch, flag, i, fmt, lineno, nentries;
100 int prtheader, showthreads, wflag, kflag, what, Uflag, xflg;
101 char *nlistf, *memf, *swapf, *cols, errbuf[_POSIX2_LINE_MAX2048];
102
103 setlocale(LC_CTYPE2, "");
104
105 termwidth = 0;
106 if ((cols = getenv("COLUMNS")) != NULL((void *)0))
107 termwidth = strtonum(cols, 1, INT_MAX2147483647, NULL((void *)0));
108 if (termwidth == 0 &&
109 (ioctl(STDOUT_FILENO1, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &ws) == 0 ||
110 ioctl(STDERR_FILENO2, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &ws) == 0 ||
111 ioctl(STDIN_FILENO0, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &ws) == 0) &&
112 ws.ws_col > 0)
113 termwidth = ws.ws_col - 1;
114 if (termwidth == 0)
115 termwidth = 79;
116
117 if (argc > 1)
118 argv[1] = kludge_oldps_options(argv[1]);
119
120 all = fmt = prtheader = showthreads = wflag = kflag = Uflag = xflg = 0;
121 pid = -1;
122 uid = 0;
123 ttydev = NODEV(dev_t)(-1);
124 memf = nlistf = swapf = NULL((void *)0);
125 while ((ch = getopt(argc, argv,
126 "AaCcegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
127 switch (ch) {
128 case 'A':
129 all = 1;
130 xflg = 1;
131 break;
132 case 'a':
133 all = 1;
134 break;
135 case 'C':
136 break; /* no-op */
137 case 'c':
138 commandonly = 1;
139 break;
140 case 'e': /* XXX set ufmt */
141 needenv = 1;
142 break;
143 case 'g':
144 break; /* no-op */
145 case 'H':
146 showthreads = 1;
147 break;
148 case 'h':
149 prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
150 break;
151 case 'j':
152 parsefmt(jfmt);
153 fmt = 1;
154 jfmt[0] = '\0';
155 break;
156 case 'k':
157 kflag = 1;
158 break;
159 case 'L':
160 showkey();
161 exit(0);
162 case 'l':
163 parsefmt(lfmt);
164 fmt = 1;
165 lfmt[0] = '\0';
166 break;
167 case 'M':
168 memf = optarg;
169 break;
170 case 'm':
171 sortby = SORTMEM;
172 break;
173 case 'N':
174 nlistf = optarg;
175 break;
176 case 'O':
177 parsefmt(o1);
178 parsefmt(optarg);
179 parsefmt(o2);
180 o1[0] = o2[0] = '\0';
181 fmt = 1;
182 break;
183 case 'o':
184 parsefmt(optarg);
185 fmt = 1;
186 break;
187 case 'p':
188 pid = atol(optarg);
189 xflg = 1;
190 break;
191 case 'r':
192 sortby = SORTCPU;
193 break;
194 case 'S':
195 sumrusage = 1;
196 break;
197 case 'T':
198 if ((optarg = ttyname(STDIN_FILENO0)) == NULL((void *)0))
199 errx(1, "stdin: not a terminal");
200 /* FALLTHROUGH */
201 case 't': {
202 struct stat sb;
203 char *ttypath, pathbuf[PATH_MAX1024];
204
205 if (strcmp(optarg, "co") == 0)
206 ttypath = _PATH_CONSOLE"/dev/console";
207 else if (*optarg != '/') {
208 int r = snprintf(pathbuf, sizeof(pathbuf), "%s%s",
209 _PATH_TTY"/dev/tty", optarg);
210 if (r < 0 || r > sizeof(pathbuf))
211 errx(1, "%s: too long\n", optarg);
212 ttypath = pathbuf;
213 } else
214 ttypath = optarg;
215 if (stat(ttypath, &sb) == -1)
216 err(1, "%s", ttypath);
217 if (!S_ISCHR(sb.st_mode)((sb.st_mode & 0170000) == 0020000))
218 errx(1, "%s: not a terminal", ttypath);
219 ttydev = sb.st_rdev;
220 break;
221 }
222 case 'U':
223 if (uid_from_user(optarg, &uid) == -1)
224 errx(1, "%s: no such user", optarg);
225 Uflag = xflg = 1;
226 break;
227 case 'u':
228 parsefmt(ufmt);
229 sortby = SORTCPU;
230 fmt = 1;
231 ufmt[0] = '\0';
232 break;
233 case 'v':
234 parsefmt(vfmt);
235 sortby = SORTMEM;
236 fmt = 1;
237 vfmt[0] = '\0';
238 break;
239 case 'W':
240 swapf = optarg;
241 break;
242 case 'w':
243 if (wflag)
244 termwidth = UNLIMITED0;
245 else if (termwidth < 131)
246 termwidth = 131;
247 wflag = 1;
248 break;
249 case 'x':
250 xflg = 1;
251 break;
252 default:
253 usage();
254 }
255 argc -= optind;
Value stored to 'argc' is never read
256 argv += optind;
257
258#define BACKWARD_COMPATIBILITY
259#ifdef BACKWARD_COMPATIBILITY
260 if (*argv) {
261 nlistf = *argv;
262 if (*++argv) {
263 memf = *argv;
264 if (*++argv)
265 swapf = *argv;
266 }
267 }
268#endif
269
270 if (nlistf == NULL((void *)0) && memf == NULL((void *)0) && swapf == NULL((void *)0)) {
271 kd = kvm_openfiles(NULL((void *)0), NULL((void *)0), NULL((void *)0), KVM_NO_FILES0x80000000, errbuf);
272 kvm_sysctl_only = 1;
273 } else {
274 kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY0x0000, errbuf);
275 }
276 if (kd == NULL((void *)0))
277 errx(1, "%s", errbuf);
278
279 if (unveil(_PATH_DEVDB"/var/run/dev.db", "r") == -1 && errno(*__errno()) != ENOENT2)
280 err(1, "unveil %s", _PATH_DEVDB"/var/run/dev.db");
281 if (unveil(_PATH_DEV"/dev/", "r") == -1 && errno(*__errno()) != ENOENT2)
282 err(1, "unveil %s", _PATH_DEV"/dev/");
283 if (swapf)
284 if (unveil(swapf, "r") == -1)
285 err(1, "unveil %s", swapf);
286 if (nlistf)
287 if (unveil(nlistf, "r") == -1)
288 err(1, "unveil %s", nlistf);
289 if (memf)
290 if (unveil(memf, "r") == -1)
291 err(1, "unveil %s", memf);
292 if (pledge("stdio rpath getpw ps", NULL((void *)0)) == -1)
293 err(1, "pledge");
294
295 if (!fmt) {
296 if (showthreads)
297 parsefmt(tfmt);
298 else
299 parsefmt(dfmt);
300 }
301
302 /* XXX - should be cleaner */
303 if (!all && ttydev == NODEV(dev_t)(-1) && pid == -1 && !Uflag) {
304 uid = getuid();
305 Uflag = 1;
306 }
307
308 /*
309 * scan requested variables, noting what structures are needed,
310 * and adjusting header widths as appropriate.
311 */
312 scanvars();
313
314 if (neednlist && !nlistread)
315 (void) donlist();
316
317 /*
318 * get proc list
319 */
320 if (Uflag) {
321 what = KERN_PROC_UID5;
322 flag = uid;
323 } else if (ttydev != NODEV(dev_t)(-1)) {
324 what = KERN_PROC_TTY4;
325 flag = ttydev;
326 } else if (pid != -1) {
327 what = KERN_PROC_PID1;
328 flag = pid;
329 } else if (kflag) {
330 what = KERN_PROC_KTHREAD7;
331 flag = 0;
332 } else {
333 what = KERN_PROC_ALL0;
334 flag = 0;
335 }
336 if (showthreads)
337 what |= KERN_PROC_SHOW_THREADS0x40000000;
338
339 /*
340 * select procs
341 */
342 kp = kvm_getprocs(kd, what, flag, sizeof(*kp), &nentries);
343 if (kp == NULL((void *)0))
344 errx(1, "%s", kvm_geterr(kd));
345
346 /*
347 * print header
348 */
349 printheader();
350 if (nentries == 0)
351 exit(1);
352 /*
353 * sort proc list, we convert from an array of structs to an array
354 * of pointers to make the sort cheaper.
355 */
356 if ((kinfo = reallocarray(NULL((void *)0), nentries, sizeof(*kinfo))) == NULL((void *)0))
357 err(1, "failed to allocate memory for proc pointers");
358 for (i = 0; i < nentries; i++)
359 kinfo[i] = &kp[i];
360 qsort(kinfo, nentries, sizeof(*kinfo), pscomp);
361 /*
362 * for each proc, call each variable output function.
363 */
364 for (i = lineno = 0; i < nentries; i++) {
365 if (xflg == 0 && ((int)kinfo[i]->p_tdev == NODEV(dev_t)(-1) ||
366 (kinfo[i]->p_psflags & PS_CONTROLT0x00000001 ) == 0))
367 continue;
368 if (showthreads && kinfo[i]->p_tid == -1)
369 continue;
370 for (vent = vhead; vent; vent = vent->next) {
371 (vent->var->oproc)(kinfo[i], vent);
372 if (vent->next != NULL((void *)0))
373 (void)putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', (
&__sF[1])))
;
374 }
375 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
376 if (prtheader && lineno++ == prtheader - 4) {
377 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
378 printheader();
379 lineno = 0;
380 }
381 }
382 exit(eval);
383}
384
385static void
386scanvars(void)
387{
388 struct varent *vent;
389 VAR *v;
390 int i;
391
392 for (vent = vhead; vent; vent = vent->next) {
393 v = vent->var;
394 i = strlen(v->header);
395 if (v->width < i)
396 v->width = i;
397 totwidth += v->width + 1; /* +1 for space */
398 if (v->flag & COMM0x01)
399 needcomm = 1;
400 if (v->flag & NLIST0x10)
401 neednlist = 1;
402 }
403 totwidth--;
404}
405
406static int
407pscomp(const void *v1, const void *v2)
408{
409 const struct kinfo_proc *kp1 = *(const struct kinfo_proc **)v1;
410 const struct kinfo_proc *kp2 = *(const struct kinfo_proc **)v2;
411 int i;
412#define VSIZE(k)((k)->p_vm_dsize + (k)->p_vm_ssize + (k)->p_vm_tsize
)
((k)->p_vm_dsize + (k)->p_vm_ssize + (k)->p_vm_tsize)
413
414 if (sortby == SORTCPU && (i = getpcpu(kp2) - getpcpu(kp1)) != 0)
415 return (i);
416 if (sortby == SORTMEM && (i = VSIZE(kp2)((kp2)->p_vm_dsize + (kp2)->p_vm_ssize + (kp2)->p_vm_tsize
)
- VSIZE(kp1)((kp1)->p_vm_dsize + (kp1)->p_vm_ssize + (kp1)->p_vm_tsize
)
) != 0)
417 return (i);
418 if ((i = kp1->p_tdev - kp2->p_tdev) == 0 &&
419 (i = kp1->p_ustart_sec - kp2->p_ustart_sec) == 0)
420 i = kp1->p_ustart_usec - kp2->p_ustart_usec;
421 return (i);
422}
423
424/*
425 * ICK (all for getopt), would rather hide the ugliness
426 * here than taint the main code.
427 *
428 * ps foo -> ps -foo
429 * ps 34 -> ps -p34
430 *
431 * The old convention that 't' with no trailing tty arg means the users
432 * tty, is only supported if argv[1] doesn't begin with a '-'. This same
433 * feature is available with the option 'T', which takes no argument.
434 */
435static char *
436kludge_oldps_options(char *s)
437{
438 size_t len;
439 char *newopts, *ns, *cp;
440
441 len = strlen(s);
442 if ((newopts = ns = malloc(2 + len + 1)) == NULL((void *)0))
443 err(1, NULL((void *)0));
444 /*
445 * options begin with '-'
446 */
447 if (*s != '-')
448 *ns++ = '-'; /* add option flag */
449
450 /*
451 * gaze to end of argv[1]
452 */
453 cp = s + len - 1;
454 /*
455 * if last letter is a 't' flag with no argument (in the context
456 * of the oldps options -- option string NOT starting with a '-' --
457 * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
458 */
459 if (*cp == 't' && *s != '-')
460 *cp = 'T';
461 else {
462 /*
463 * otherwise check for trailing number, which *may* be a
464 * pid.
465 */
466 while (cp >= s && isdigit((unsigned char)*cp))
467 --cp;
468 }
469 cp++;
470 memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */
471 ns += cp - s;
472 /*
473 * if there's a trailing number, and not a preceding 'p' (pid) or
474 * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
475 */
476 if (isdigit((unsigned char)*cp) &&
477 (cp == s || (cp[-1] != 't' && cp[-1] != 'p' &&
478 (cp - 1 == s || cp[-2] != 't'))))
479 *ns++ = 'p';
480 /* and append the number */
481 (void)strlcpy(ns, cp, newopts + len + 3 - ns);
482
483 return (newopts);
484}
485
486static void
487usage(void)
488{
489 (void)fprintf(stderr(&__sF[2]),
490 "usage: %s [-AaceHhjkLlmrSTuvwx] [-M core] [-N system] [-O fmt] [-o fmt] [-p pid]\n",
491 __progname);
492 (void)fprintf(stderr(&__sF[2]),
493 "%-*s[-t tty] [-U username] [-W swap]\n", (int)strlen(__progname) + 8, "");
494 exit(1);
495}