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