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