1 /** $MirOS: src/bin/ps/print.c,v 1.2 2005/10/21 11:02:37 tg Exp $ */
2 /* $OpenBSD: print.c,v 1.38 2005/07/06 21:41:24 millert Exp $ */
3 /* $NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $ */
4
5 /*-
6 * Copyright (c) 1990, 1993, 1994
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
37 #else
38 static char rcsid[] = "$OpenBSD: print.c,v 1.38 2005/07/06 21:41:24 millert Exp $";
39 #endif
40 #endif /* not lint */
41
42 #include <sys/param.h>
43 #include <sys/time.h>
44 #include <sys/resource.h>
45 #include <sys/proc.h>
46 #include <sys/stat.h>
47
48 #include <sys/ucred.h>
49 #include <sys/sysctl.h>
50 #include <uvm/uvm_extern.h>
51
52 #include <err.h>
53 #include <grp.h>
54 #include <kvm.h>
55 #include <math.h>
56 #include <nlist.h>
57 #include <stddef.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <tzfile.h>
62 #include <unistd.h>
63 #include <pwd.h>
64
65 #include "ps.h"
66
67 extern kvm_t *kd;
68 extern int needenv, needcomm, commandonly;
69
70 static char *cmdpart(char *);
71
72 #define min(a,b) ((a) < (b) ? (a) : (b))
73
74 static char *
cmdpart(char * arg0)75 cmdpart(char *arg0)
76 {
77 char *cp;
78
79 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
80 }
81
82 void
printheader(void)83 printheader(void)
84 {
85 VAR *v;
86 struct varent *vent;
87
88 for (vent = vhead; vent; vent = vent->next) {
89 v = vent->var;
90 if (v->flag & LJUST) {
91 if (vent->next == NULL) /* last one */
92 (void)printf("%s", v->header);
93 else
94 (void)printf("%-*s", v->width, v->header);
95 } else
96 (void)printf("%*s", v->width, v->header);
97 if (vent->next != NULL)
98 (void)putchar(' ');
99 }
100 (void)putchar('\n');
101 }
102
103 void
command(const struct kinfo_proc2 * kp,VARENT * ve)104 command(const struct kinfo_proc2 *kp, VARENT *ve)
105 {
106 VAR *v;
107 int left;
108 char **argv, **p;
109
110 v = ve->var;
111 if (ve->next != NULL || termwidth != UNLIMITED) {
112 if (ve->next == NULL) {
113 left = termwidth - (totwidth - v->width);
114 if (left < 1) /* already wrapped, just use std width */
115 left = v->width;
116 } else
117 left = v->width;
118 } else
119 left = -1;
120 if (needenv && kd != NULL) {
121 argv = kvm_getenvv2(kd, kp, termwidth);
122 if ((p = argv) != NULL) {
123 while (*p) {
124 if (p != argv)
125 fmt_putc(' ', &left);
126 fmt_puts(*p, &left);
127 p++;
128 }
129 }
130 } else
131 argv = NULL;
132 if (needcomm) {
133 if (!commandonly) {
134 if (kd != NULL) {
135 argv = kvm_getargv2(kd, kp, termwidth);
136 if ((p = argv) != NULL) {
137 while (*p) {
138 if (p != argv)
139 fmt_putc(' ', &left);
140 fmt_puts(*p, &left);
141 p++;
142 }
143 }
144 }
145 if (argv == NULL || argv[0] == '\0' ||
146 strcmp(cmdpart(argv[0]), kp->p_comm)) {
147 if (argv != NULL && argv[0] != '\0')
148 fmt_putc(' ', &left);
149 fmt_putc('(', &left);
150 fmt_puts(kp->p_comm, &left);
151 fmt_putc(')', &left);
152 }
153 } else {
154 fmt_puts(kp->p_comm, &left);
155 }
156 }
157 if (ve->next && left > 0)
158 printf("%*s", left, "");
159 }
160
161 void
ucomm(const struct kinfo_proc2 * kp,VARENT * ve)162 ucomm(const struct kinfo_proc2 *kp, VARENT *ve)
163 {
164 VAR *v;
165
166 v = ve->var;
167 (void)printf("%-*s", v->width, kp->p_comm);
168 }
169
170 void
logname(const struct kinfo_proc2 * kp,VARENT * ve)171 logname(const struct kinfo_proc2 *kp, VARENT *ve)
172 {
173 VAR *v;
174
175 v = ve->var;
176 if (kp->p_login[0]) {
177 int n = min(v->width, MAXLOGNAME);
178 (void)printf("%-*.*s", n, n, kp->p_login);
179 if (v->width > n)
180 (void)printf("%*s", v->width - n, "");
181 } else
182 (void)printf("%-*s", v->width, "-");
183 }
184
185 #define pgtok(a) (((a)*getpagesize())/1024)
186
187 void
state(const struct kinfo_proc2 * kp,VARENT * ve)188 state(const struct kinfo_proc2 *kp, VARENT *ve)
189 {
190 extern int ncpu;
191 int flag;
192 char *cp, state = '\0';
193 VAR *v;
194 char buf[16];
195
196 v = ve->var;
197 flag = kp->p_flag;
198 cp = buf;
199
200 switch (kp->p_stat) {
201
202 case SSTOP:
203 *cp = 'T';
204 break;
205
206 case SSLEEP:
207 if (flag & P_SINTR) /* interruptible (long) */
208 *cp = kp->p_slptime >= maxslp ? 'I' : 'S';
209 else
210 *cp = 'D';
211 break;
212
213 case SRUN:
214 case SIDL:
215 #ifdef SONPROC
216 case SONPROC:
217 #endif
218 state = *cp = 'R';
219 break;
220
221 case SZOMB:
222 *cp = 'Z';
223 break;
224
225 default:
226 *cp = '?';
227 }
228 cp++;
229
230 if (flag & P_INMEM) {
231 } else
232 *cp++ = 'W';
233 if (kp->p_nice < NZERO)
234 *cp++ = '<';
235 else if (kp->p_nice > NZERO)
236 *cp++ = 'N';
237 if (flag & P_TRACED)
238 *cp++ = 'X';
239 if (flag & P_SYSTRACE)
240 *cp++ = 'x';
241 if (flag & P_WEXIT && kp->p_stat != SZOMB)
242 *cp++ = 'E';
243 if (flag & P_PPWAIT)
244 *cp++ = 'V';
245 if (flag & P_SYSTEM)
246 *cp++ = 'K';
247 /* XXX Since P_SYSTEM now shows a K, should L just be for holdcnt? */
248 if ((flag & P_SYSTEM) || kp->p_holdcnt)
249 *cp++ = 'L';
250 if ((flag & P_SYSTEM) == 0 &&
251 kp->p_rlim_rss_cur / 1024 < pgtok(kp->p_vm_rssize))
252 *cp++ = '>';
253 if (kp->p_eflag & EPROC_SLEADER)
254 *cp++ = 's';
255 if ((flag & P_CONTROLT) && kp->p__pgid == kp->p_tpgid)
256 *cp++ = '+';
257 *cp = '\0';
258
259 #if 0
260 if (state == 'R' && ncpu && kp->p_cpuid != KI_NOCPU) {
261 char pbuf[16];
262
263 snprintf(pbuf, sizeof pbuf, "/%d", kp->p_cpuid);
264 *++cp = '\0';
265 strlcat(buf, pbuf, sizeof buf);
266 cp = buf + strlen(buf);
267 }
268 #endif
269
270 (void)printf("%-*s", v->width, buf);
271 }
272
273 void
pri(const struct kinfo_proc2 * kp,VARENT * ve)274 pri(const struct kinfo_proc2 *kp, VARENT *ve)
275 {
276 VAR *v;
277
278 v = ve->var;
279 (void)printf("%*d", v->width, kp->p_priority - PZERO);
280 }
281
282 void
euname(const struct kinfo_proc2 * kp,VARENT * ve)283 euname(const struct kinfo_proc2 *kp, VARENT *ve)
284 {
285 VAR *v;
286
287 v = ve->var;
288 (void)printf("%-*s",
289 (int)v->width, user_from_uid(kp->p_uid, 0));
290 }
291
292 void
runame(const struct kinfo_proc2 * kp,VARENT * ve)293 runame(const struct kinfo_proc2 *kp, VARENT *ve)
294 {
295 VAR *v;
296
297 v = ve->var;
298 (void)printf("%-*s",
299 (int)v->width, user_from_uid(kp->p_ruid, 0));
300 }
301
302 void
gname(const struct kinfo_proc2 * kp,VARENT * ve)303 gname(const struct kinfo_proc2 *kp, VARENT *ve)
304 {
305 VAR *v;
306
307 v = ve->var;
308 (void)printf("%-*s",
309 (int)v->width, group_from_gid(kp->p_gid, 0));
310 }
311
312 void
rgname(const struct kinfo_proc2 * kp,VARENT * ve)313 rgname(const struct kinfo_proc2 *kp, VARENT *ve)
314 {
315 VAR *v;
316
317 v = ve->var;
318 (void)printf("%-*s",
319 (int)v->width, group_from_gid(kp->p_rgid, 0));
320 }
321
322 void
tdev(const struct kinfo_proc2 * kp,VARENT * ve)323 tdev(const struct kinfo_proc2 *kp, VARENT *ve)
324 {
325 VAR *v;
326 dev_t dev;
327 char buff[16];
328
329 v = ve->var;
330 dev = kp->p_tdev;
331 if (dev == NODEV)
332 (void)printf("%*s", v->width, "??");
333 else {
334 (void)snprintf(buff, sizeof(buff),
335 "%d/%d", major(dev), minor(dev));
336 (void)printf("%*s", v->width, buff);
337 }
338 }
339
340 void
tname(const struct kinfo_proc2 * kp,VARENT * ve)341 tname(const struct kinfo_proc2 *kp, VARENT *ve)
342 {
343 VAR *v;
344 dev_t dev;
345 char *ttname;
346
347 v = ve->var;
348 dev = kp->p_tdev;
349 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
350 (void)printf("%-*s", v->width, "??");
351 else {
352 if (strncmp(ttname, "tty", 3) == 0)
353 ttname += 3;
354 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
355 kp->p_eflag & EPROC_CTTY ? ' ' : '-');
356 }
357 }
358
359 void
longtname(const struct kinfo_proc2 * kp,VARENT * ve)360 longtname(const struct kinfo_proc2 *kp, VARENT *ve)
361 {
362 VAR *v;
363 dev_t dev;
364 char *ttname;
365
366 v = ve->var;
367 dev = kp->p_tdev;
368 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
369 (void)printf("%-*s", v->width, "??");
370 else
371 (void)printf("%-*s", v->width, ttname);
372 }
373
374 void
started(const struct kinfo_proc2 * kp,VARENT * ve)375 started(const struct kinfo_proc2 *kp, VARENT *ve)
376 {
377 VAR *v;
378 static time_t now;
379 time_t startt;
380 struct tm *tp;
381 char buf[100];
382
383 v = ve->var;
384 if (!kp->p_uvalid) {
385 (void)printf("%-*s", v->width, "-");
386 return;
387 }
388
389 startt = kp->p_ustart_sec;
390 tp = localtime(&startt);
391 if (!now)
392 (void)time(&now);
393 if (now - kp->p_ustart_sec < 24 * SECSPERHOUR) {
394 (void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp);
395 } else if (now - kp->p_ustart_sec < 7 * SECSPERDAY) {
396 (void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp);
397 } else
398 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
399 (void)printf("%-*s", v->width, buf);
400 }
401
402 void
lstarted(const struct kinfo_proc2 * kp,VARENT * ve)403 lstarted(const struct kinfo_proc2 *kp, VARENT *ve)
404 {
405 VAR *v;
406 time_t startt;
407 char buf[100];
408
409 v = ve->var;
410 if (!kp->p_uvalid) {
411 (void)printf("%-*s", v->width, "-");
412 return;
413 }
414 startt = kp->p_ustart_sec;
415 (void)strftime(buf, sizeof(buf) -1, "%c",
416 localtime(&startt));
417 (void)printf("%-*s", v->width, buf);
418 }
419
420 void
wchan(const struct kinfo_proc2 * kp,VARENT * ve)421 wchan(const struct kinfo_proc2 *kp, VARENT *ve)
422 {
423 VAR *v;
424
425 v = ve->var;
426 if (kp->p_wchan) {
427 int n;
428
429 if (kp->p_wmesg) {
430 n = min(v->width, WMESGLEN);
431 (void)printf("%-*.*s", n, n, kp->p_wmesg);
432 if (v->width > n)
433 (void)printf("%*s", v->width - n, "");
434 } else
435 (void)printf("%-*lx", v->width,
436 (long)kp->p_wchan &~ KERNBASE);
437 } else
438 (void)printf("%-*s", v->width, "-");
439 }
440
441 void
vsize(const struct kinfo_proc2 * kp,VARENT * ve)442 vsize(const struct kinfo_proc2 *kp, VARENT *ve)
443 {
444 VAR *v;
445
446 v = ve->var;
447 (void)printf("%*d", v->width,
448 pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize));
449 }
450
451 void
rssize(const struct kinfo_proc2 * kp,VARENT * ve)452 rssize(const struct kinfo_proc2 *kp, VARENT *ve)
453 {
454 VAR *v;
455
456 v = ve->var;
457 /* XXX don't have info about shared */
458 (void)printf("%*d", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
459 pgtok(kp->p_vm_rssize));
460 }
461
462 void
p_rssize(const struct kinfo_proc2 * kp,VARENT * ve)463 p_rssize(const struct kinfo_proc2 *kp, VARENT *ve)
464 {
465 VAR *v;
466
467 v = ve->var;
468 (void)printf("%*d", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
469 pgtok(kp->p_vm_rssize));
470 }
471
472 void
cputime(const struct kinfo_proc2 * kp,VARENT * ve)473 cputime(const struct kinfo_proc2 *kp, VARENT *ve)
474 {
475 VAR *v;
476 long secs;
477 long psecs; /* "parts" of a second. first micro, then centi */
478 char obuff[128];
479
480 v = ve->var;
481 if (kp->p_stat == SZOMB || !kp->p_uvalid) {
482 secs = 0;
483 psecs = 0;
484 } else {
485 /*
486 * This counts time spent handling interrupts. We could
487 * fix this, but it is not 100% trivial (and interrupt
488 * time fractions only work on the sparc anyway). XXX
489 */
490 secs = kp->p_rtime_sec;
491 psecs = kp->p_rtime_usec;
492 if (sumrusage) {
493 secs += kp->p_uctime_sec;
494 psecs += kp->p_uctime_usec;
495 }
496 /*
497 * round and scale to 100's
498 */
499 psecs = (psecs + 5000) / 10000;
500 secs += psecs / 100;
501 psecs = psecs % 100;
502 }
503 (void)snprintf(obuff, sizeof(obuff),
504 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
505 (void)printf("%*s", v->width, obuff);
506 }
507
508 double
getpcpu(const struct kinfo_proc2 * kp)509 getpcpu(const struct kinfo_proc2 *kp)
510 {
511 static int failure;
512 double d;
513
514 if (!nlistread)
515 failure = donlist();
516 if (failure)
517 return (0.0);
518
519 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
520
521 /* XXX - I don't like this */
522 if (kp->p_swtime == 0 || (kp->p_flag & P_INMEM) == 0)
523 return (0.0);
524 if (rawcpu)
525 return (100.0 * fxtofl(kp->p_pctcpu));
526
527 d = kp->p_swtime * log(fxtofl(ccpu));
528 if (d < -700.0)
529 d = 0.0; /* avoid IEEE underflow */
530 else
531 d = exp(d);
532 if (d == 1.0)
533 return (0.0);
534 return (100.0 * fxtofl(kp->p_pctcpu) /
535 (1.0 - d));
536 }
537
538 void
pcpu(const struct kinfo_proc2 * kp,VARENT * ve)539 pcpu(const struct kinfo_proc2 *kp, VARENT *ve)
540 {
541 VAR *v;
542
543 v = ve->var;
544 (void)printf("%*.1f", v->width, getpcpu(kp));
545 }
546
547 double
getpmem(const struct kinfo_proc2 * kp)548 getpmem(const struct kinfo_proc2 *kp)
549 {
550 static int failure;
551 double fracmem;
552 int szptudot;
553
554 if (!nlistread)
555 failure = donlist();
556 if (failure)
557 return (0.0);
558
559 if ((kp->p_flag & P_INMEM) == 0 || (kp->p_flag & P_SYSTEM))
560 return (0.0);
561 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
562 szptudot = USPACE/getpagesize();
563 /* XXX don't have info about shared */
564 fracmem = ((float)kp->p_vm_rssize + szptudot)/mempages;
565 return (100.0 * fracmem);
566 }
567
568 void
pmem(const struct kinfo_proc2 * kp,VARENT * ve)569 pmem(const struct kinfo_proc2 *kp, VARENT *ve)
570 {
571 VAR *v;
572
573 v = ve->var;
574 (void)printf("%*.1f", v->width, getpmem(kp));
575 }
576
577 void
pagein(const struct kinfo_proc2 * kp,VARENT * ve)578 pagein(const struct kinfo_proc2 *kp, VARENT *ve)
579 {
580 VAR *v;
581
582 v = ve->var;
583 (void)printf("%*llu", v->width,
584 kp->p_uvalid ? kp->p_uru_majflt : 0);
585 }
586
587 void
maxrss(const struct kinfo_proc2 * kp,VARENT * ve)588 maxrss(const struct kinfo_proc2 *kp, VARENT *ve)
589 {
590 VAR *v;
591
592 v = ve->var;
593 (void)printf("%*lld", v->width, kp->p_rlim_rss_cur / 1024);
594 }
595
596 void
tsize(const struct kinfo_proc2 * kp,VARENT * ve)597 tsize(const struct kinfo_proc2 *kp, VARENT *ve)
598 {
599 VAR *v;
600
601 v = ve->var;
602 (void)printf("%*d", v->width, pgtok(kp->p_vm_tsize));
603 }
604
605 void
dsize(const struct kinfo_proc2 * kp,VARENT * ve)606 dsize(const struct kinfo_proc2 *kp, VARENT *ve)
607 {
608 VAR *v;
609
610 v = ve->var;
611 (void)printf("%*d", v->width, pgtok(kp->p_vm_dsize));
612 }
613
614 void
ssize(const struct kinfo_proc2 * kp,VARENT * ve)615 ssize(const struct kinfo_proc2 *kp, VARENT *ve)
616 {
617 VAR *v;
618
619 v = ve->var;
620 (void)printf("%*d", v->width, pgtok(kp->p_vm_ssize));
621 }
622
623 /*
624 * Generic output routines. Print fields from various prototype
625 * structures.
626 */
627 static void
printval(char * bp,VAR * v)628 printval(char *bp, VAR *v)
629 {
630 char ofmt[32];
631
632 snprintf(ofmt, sizeof(ofmt), "%%%s*%s", (v->flag & LJUST) ? "-" : "",
633 v->fmt);
634
635 /*
636 * Note that the "INF127" check is nonsensical for types
637 * that are or can be signed.
638 */
639 #define GET(type) (*(type *)bp)
640 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
641
642 switch (v->type) {
643 case INT8:
644 (void)printf(ofmt, v->width, GET(int8_t));
645 break;
646 case UINT8:
647 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int8_t)));
648 break;
649 case INT16:
650 (void)printf(ofmt, v->width, GET(int16_t));
651 break;
652 case UINT16:
653 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int16_t)));
654 break;
655 case INT32:
656 (void)printf(ofmt, v->width, GET(int32_t));
657 break;
658 case UINT32:
659 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int32_t)));
660 break;
661 case INT64:
662 (void)printf(ofmt, v->width, GET(int64_t));
663 case UINT64:
664 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int64_t)));
665 break;
666 default:
667 errx(1, "unknown type %d", v->type);
668 }
669 #undef GET
670 #undef CHK_INF127
671 }
672
673 void
pvar(const struct kinfo_proc2 * kp,VARENT * ve)674 pvar(const struct kinfo_proc2 *kp, VARENT *ve)
675 {
676 VAR *v;
677
678 v = ve->var;
679 if ((v->flag & USER) && !kp->p_uvalid)
680 (void)printf("%*s", v->width, "-");
681 else
682 printval((char *)kp + v->off, v);
683 }
684
685 void
emulname(const struct kinfo_proc2 * kp,VARENT * ve)686 emulname(const struct kinfo_proc2 *kp, VARENT *ve)
687 {
688 VAR *v;
689
690 v = ve->var;
691
692 (void)printf("%-*s", (int)v->width, kp->p_emul);
693 }
694