GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: ps.c,v 1.70 2016/03/17 05:27:10 bentley 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> /* MAXCOMLEN NODEV */ |
||
34 |
#include <sys/types.h> |
||
35 |
#include <sys/sysctl.h> |
||
36 |
#include <sys/time.h> |
||
37 |
#include <sys/resource.h> |
||
38 |
#include <sys/proc.h> |
||
39 |
#include <sys/stat.h> |
||
40 |
#include <sys/ioctl.h> |
||
41 |
|||
42 |
#include <ctype.h> |
||
43 |
#include <err.h> |
||
44 |
#include <errno.h> |
||
45 |
#include <fcntl.h> |
||
46 |
#include <kvm.h> |
||
47 |
#include <locale.h> |
||
48 |
#include <nlist.h> |
||
49 |
#include <paths.h> |
||
50 |
#include <pwd.h> |
||
51 |
#include <stdio.h> |
||
52 |
#include <stdlib.h> |
||
53 |
#include <string.h> |
||
54 |
#include <unistd.h> |
||
55 |
#include <limits.h> |
||
56 |
|||
57 |
#include "ps.h" |
||
58 |
|||
59 |
extern char *__progname; |
||
60 |
|||
61 |
struct varent *vhead; |
||
62 |
|||
63 |
int eval; /* exit value */ |
||
64 |
int sumrusage; /* -S */ |
||
65 |
int termwidth; /* width of screen (0 == infinity) */ |
||
66 |
int totwidth; /* calculated width of requested variables */ |
||
67 |
|||
68 |
int needcomm, needenv, neednlist, commandonly; |
||
69 |
|||
70 |
enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; |
||
71 |
|||
72 |
static char *kludge_oldps_options(char *); |
||
73 |
static int pscomp(const void *, const void *); |
||
74 |
static void scanvars(void); |
||
75 |
static void usage(void); |
||
76 |
|||
77 |
char dfmt[] = "pid tt state time command"; |
||
78 |
char tfmt[] = "pid tid tt state time command"; |
||
79 |
char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; |
||
80 |
char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; |
||
81 |
char o1[] = "pid"; |
||
82 |
char o2[] = "tt state time command"; |
||
83 |
char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; |
||
84 |
char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; |
||
85 |
|||
86 |
kvm_t *kd; |
||
87 |
int kvm_sysctl_only; |
||
88 |
|||
89 |
int |
||
90 |
main(int argc, char *argv[]) |
||
91 |
121 |
{ |
|
92 |
struct kinfo_proc *kp, **kinfo; |
||
93 |
struct varent *vent; |
||
94 |
struct winsize ws; |
||
95 |
struct passwd *pwd; |
||
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_MAX]; |
||
102 |
|||
103 |
121 |
setlocale(LC_CTYPE, ""); |
|
104 |
|||
105 |
121 |
termwidth = 0; |
|
106 |
✓✓ | 121 |
if ((cols = getenv("COLUMNS")) != NULL) |
107 |
19 |
termwidth = strtonum(cols, 1, INT_MAX, NULL); |
|
108 |
✓✓✗✓ ✗✗ |
121 |
if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && |
109 |
ws.ws_col > 0) |
||
110 |
termwidth = ws.ws_col - 1; |
||
111 |
✓✓ | 121 |
if (termwidth == 0) |
112 |
102 |
termwidth = 79; |
|
113 |
|||
114 |
✓✗ | 121 |
if (argc > 1) |
115 |
121 |
argv[1] = kludge_oldps_options(argv[1]); |
|
116 |
|||
117 |
121 |
all = fmt = prtheader = showthreads = wflag = kflag = Uflag = xflg = 0; |
|
118 |
121 |
pid = -1; |
|
119 |
121 |
uid = 0; |
|
120 |
121 |
ttydev = NODEV; |
|
121 |
121 |
memf = nlistf = swapf = NULL; |
|
122 |
✓✓ | 662 |
while ((ch = getopt(argc, argv, |
123 |
"AaCcegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1) |
||
124 |
✗✗✓✓ ✗✗✗✗ ✓✗✗✗ ✗✗✓✓ ✗✗✗✗ ✗✗✗✗ ✓✗✗✗ |
424 |
switch (ch) { |
125 |
case 'A': |
||
126 |
all = 1; |
||
127 |
xflg = 1; |
||
128 |
break; |
||
129 |
case 'a': |
||
130 |
all = 1; |
||
131 |
break; |
||
132 |
case 'C': |
||
133 |
break; /* no-op */ |
||
134 |
case 'c': |
||
135 |
30 |
commandonly = 1; |
|
136 |
30 |
break; |
|
137 |
case 'e': /* XXX set ufmt */ |
||
138 |
46 |
needenv = 1; |
|
139 |
46 |
break; |
|
140 |
case 'g': |
||
141 |
break; /* no-op */ |
||
142 |
case 'H': |
||
143 |
showthreads = 1; |
||
144 |
break; |
||
145 |
case 'h': |
||
146 |
prtheader = ws.ws_row > 5 ? ws.ws_row : 22; |
||
147 |
break; |
||
148 |
case 'j': |
||
149 |
parsefmt(jfmt); |
||
150 |
fmt = 1; |
||
151 |
jfmt[0] = '\0'; |
||
152 |
break; |
||
153 |
case 'k': |
||
154 |
kflag = 1; |
||
155 |
break; |
||
156 |
case 'L': |
||
157 |
2 |
showkey(); |
|
158 |
2 |
exit(0); |
|
159 |
case 'l': |
||
160 |
parsefmt(lfmt); |
||
161 |
fmt = 1; |
||
162 |
lfmt[0] = '\0'; |
||
163 |
break; |
||
164 |
case 'M': |
||
165 |
memf = optarg; |
||
166 |
break; |
||
167 |
case 'm': |
||
168 |
sortby = SORTMEM; |
||
169 |
break; |
||
170 |
case 'N': |
||
171 |
nlistf = optarg; |
||
172 |
break; |
||
173 |
case 'O': |
||
174 |
parsefmt(o1); |
||
175 |
parsefmt(optarg); |
||
176 |
parsefmt(o2); |
||
177 |
o1[0] = o2[0] = '\0'; |
||
178 |
fmt = 1; |
||
179 |
break; |
||
180 |
case 'o': |
||
181 |
119 |
parsefmt(optarg); |
|
182 |
117 |
fmt = 1; |
|
183 |
117 |
break; |
|
184 |
case 'p': |
||
185 |
115 |
pid = atol(optarg); |
|
186 |
115 |
xflg = 1; |
|
187 |
115 |
break; |
|
188 |
case 'r': |
||
189 |
sortby = SORTCPU; |
||
190 |
break; |
||
191 |
case 'S': |
||
192 |
sumrusage = 1; |
||
193 |
break; |
||
194 |
case 'T': |
||
195 |
if ((optarg = ttyname(STDIN_FILENO)) == NULL) |
||
196 |
errx(1, "stdin: not a terminal"); |
||
197 |
/* FALLTHROUGH */ |
||
198 |
case 't': { |
||
199 |
struct stat sb; |
||
200 |
char *ttypath, pathbuf[PATH_MAX]; |
||
201 |
|||
202 |
if (strcmp(optarg, "co") == 0) |
||
203 |
ttypath = _PATH_CONSOLE; |
||
204 |
else if (*optarg != '/') |
||
205 |
(void)snprintf(ttypath = pathbuf, |
||
206 |
sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); |
||
207 |
else |
||
208 |
ttypath = optarg; |
||
209 |
if (stat(ttypath, &sb) == -1) |
||
210 |
err(1, "%s", ttypath); |
||
211 |
if (!S_ISCHR(sb.st_mode)) |
||
212 |
errx(1, "%s: not a terminal", ttypath); |
||
213 |
ttydev = sb.st_rdev; |
||
214 |
break; |
||
215 |
} |
||
216 |
case 'U': |
||
217 |
pwd = getpwnam(optarg); |
||
218 |
if (pwd == NULL) |
||
219 |
errx(1, "%s: no such user", optarg); |
||
220 |
uid = pwd->pw_uid; |
||
221 |
endpwent(); |
||
222 |
Uflag = xflg = 1; |
||
223 |
break; |
||
224 |
case 'u': |
||
225 |
parsefmt(ufmt); |
||
226 |
sortby = SORTCPU; |
||
227 |
fmt = 1; |
||
228 |
ufmt[0] = '\0'; |
||
229 |
break; |
||
230 |
case 'v': |
||
231 |
parsefmt(vfmt); |
||
232 |
sortby = SORTMEM; |
||
233 |
fmt = 1; |
||
234 |
vfmt[0] = '\0'; |
||
235 |
break; |
||
236 |
case 'W': |
||
237 |
swapf = optarg; |
||
238 |
break; |
||
239 |
case 'w': |
||
240 |
✓✓ | 112 |
if (wflag) |
241 |
56 |
termwidth = UNLIMITED; |
|
242 |
✓✗ | 56 |
else if (termwidth < 131) |
243 |
56 |
termwidth = 131; |
|
244 |
112 |
wflag = 1; |
|
245 |
112 |
break; |
|
246 |
case 'x': |
||
247 |
xflg = 1; |
||
248 |
break; |
||
249 |
default: |
||
250 |
usage(); |
||
251 |
} |
||
252 |
117 |
argc -= optind; |
|
253 |
117 |
argv += optind; |
|
254 |
|||
255 |
#define BACKWARD_COMPATIBILITY |
||
256 |
#ifdef BACKWARD_COMPATIBILITY |
||
257 |
✗✓ | 117 |
if (*argv) { |
258 |
nlistf = *argv; |
||
259 |
if (*++argv) { |
||
260 |
memf = *argv; |
||
261 |
if (*++argv) |
||
262 |
swapf = *argv; |
||
263 |
} |
||
264 |
} |
||
265 |
#endif |
||
266 |
|||
267 |
✓✗ | 117 |
if (nlistf == NULL && memf == NULL && swapf == NULL) { |
268 |
117 |
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); |
|
269 |
117 |
kvm_sysctl_only = 1; |
|
270 |
} else { |
||
271 |
kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); |
||
272 |
} |
||
273 |
✗✓ | 117 |
if (kd == NULL) |
274 |
errx(1, "%s", errbuf); |
||
275 |
|||
276 |
✗✓ | 117 |
if (pledge("stdio rpath getpw ps wpath cpath", NULL) == -1) |
277 |
err(1, "pledge"); |
||
278 |
|||
279 |
✗✓ | 117 |
if (!fmt) { |
280 |
if (showthreads) |
||
281 |
parsefmt(tfmt); |
||
282 |
else |
||
283 |
parsefmt(dfmt); |
||
284 |
} |
||
285 |
|||
286 |
/* XXX - should be cleaner */ |
||
287 |
✓✗✓✓ |
117 |
if (!all && ttydev == NODEV && pid == -1 && !Uflag) { |
288 |
2 |
uid = getuid(); |
|
289 |
2 |
Uflag = 1; |
|
290 |
} |
||
291 |
|||
292 |
/* |
||
293 |
* scan requested variables, noting what structures are needed, |
||
294 |
* and adjusting header widths as appropriate. |
||
295 |
*/ |
||
296 |
117 |
scanvars(); |
|
297 |
|||
298 |
✓✓✓✗ |
117 |
if (neednlist && !nlistread) |
299 |
2 |
(void) donlist(); |
|
300 |
|||
301 |
/* |
||
302 |
* get proc list |
||
303 |
*/ |
||
304 |
✓✓ | 117 |
if (Uflag) { |
305 |
2 |
what = KERN_PROC_UID; |
|
306 |
2 |
flag = uid; |
|
307 |
✗✓ | 115 |
} else if (ttydev != NODEV) { |
308 |
what = KERN_PROC_TTY; |
||
309 |
flag = ttydev; |
||
310 |
✓✗ | 115 |
} else if (pid != -1) { |
311 |
115 |
what = KERN_PROC_PID; |
|
312 |
115 |
flag = pid; |
|
313 |
} else if (kflag) { |
||
314 |
what = KERN_PROC_KTHREAD; |
||
315 |
flag = 0; |
||
316 |
} else { |
||
317 |
what = KERN_PROC_ALL; |
||
318 |
flag = 0; |
||
319 |
} |
||
320 |
✗✓ | 117 |
if (showthreads) |
321 |
what |= KERN_PROC_SHOW_THREADS; |
||
322 |
|||
323 |
/* |
||
324 |
* select procs |
||
325 |
*/ |
||
326 |
117 |
kp = kvm_getprocs(kd, what, flag, sizeof(*kp), &nentries); |
|
327 |
✗✓ | 117 |
if (kp == NULL) |
328 |
errx(1, "%s", kvm_geterr(kd)); |
||
329 |
|||
330 |
/* |
||
331 |
* print header |
||
332 |
*/ |
||
333 |
117 |
printheader(); |
|
334 |
✗✓ | 117 |
if (nentries == 0) |
335 |
exit(1); |
||
336 |
/* |
||
337 |
* sort proc list, we convert from an array of structs to an array |
||
338 |
* of pointers to make the sort cheaper. |
||
339 |
*/ |
||
340 |
✗✓ | 117 |
if ((kinfo = reallocarray(NULL, nentries, sizeof(*kinfo))) == NULL) |
341 |
err(1, "failed to allocate memory for proc pointers"); |
||
342 |
✓✓ | 320 |
for (i = 0; i < nentries; i++) |
343 |
203 |
kinfo[i] = &kp[i]; |
|
344 |
117 |
qsort(kinfo, nentries, sizeof(*kinfo), pscomp); |
|
345 |
/* |
||
346 |
* for each proc, call each variable output function. |
||
347 |
*/ |
||
348 |
✓✓ | 320 |
for (i = lineno = 0; i < nentries; i++) { |
349 |
✓✗✗✓ |
203 |
if (showthreads == 0 && (kinfo[i]->p_flag & P_THREAD) != 0) |
350 |
continue; |
||
351 |
✓✓✓✓ ✓✗ |
203 |
if (xflg == 0 && ((int)kinfo[i]->p_tdev == NODEV || |
352 |
(kinfo[i]->p_psflags & PS_CONTROLT ) == 0)) |
||
353 |
continue; |
||
354 |
✗✓✗✗ |
147 |
if (showthreads && kinfo[i]->p_tid == -1) |
355 |
continue; |
||
356 |
✓✓ | 2741 |
for (vent = vhead; vent; vent = vent->next) { |
357 |
2594 |
(vent->var->oproc)(kinfo[i], vent); |
|
358 |
✓✓ | 2594 |
if (vent->next != NULL) |
359 |
✓✗ | 2447 |
(void)putchar(' '); |
360 |
} |
||
361 |
✓✗ | 147 |
(void)putchar('\n'); |
362 |
✗✓✗✗ |
147 |
if (prtheader && lineno++ == prtheader - 4) { |
363 |
(void)putchar('\n'); |
||
364 |
printheader(); |
||
365 |
lineno = 0; |
||
366 |
} |
||
367 |
} |
||
368 |
117 |
exit(eval); |
|
369 |
} |
||
370 |
|||
371 |
static void |
||
372 |
scanvars(void) |
||
373 |
117 |
{ |
|
374 |
struct varent *vent; |
||
375 |
VAR *v; |
||
376 |
int i; |
||
377 |
|||
378 |
✓✓ | 491 |
for (vent = vhead; vent; vent = vent->next) { |
379 |
374 |
v = vent->var; |
|
380 |
374 |
i = strlen(v->header); |
|
381 |
✓✓ | 374 |
if (v->width < i) |
382 |
26 |
v->width = i; |
|
383 |
374 |
totwidth += v->width + 1; /* +1 for space */ |
|
384 |
✓✓ | 374 |
if (v->flag & COMM) |
385 |
103 |
needcomm = 1; |
|
386 |
✓✓ | 374 |
if (v->flag & NLIST) |
387 |
6 |
neednlist = 1; |
|
388 |
} |
||
389 |
117 |
totwidth--; |
|
390 |
117 |
} |
|
391 |
|||
392 |
static int |
||
393 |
pscomp(const void *v1, const void *v2) |
||
394 |
389 |
{ |
|
395 |
389 |
const struct kinfo_proc *kp1 = *(const struct kinfo_proc **)v1; |
|
396 |
389 |
const struct kinfo_proc *kp2 = *(const struct kinfo_proc **)v2; |
|
397 |
int i; |
||
398 |
#define VSIZE(k) ((k)->p_vm_dsize + (k)->p_vm_ssize + (k)->p_vm_tsize) |
||
399 |
|||
400 |
✗✓✗✗ |
389 |
if (sortby == SORTCPU && (i = getpcpu(kp2) - getpcpu(kp1)) != 0) |
401 |
return (i); |
||
402 |
✗✓✗✗ |
389 |
if (sortby == SORTMEM && (i = VSIZE(kp2) - VSIZE(kp1)) != 0) |
403 |
return (i); |
||
404 |
✓✓✓✓ |
389 |
if ((i = kp1->p_tdev - kp2->p_tdev) == 0 && |
405 |
(i = kp1->p_ustart_sec - kp2->p_ustart_sec) == 0) |
||
406 |
114 |
i = kp1->p_ustart_usec - kp2->p_ustart_usec; |
|
407 |
389 |
return (i); |
|
408 |
} |
||
409 |
|||
410 |
/* |
||
411 |
* ICK (all for getopt), would rather hide the ugliness |
||
412 |
* here than taint the main code. |
||
413 |
* |
||
414 |
* ps foo -> ps -foo |
||
415 |
* ps 34 -> ps -p34 |
||
416 |
* |
||
417 |
* The old convention that 't' with no trailing tty arg means the users |
||
418 |
* tty, is only supported if argv[1] doesn't begin with a '-'. This same |
||
419 |
* feature is available with the option 'T', which takes no argument. |
||
420 |
*/ |
||
421 |
static char * |
||
422 |
kludge_oldps_options(char *s) |
||
423 |
121 |
{ |
|
424 |
size_t len; |
||
425 |
char *newopts, *ns, *cp; |
||
426 |
|||
427 |
121 |
len = strlen(s); |
|
428 |
✗✓ | 121 |
if ((newopts = ns = malloc(2 + len + 1)) == NULL) |
429 |
err(1, NULL); |
||
430 |
/* |
||
431 |
* options begin with '-' |
||
432 |
*/ |
||
433 |
✗✓ | 121 |
if (*s != '-') |
434 |
*ns++ = '-'; /* add option flag */ |
||
435 |
|||
436 |
/* |
||
437 |
* gaze to end of argv[1] |
||
438 |
*/ |
||
439 |
121 |
cp = s + len - 1; |
|
440 |
/* |
||
441 |
* if last letter is a 't' flag with no argument (in the context |
||
442 |
* of the oldps options -- option string NOT starting with a '-' -- |
||
443 |
* then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). |
||
444 |
*/ |
||
445 |
✗✓✗✗ |
121 |
if (*cp == 't' && *s != '-') |
446 |
*cp = 'T'; |
||
447 |
else { |
||
448 |
/* |
||
449 |
* otherwise check for trailing number, which *may* be a |
||
450 |
* pid. |
||
451 |
*/ |
||
452 |
✓✗✗✓ |
121 |
while (cp >= s && isdigit((unsigned char)*cp)) |
453 |
--cp; |
||
454 |
} |
||
455 |
121 |
cp++; |
|
456 |
121 |
memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ |
|
457 |
121 |
ns += cp - s; |
|
458 |
/* |
||
459 |
* if there's a trailing number, and not a preceding 'p' (pid) or |
||
460 |
* 't' (tty) flag, then assume it's a pid and insert a 'p' flag. |
||
461 |
*/ |
||
462 |
✗✓✗✗ ✗✗✗✗ ✗✗ |
121 |
if (isdigit((unsigned char)*cp) && |
463 |
(cp == s || (cp[-1] != 't' && cp[-1] != 'p' && |
||
464 |
(cp - 1 == s || cp[-2] != 't')))) |
||
465 |
*ns++ = 'p'; |
||
466 |
/* and append the number */ |
||
467 |
121 |
(void)strlcpy(ns, cp, newopts + len + 3 - ns); |
|
468 |
|||
469 |
121 |
return (newopts); |
|
470 |
} |
||
471 |
|||
472 |
static void |
||
473 |
usage(void) |
||
474 |
{ |
||
475 |
(void)fprintf(stderr, |
||
476 |
"usage: %s [-AaceHhjkLlmrSTuvwx] [-M core] [-N system] [-O fmt] [-o fmt] [-p pid]\n", |
||
477 |
__progname); |
||
478 |
(void)fprintf(stderr, |
||
479 |
"%-*s[-t tty] [-U username] [-W swap]\n", (int)strlen(__progname) + 8, ""); |
||
480 |
exit(1); |
||
481 |
} |
Generated by: GCOVR (Version 3.3) |