Commit | Line | Data |
---|---|---|
813ead68 MT |
1 | /*- |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
3378c3d2 MT |
3 | * All rights reserved. |
4 | * | |
813ead68 | 5 | * %sccs.include.redist.c% |
761330fe DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
9 | char copyright[] = | |
813ead68 | 10 | "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ |
761330fe | 11 | All rights reserved.\n"; |
3378c3d2 | 12 | #endif /* not lint */ |
761330fe | 13 | |
3d9f6a35 | 14 | #ifndef lint |
cc8c7cdb | 15 | static char sccsid[] = "@(#)ps.c 5.51 (Berkeley) %G%"; |
3378c3d2 | 16 | #endif /* not lint */ |
813ead68 | 17 | |
aafc2e2f | 18 | #include <sys/param.h> |
aafc2e2f | 19 | #include <sys/user.h> |
fd57c467 KB |
20 | #include <sys/time.h> |
21 | #include <sys/resource.h> | |
aafc2e2f | 22 | #include <sys/proc.h> |
aafc2e2f | 23 | #include <sys/stat.h> |
fd57c467 | 24 | #include <sys/ioctl.h> |
6be662be | 25 | #include <sys/sysctl.h> |
cc8c7cdb KB |
26 | |
27 | #include <ctype.h> | |
28 | #include <err.h> | |
e8807835 | 29 | #include <errno.h> |
cc8c7cdb KB |
30 | #include <fcntl.h> |
31 | #include <kvm.h> | |
32 | #include <nlist.h> | |
33 | #include <paths.h> | |
a5ae2576 | 34 | #include <stdio.h> |
b5bb6e20 MT |
35 | #include <stdlib.h> |
36 | #include <string.h> | |
cc8c7cdb KB |
37 | #include <unistd.h> |
38 | ||
fd57c467 | 39 | #include "ps.h" |
3378c3d2 | 40 | |
1d2a7f51 MK |
41 | #ifdef SPPWAIT |
42 | #define NEWVM | |
43 | #endif | |
44 | ||
fd57c467 | 45 | KINFO *kinfo; |
b595f31e | 46 | struct varent *vhead, *vtail; |
d03cc310 | 47 | |
fd57c467 KB |
48 | int eval; /* exit value */ |
49 | int rawcpu; /* -C */ | |
50 | int sumrusage; /* -S */ | |
51 | int termwidth; /* width of screen (0 == infinity) */ | |
52 | int totwidth; /* calculated width of requested variables */ | |
3378c3d2 | 53 | |
967726ab | 54 | static int needuser, needcomm, needenv; |
3378c3d2 | 55 | |
0f5eb034 | 56 | enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; |
3378c3d2 | 57 | |
8faab6ff KB |
58 | static char *fmt __P((char **(*)(kvm_t *, const struct kinfo_proc *, int), |
59 | KINFO *, char *, int)); | |
60 | static char *kludge_oldps_options __P((char *)); | |
61 | static int pscomp __P((const void *, const void *)); | |
62 | static void saveuser __P((KINFO *)); | |
63 | static void scanvars __P((void)); | |
64 | static void usage __P((void)); | |
3378c3d2 | 65 | |
5bd2e803 KB |
66 | char dfmt[] = "pid tt state time command"; |
67 | char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; | |
68 | char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; | |
69 | char o1[] = "pid"; | |
70 | char o2[] = "tt state time command"; | |
71 | char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; | |
f9855ed1 | 72 | char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; |
066ec2ef | 73 | |
967726ab KM |
74 | kvm_t *kd; |
75 | ||
8faab6ff | 76 | int |
7a1cd4ac MT |
77 | main(argc, argv) |
78 | int argc; | |
8faab6ff | 79 | char *argv[]; |
aafc2e2f | 80 | { |
967726ab | 81 | register struct kinfo_proc *kp; |
b595f31e | 82 | register struct varent *vent; |
967726ab | 83 | int nentries; |
fd57c467 | 84 | register int i; |
3378c3d2 | 85 | struct winsize ws; |
fd57c467 | 86 | dev_t ttydev; |
8faab6ff KB |
87 | int all, ch, flag, fmt, lineno, pid, prtheader, uid, wflag, what, xflg; |
88 | char *nlistf, *memf, *swapf, errbuf[256]; | |
3378c3d2 | 89 | |
fd57c467 KB |
90 | if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && |
91 | ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && | |
92 | ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || | |
3378c3d2 MT |
93 | ws.ws_col == 0) |
94 | termwidth = 79; | |
417dadf5 | 95 | else |
3378c3d2 | 96 | termwidth = ws.ws_col - 1; |
fd57c467 | 97 | |
3378c3d2 MT |
98 | if (argc > 1) |
99 | argv[1] = kludge_oldps_options(argv[1]); | |
100 | ||
cc8c7cdb | 101 | all = fmt = prtheader = wflag = xflg = 0; |
fd57c467 KB |
102 | pid = uid = -1; |
103 | ttydev = NODEV; | |
783b6016 KB |
104 | memf = nlistf = swapf = NULL; |
105 | while ((ch = getopt(argc, argv, | |
967726ab | 106 | "aCeghjLlM:mN:O:o:p:rSTt:uvW:wx")) != EOF) |
3378c3d2 | 107 | switch((char)ch) { |
fd57c467 KB |
108 | case 'a': |
109 | all = 1; | |
0f0e0052 | 110 | break; |
cc8c7cdb | 111 | case 'e': /* XXX set ufmt */ |
967726ab KM |
112 | needenv = 1; |
113 | break; | |
fd57c467 KB |
114 | case 'C': |
115 | rawcpu = 1; | |
1fb6a666 | 116 | break; |
fd57c467 | 117 | case 'g': |
cc8c7cdb | 118 | break; /* no-op */ |
fd57c467 KB |
119 | case 'h': |
120 | prtheader = ws.ws_row > 5 ? ws.ws_row : 22; | |
121 | break; | |
122 | case 'j': | |
5bd2e803 | 123 | parsefmt(jfmt); |
fd57c467 | 124 | fmt = 1; |
51851ab8 | 125 | jfmt[0] = '\0'; |
aafc2e2f | 126 | break; |
967726ab | 127 | case 'L': |
fd57c467 KB |
128 | showkey(); |
129 | exit(0); | |
3378c3d2 | 130 | case 'l': |
5bd2e803 | 131 | parsefmt(lfmt); |
fd57c467 | 132 | fmt = 1; |
51851ab8 | 133 | lfmt[0] = '\0'; |
aafc2e2f | 134 | break; |
783b6016 KB |
135 | case 'M': |
136 | memf = optarg; | |
137 | break; | |
fd57c467 | 138 | case 'm': |
3378c3d2 | 139 | sortby = SORTMEM; |
aafc2e2f | 140 | break; |
783b6016 KB |
141 | case 'N': |
142 | nlistf = optarg; | |
143 | break; | |
fd57c467 | 144 | case 'O': |
5bd2e803 | 145 | parsefmt(o1); |
fd57c467 | 146 | parsefmt(optarg); |
5bd2e803 | 147 | parsefmt(o2); |
51851ab8 | 148 | o1[0] = o2[0] = '\0'; |
fd57c467 KB |
149 | fmt = 1; |
150 | break; | |
151 | case 'o': | |
152 | parsefmt(optarg); | |
153 | fmt = 1; | |
154 | break; | |
155 | case 'p': | |
156 | pid = atoi(optarg); | |
157 | xflg = 1; | |
158 | break; | |
159 | case 'r': | |
3378c3d2 | 160 | sortby = SORTCPU; |
aafc2e2f | 161 | break; |
fd57c467 KB |
162 | case 'S': |
163 | sumrusage = 1; | |
dcbf8036 | 164 | break; |
3378c3d2 | 165 | case 'T': |
fd57c467 | 166 | if ((optarg = ttyname(STDIN_FILENO)) == NULL) |
cc8c7cdb | 167 | errx(1, "stdin: not a terminal"); |
b5bb6e20 | 168 | /* FALLTHROUGH */ |
3378c3d2 | 169 | case 't': { |
8faab6ff KB |
170 | struct stat sb; |
171 | char *ttypath, pathbuf[MAXPATHLEN]; | |
b5bb6e20 MT |
172 | |
173 | if (strcmp(optarg, "co") == 0) | |
174 | ttypath = _PATH_CONSOLE; | |
175 | else if (*optarg != '/') | |
8faab6ff KB |
176 | (void)snprintf(ttypath = pathbuf, |
177 | sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); | |
b5bb6e20 MT |
178 | else |
179 | ttypath = optarg; | |
8faab6ff | 180 | if (stat(ttypath, &sb) == -1) |
cc8c7cdb | 181 | err(1, "%s", ttypath); |
8faab6ff | 182 | if (!S_ISCHR(sb.st_mode)) |
cc8c7cdb | 183 | errx(1, "%s: not a terminal", ttypath); |
8faab6ff | 184 | ttydev = sb.st_rdev; |
aafc2e2f | 185 | break; |
3378c3d2 | 186 | } |
fd57c467 | 187 | case 'u': |
5bd2e803 | 188 | parsefmt(ufmt); |
fd57c467 KB |
189 | sortby = SORTCPU; |
190 | fmt = 1; | |
51851ab8 | 191 | ufmt[0] = '\0'; |
aafc2e2f | 192 | break; |
fd57c467 | 193 | case 'v': |
5bd2e803 | 194 | parsefmt(vfmt); |
3378c3d2 | 195 | sortby = SORTMEM; |
fd57c467 | 196 | fmt = 1; |
51851ab8 | 197 | vfmt[0] = '\0'; |
aafc2e2f | 198 | break; |
783b6016 KB |
199 | case 'W': |
200 | swapf = optarg; | |
201 | break; | |
fd57c467 | 202 | case 'w': |
2126084b | 203 | if (wflag) |
fd57c467 | 204 | termwidth = UNLIMITED; |
2126084b MT |
205 | else if (termwidth < 131) |
206 | termwidth = 131; | |
207 | wflag++; | |
aafc2e2f | 208 | break; |
fd57c467 KB |
209 | case 'x': |
210 | xflg = 1; | |
aafc2e2f | 211 | break; |
3378c3d2 | 212 | case '?': |
aafc2e2f | 213 | default: |
fd57c467 | 214 | usage(); |
25659ede | 215 | } |
3378c3d2 MT |
216 | argc -= optind; |
217 | argv += optind; | |
b5bb6e20 | 218 | |
783b6016 KB |
219 | #define BACKWARD_COMPATIBILITY |
220 | #ifdef BACKWARD_COMPATIBILITY | |
3378c3d2 | 221 | if (*argv) { |
783b6016 KB |
222 | nlistf = *argv; |
223 | if (*++argv) { | |
224 | memf = *argv; | |
225 | if (*++argv) | |
226 | swapf = *argv; | |
aafc2e2f BJ |
227 | } |
228 | } | |
783b6016 | 229 | #endif |
ad07e3a9 KB |
230 | /* |
231 | * Discard setgid privileges if not the running kernel so that bad | |
232 | * guys can't print interesting stuff from kernel memory. | |
233 | */ | |
234 | if (nlistf != NULL || memf != NULL || swapf != NULL) | |
235 | setgid(getgid()); | |
236 | ||
967726ab KM |
237 | kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); |
238 | if (kd == 0) | |
cc8c7cdb | 239 | errx(1, "%s", errbuf); |
3378c3d2 MT |
240 | |
241 | if (!fmt) | |
5bd2e803 | 242 | parsefmt(dfmt); |
3378c3d2 MT |
243 | |
244 | if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */ | |
245 | uid = getuid(); | |
246 | ||
247 | /* | |
248 | * scan requested variables, noting what structures are needed, | |
249 | * and adjusting header widths as appropiate. | |
250 | */ | |
251 | scanvars(); | |
3378c3d2 MT |
252 | /* |
253 | * get proc list | |
254 | */ | |
255 | if (uid != -1) { | |
6be662be | 256 | what = KERN_PROC_UID; |
3378c3d2 MT |
257 | flag = uid; |
258 | } else if (ttydev != NODEV) { | |
6be662be | 259 | what = KERN_PROC_TTY; |
3378c3d2 MT |
260 | flag = ttydev; |
261 | } else if (pid != -1) { | |
6be662be | 262 | what = KERN_PROC_PID; |
3378c3d2 | 263 | flag = pid; |
3378c3d2 MT |
264 | /* |
265 | * select procs | |
266 | */ | |
967726ab | 267 | if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0) |
cc8c7cdb KB |
268 | errx(1, "%s", kvm_geterr(kd)); |
269 | if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) | |
270 | err(1, NULL); | |
967726ab KM |
271 | for (i = nentries; --i >= 0; ++kp) { |
272 | kinfo[i].ki_p = kp; | |
3378c3d2 | 273 | if (needuser) |
967726ab | 274 | saveuser(&kinfo[i]); |
3378c3d2 | 275 | } |
3378c3d2 MT |
276 | /* |
277 | * print header | |
278 | */ | |
279 | printheader(); | |
280 | if (nentries == 0) | |
281 | exit(0); | |
282 | /* | |
283 | * sort proc list | |
284 | */ | |
8faab6ff | 285 | qsort(kinfo, nentries, sizeof(KINFO), pscomp); |
3378c3d2 MT |
286 | /* |
287 | * for each proc, call each variable output function. | |
288 | */ | |
fd57c467 | 289 | for (i = lineno = 0; i < nentries; i++) { |
967726ab KM |
290 | if (xflg == 0 && (KI_EPROC(&kinfo[i])->e_tdev == NODEV || |
291 | (KI_PROC(&kinfo[i])->p_flag & SCTTY ) == 0)) | |
3378c3d2 | 292 | continue; |
b595f31e | 293 | for (vent = vhead; vent; vent = vent->next) { |
8faab6ff | 294 | (vent->var->oproc)(&kinfo[i], vent); |
b595f31e | 295 | if (vent->next != NULL) |
8faab6ff | 296 | (void)putchar(' '); |
3378c3d2 | 297 | } |
8faab6ff | 298 | (void)putchar('\n'); |
cc8c7cdb | 299 | if (prtheader && lineno++ == prtheader - 4) { |
8faab6ff | 300 | (void)putchar('\n'); |
3378c3d2 MT |
301 | printheader(); |
302 | lineno = 0; | |
303 | } | |
aafc2e2f | 304 | } |
fd57c467 | 305 | exit(eval); |
bdb1f95f BJ |
306 | } |
307 | ||
8faab6ff | 308 | static void |
3378c3d2 | 309 | scanvars() |
6e515893 | 310 | { |
b595f31e | 311 | register struct varent *vent; |
fd57c467 KB |
312 | register VAR *v; |
313 | register int i; | |
3378c3d2 | 314 | |
b595f31e MT |
315 | for (vent = vhead; vent; vent = vent->next) { |
316 | v = vent->var; | |
3378c3d2 MT |
317 | i = strlen(v->header); |
318 | if (v->width < i) | |
319 | v->width = i; | |
320 | totwidth += v->width + 1; /* +1 for space */ | |
321 | if (v->flag & USER) | |
322 | needuser = 1; | |
323 | if (v->flag & COMM) | |
324 | needcomm = 1; | |
e8807835 | 325 | } |
3378c3d2 | 326 | totwidth--; |
6e515893 | 327 | } |
b5bb6e20 | 328 | |
967726ab KM |
329 | static char * |
330 | fmt(fn, ki, comm, maxlen) | |
331 | char **(*fn) __P((kvm_t *, const struct kinfo_proc *, int)); | |
fd57c467 | 332 | KINFO *ki; |
967726ab KM |
333 | char *comm; |
334 | int maxlen; | |
aafc2e2f | 335 | { |
967726ab | 336 | register char *s; |
b5bb6e20 | 337 | |
cc8c7cdb KB |
338 | if ((s = |
339 | fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen)) == NULL) | |
340 | err(1, NULL); | |
967726ab KM |
341 | return (s); |
342 | } | |
343 | ||
8faab6ff | 344 | static void |
967726ab KM |
345 | saveuser(ki) |
346 | KINFO *ki; | |
347 | { | |
348 | register struct usave *usp = &ki->ki_u; | |
349 | struct pstats pstats; | |
350 | extern char *fmt_argv(); | |
351 | ||
352 | if (kvm_read(kd, (u_long)&KI_PROC(ki)->p_addr->u_stats, | |
353 | (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) { | |
3378c3d2 | 354 | /* |
967726ab KM |
355 | * The u-area might be swapped out, and we can't get |
356 | * at it because we have a crashdump and no swap. | |
357 | * If it's here fill in these fields, otherwise, just | |
358 | * leave them 0. | |
3378c3d2 | 359 | */ |
967726ab KM |
360 | usp->u_start = pstats.p_start; |
361 | usp->u_ru = pstats.p_ru; | |
362 | usp->u_cru = pstats.p_cru; | |
363 | usp->u_valid = 1; | |
aa2c7663 | 364 | } else |
967726ab KM |
365 | usp->u_valid = 0; |
366 | /* | |
367 | * save arguments if needed | |
368 | */ | |
369 | if (needcomm) | |
370 | ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm, | |
371 | MAXCOMLEN); | |
372 | else | |
373 | ki->ki_args = NULL; | |
374 | if (needenv) | |
375 | ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0); | |
376 | else | |
377 | ki->ki_env = NULL; | |
aafc2e2f BJ |
378 | } |
379 | ||
8faab6ff KB |
380 | static int |
381 | pscomp(a, b) | |
382 | const void *a, *b; | |
aafc2e2f | 383 | { |
3378c3d2 | 384 | int i; |
1d2a7f51 | 385 | #ifdef NEWVM |
967726ab KM |
386 | #define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \ |
387 | KI_EPROC(k)->e_vm.vm_tsize) | |
1d2a7f51 | 388 | #else |
3378c3d2 | 389 | #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize) |
1d2a7f51 | 390 | #endif |
aafc2e2f | 391 | |
3378c3d2 | 392 | if (sortby == SORTCPU) |
8faab6ff | 393 | return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a)); |
3378c3d2 | 394 | if (sortby == SORTMEM) |
8faab6ff KB |
395 | return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a)); |
396 | i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev; | |
aafc2e2f | 397 | if (i == 0) |
8faab6ff | 398 | i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid; |
aafc2e2f BJ |
399 | return (i); |
400 | } | |
401 | ||
3180e1ce | 402 | /* |
3378c3d2 MT |
403 | * ICK (all for getopt), would rather hide the ugliness |
404 | * here than taint the main code. | |
405 | * | |
406 | * ps foo -> ps -foo | |
407 | * ps 34 -> ps -p34 | |
408 | * | |
409 | * The old convention that 't' with no trailing tty arg means the users | |
410 | * tty, is only supported if argv[1] doesn't begin with a '-'. This same | |
411 | * feature is available with the option 'T', which takes no argument. | |
3180e1ce | 412 | */ |
8faab6ff | 413 | static char * |
3378c3d2 MT |
414 | kludge_oldps_options(s) |
415 | char *s; | |
3180e1ce | 416 | { |
fd57c467 | 417 | size_t len; |
3378c3d2 MT |
418 | char *newopts, *ns, *cp; |
419 | ||
fd57c467 | 420 | len = strlen(s); |
9ed1608e | 421 | if ((newopts = ns = malloc(len + 2)) == NULL) |
cc8c7cdb | 422 | err(1, NULL); |
3378c3d2 MT |
423 | /* |
424 | * options begin with '-' | |
425 | */ | |
426 | if (*s != '-') | |
427 | *ns++ = '-'; /* add option flag */ | |
428 | /* | |
429 | * gaze to end of argv[1] | |
430 | */ | |
431 | cp = s + len - 1; | |
432 | /* | |
433 | * if last letter is a 't' flag with no argument (in the context | |
434 | * of the oldps options -- option string NOT starting with a '-' -- | |
b5bb6e20 | 435 | * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). |
3378c3d2 MT |
436 | */ |
437 | if (*cp == 't' && *s != '-') | |
438 | *cp = 'T'; | |
439 | else { | |
440 | /* | |
441 | * otherwise check for trailing number, which *may* be a | |
442 | * pid. | |
443 | */ | |
b5bb6e20 | 444 | while (cp >= s && isdigit(*cp)) |
3378c3d2 | 445 | --cp; |
3180e1ce | 446 | } |
3378c3d2 | 447 | cp++; |
cc8c7cdb | 448 | memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ |
b5bb6e20 | 449 | ns += cp - s; |
3378c3d2 MT |
450 | /* |
451 | * if there's a trailing number, and not a preceding 'p' (pid) or | |
452 | * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. | |
453 | */ | |
b5bb6e20 MT |
454 | if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' && |
455 | (cp - 1 == s || cp[-2] != 't'))) | |
3378c3d2 | 456 | *ns++ = 'p'; |
8faab6ff | 457 | (void)strcpy(ns, cp); /* and append the number */ |
3180e1ce | 458 | |
3378c3d2 | 459 | return (newopts); |
3180e1ce | 460 | } |
fd57c467 | 461 | |
8faab6ff | 462 | static void |
fd57c467 KB |
463 | usage() |
464 | { | |
8faab6ff | 465 | (void)fprintf(stderr, |
9ed1608e | 466 | "usage: ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty]\n\t [-M core] [-N system] [-W swap]\n ps [-L]\n"); |
fd57c467 KB |
467 | exit(1); |
468 | } |