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