print.c revision 1.69 1 /* $NetBSD: print.c,v 1.69 2001/08/24 06:37:03 lukem Exp $ */
2
3 /*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Simon Burge.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1990, 1993, 1994
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71
72 #include <sys/cdefs.h>
73 #ifndef lint
74 #if 0
75 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
76 #else
77 __RCSID("$NetBSD: print.c,v 1.69 2001/08/24 06:37:03 lukem Exp $");
78 #endif
79 #endif /* not lint */
80
81 #include <sys/param.h>
82 #include <sys/time.h>
83 #include <sys/resource.h>
84 #include <sys/proc.h>
85 #include <sys/stat.h>
86 #include <sys/ucred.h>
87 #include <sys/sysctl.h>
88
89 #include <err.h>
90 #include <kvm.h>
91 #include <math.h>
92 #include <nlist.h>
93 #include <pwd.h>
94 #include <stddef.h>
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <time.h>
99 #include <tzfile.h>
100 #include <unistd.h>
101
102 #include "ps.h"
103
104 static char *cmdpart __P((char *));
105 static void printval __P((void *, VAR *, int));
106 static int titlecmp __P((char *, char **));
107
108 static void doubleprintorsetwidth __P((VAR *, double, int, int));
109 static void intprintorsetwidth __P((VAR *, int, int));
110 static void strprintorsetwidth __P((VAR *, const char *, int));
111
112 #define min(a,b) ((a) <= (b) ? (a) : (b))
113 #define max(a,b) ((a) >= (b) ? (a) : (b))
114
115 static char *
116 cmdpart(arg0)
117 char *arg0;
118 {
119 char *cp;
120
121 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
122 }
123
124 void
125 printheader()
126 {
127 int len;
128 VAR *v;
129 struct varent *vent;
130 static int firsttime = 1;
131
132 for (vent = vhead; vent; vent = vent->next) {
133 v = vent->var;
134 if (firsttime) {
135 len = strlen(v->header);
136 if (len > v->width)
137 v->width = len;
138 totwidth += v->width + 1; /* +1 for space */
139 }
140 if (v->flag & LJUST) {
141 if (vent->next == NULL) /* last one */
142 (void)printf("%s", v->header);
143 else
144 (void)printf("%-*s", v->width,
145 v->header);
146 } else
147 (void)printf("%*s", v->width, v->header);
148 if (vent->next != NULL)
149 (void)putchar(' ');
150 }
151 (void)putchar('\n');
152 if (firsttime) {
153 firsttime = 0;
154 totwidth--; /* take off last space */
155 }
156 }
157
158 /*
159 * Return 1 if the the command name in the argument vector (u-area) does
160 * not match the command name (p_comm)
161 */
162 static int
163 titlecmp(name, argv)
164 char *name;
165 char **argv;
166 {
167 char *title;
168 int namelen;
169
170
171 /* no argument vector == no match; system processes/threads do that */
172 if (argv == 0 || argv[0] == 0)
173 return (1);
174
175 title = cmdpart(argv[0]);
176
177 /* the basename matches */
178 if (!strcmp(name, title))
179 return (0);
180
181 /* handle login shells, by skipping the leading - */
182 if (title[0] == '-' && !strcmp(name, title+1))
183 return (0);
184
185 namelen = strlen(name);
186
187 /* handle daemons that report activity as daemonname: activity */
188 if (argv[1] == 0 &&
189 !strncmp(name, title, namelen) &&
190 title[namelen + 0] == ':' &&
191 title[namelen + 1] == ' ')
192 return (0);
193
194 return (1);
195 }
196
197 static void
198 doubleprintorsetwidth(v, val, prec, mode)
199 VAR *v;
200 double val;
201 int prec;
202 int mode;
203 {
204 int fmtlen;
205
206 if (mode == WIDTHMODE) {
207 if (val < 0.0 && val < v->longestnd) {
208 fmtlen = (int)log10(-val) + prec + 2;
209 v->longestnd = val;
210 if (fmtlen > v->width)
211 v->width = fmtlen;
212 } else if (val > 0.0 && val > v->longestpd) {
213 fmtlen = (int)log10(val) + prec + 1;
214 v->longestpd = val;
215 if (fmtlen > v->width)
216 v->width = fmtlen;
217 }
218 } else {
219 printf("%*.*f", v->width, prec, val);
220 }
221 }
222
223 static void
224 intprintorsetwidth(v, val, mode)
225 VAR *v;
226 int val;
227 int mode;
228 {
229 int fmtlen;
230
231 if (mode == WIDTHMODE) {
232 if (val < 0 && val < v->longestn) {
233 fmtlen = (int)log10((double)-val) + 2;
234 v->longestn = val;
235 if (fmtlen > v->width)
236 v->width = fmtlen;
237 } else if (val > 0 && val > v->longestp) {
238 fmtlen = (int)log10((double)val) + 1;
239 v->longestp = val;
240 if (fmtlen > v->width)
241 v->width = fmtlen;
242 }
243 } else
244 printf("%*d", v->width, val);
245 }
246
247 static void
248 strprintorsetwidth(v, str, mode)
249 VAR *v;
250 const char *str;
251 {
252 int len;
253
254 if (mode == WIDTHMODE) {
255 len = strlen(str);
256 if (len > v->width)
257 v->width = len;
258 } else {
259 if (v->flag & LJUST)
260 printf("%-*.*s", v->width, v->width, str);
261 else
262 printf("%*.*s", v->width, v->width, str);
263 }
264 }
265
266 void
267 command(ki, ve, mode)
268 struct kinfo_proc2 *ki;
269 VARENT *ve;
270 int mode;
271 {
272 VAR *v;
273 int left;
274 char **argv, **p, *name;
275
276 if (mode == WIDTHMODE)
277 return;
278
279 v = ve->var;
280 if (ve->next != NULL || termwidth != UNLIMITED) {
281 if (ve->next == NULL) {
282 left = termwidth - (totwidth - v->width);
283 if (left < 1) /* already wrapped, just use std width */
284 left = v->width;
285 } else
286 left = v->width;
287 } else
288 left = -1;
289 if (needenv && kd) {
290 argv = kvm_getenvv2(kd, ki, termwidth);
291 if ((p = argv) != NULL) {
292 while (*p) {
293 fmt_puts(*p, &left);
294 p++;
295 fmt_putc(' ', &left);
296 }
297 }
298 }
299 if (needcomm) {
300 name = ki->p_comm;
301 if (!commandonly) {
302 argv = NULL;
303 if (!use_procfs)
304 argv = kvm_getargv2(kd, ki, termwidth);
305 else
306 argv = procfs_getargv(ki, termwidth);
307 if ((p = argv) != NULL) {
308 while (*p) {
309 fmt_puts(*p, &left);
310 p++;
311 fmt_putc(' ', &left);
312 }
313 if (titlecmp(name, argv)) {
314 /*
315 * append the real command name within
316 * parentheses, if the command name
317 * does not match the one in the
318 * argument vector
319 */
320 fmt_putc('(', &left);
321 fmt_puts(name, &left);
322 fmt_putc(')', &left);
323 }
324 if (use_procfs) {
325 free(argv[0]);
326 free(argv);
327 }
328 } else {
329 /*
330 * Commands that don't set an argv vector
331 * are printed with square brackets if they
332 * are system commands. Otherwise they are
333 * printed within parentheses.
334 */
335 if (ki->p_flag & P_SYSTEM) {
336 fmt_putc('[', &left);
337 fmt_puts(name, &left);
338 fmt_putc(']', &left);
339 } else {
340 fmt_putc('(', &left);
341 fmt_puts(name, &left);
342 fmt_putc(')', &left);
343 }
344 }
345 } else {
346 fmt_puts(name, &left);
347 }
348 }
349 if (ve->next && left > 0)
350 printf("%*s", left, "");
351 }
352
353 void
354 ucomm(k, ve, mode)
355 struct kinfo_proc2 *k;
356 VARENT *ve;
357 int mode;
358 {
359 VAR *v;
360
361 v = ve->var;
362 strprintorsetwidth(v, k->p_comm, mode);
363 }
364
365 void
366 logname(k, ve, mode)
367 struct kinfo_proc2 *k;
368 VARENT *ve;
369 int mode;
370 {
371 VAR *v;
372
373 v = ve->var;
374 strprintorsetwidth(v, k->p_login, mode);
375 }
376
377 void
378 state(k, ve, mode)
379 struct kinfo_proc2 *k;
380 VARENT *ve;
381 int mode;
382 {
383 int flag, is_zombie;
384 char *cp;
385 VAR *v;
386 char buf[16];
387
388 is_zombie = 0;
389 v = ve->var;
390 flag = k->p_flag;
391 cp = buf;
392
393 switch (k->p_stat) {
394
395 case SSTOP:
396 *cp = 'T';
397 break;
398
399 case SSLEEP:
400 if (flag & P_SINTR) /* interuptable (long) */
401 *cp = k->p_slptime >= maxslp ? 'I' : 'S';
402 else
403 *cp = 'D';
404 break;
405
406 case SRUN:
407 case SIDL:
408 case SONPROC:
409 *cp = 'R';
410 break;
411
412 case SZOMB:
413 case SDEAD:
414 *cp = 'Z';
415 is_zombie = 1;
416 break;
417
418 default:
419 *cp = '?';
420 }
421 cp++;
422 if (flag & P_INMEM) {
423 } else
424 *cp++ = 'W';
425 if (k->p_nice < NZERO)
426 *cp++ = '<';
427 else if (k->p_nice > NZERO)
428 *cp++ = 'N';
429 if (flag & P_TRACED)
430 *cp++ = 'X';
431 if (flag & P_WEXIT && !is_zombie)
432 *cp++ = 'E';
433 if (flag & P_PPWAIT)
434 *cp++ = 'V';
435 if (flag & P_SYSTEM)
436 *cp++ = 'K';
437 /* system process might have this too, don't need to double up */
438 else if (k->p_holdcnt)
439 *cp++ = 'L';
440 if (k->p_eflag & EPROC_SLEADER)
441 *cp++ = 's';
442 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
443 *cp++ = '+';
444 *cp = '\0';
445 strprintorsetwidth(v, buf, mode);
446 }
447
448 void
449 pnice(k, ve, mode)
450 struct kinfo_proc2 *k;
451 VARENT *ve;
452 int mode;
453 {
454 VAR *v;
455
456 v = ve->var;
457 intprintorsetwidth(v, k->p_nice - NZERO, mode);
458 }
459
460 void
461 pri(k, ve, mode)
462 struct kinfo_proc2 *k;
463 VARENT *ve;
464 int mode;
465 {
466 VAR *v;
467
468 v = ve->var;
469 intprintorsetwidth(v, k->p_priority - PZERO, mode);
470 }
471
472 void
473 uname(k, ve, mode)
474 struct kinfo_proc2 *k;
475 VARENT *ve;
476 int mode;
477 {
478 VAR *v;
479
480 v = ve->var;
481 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
482 }
483
484 void
485 runame(k, ve, mode)
486 struct kinfo_proc2 *k;
487 VARENT *ve;
488 int mode;
489 {
490 VAR *v;
491
492 v = ve->var;
493 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
494 }
495
496 void
497 tdev(k, ve, mode)
498 struct kinfo_proc2 *k;
499 VARENT *ve;
500 int mode;
501 {
502 VAR *v;
503 dev_t dev;
504 char buff[16];
505
506 v = ve->var;
507 dev = k->p_tdev;
508 if (dev == NODEV) {
509 /*
510 * Minimum width is width of header - we don't
511 * need to check it every time.
512 */
513 if (mode == PRINTMODE)
514 (void)printf("%*s", v->width, "??");
515 } else {
516 (void)snprintf(buff, sizeof(buff),
517 "%d/%d", major(dev), minor(dev));
518 strprintorsetwidth(v, buff, mode);
519 }
520 }
521
522 void
523 tname(k, ve, mode)
524 struct kinfo_proc2 *k;
525 VARENT *ve;
526 int mode;
527 {
528 VAR *v;
529 dev_t dev;
530 const char *ttname;
531 int noctty;
532
533 v = ve->var;
534 dev = k->p_tdev;
535 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
536 /*
537 * Minimum width is width of header - we don't
538 * need to check it every time.
539 */
540 if (mode == PRINTMODE)
541 (void)printf("%-*s", v->width, "??");
542 } else {
543 if (strncmp(ttname, "tty", 3) == 0 ||
544 strncmp(ttname, "dty", 3) == 0)
545 ttname += 3;
546 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
547 if (mode == WIDTHMODE) {
548 int fmtlen;
549
550 fmtlen = strlen(ttname) + noctty;
551 if (v->width < fmtlen)
552 v->width = fmtlen;
553 } else {
554 if (noctty)
555 printf("%-*s-", v->width - 1, ttname);
556 else
557 printf("%-*s", v->width, ttname);
558 }
559 }
560 }
561
562 void
563 longtname(k, ve, mode)
564 struct kinfo_proc2 *k;
565 VARENT *ve;
566 int mode;
567 {
568 VAR *v;
569 dev_t dev;
570 const char *ttname;
571
572 v = ve->var;
573 dev = k->p_tdev;
574 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
575 /*
576 * Minimum width is width of header - we don't
577 * need to check it every time.
578 */
579 if (mode == PRINTMODE)
580 (void)printf("%-*s", v->width, "??");
581 }
582 else {
583 strprintorsetwidth(v, ttname, mode);
584 }
585 }
586
587 void
588 started(k, ve, mode)
589 struct kinfo_proc2 *k;
590 VARENT *ve;
591 int mode;
592 {
593 VAR *v;
594 static time_t now;
595 time_t startt;
596 struct tm *tp;
597 char buf[100], *cp;
598
599 /*
600 * XXX: The maximum width of this field is the same as the header
601 * "STARTED" for locales that have 3 letter abbreviated month
602 * names and 2 letter am/pm descriptions.
603 */
604 if (mode == WIDTHMODE)
605 return;
606
607 v = ve->var;
608 if (!k->p_uvalid) {
609 if (mode == PRINTMODE)
610 (void)printf("%*s", v->width, "-");
611 return;
612 }
613
614 startt = k->p_ustart_sec;
615 tp = localtime(&startt);
616 if (!now)
617 (void)time(&now);
618 if (now - k->p_ustart_sec < SECSPERDAY)
619 /* I *hate* SCCS... */
620 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
621 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
622 /* I *hate* SCCS... */
623 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
624 else
625 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
626 /* %e and %l can start with a space. */
627 cp = buf;
628 if (*cp == ' ')
629 cp++;
630 strprintorsetwidth(v, cp, mode);
631 }
632
633 void
634 lstarted(k, ve, mode)
635 struct kinfo_proc2 *k;
636 VARENT *ve;
637 int mode;
638 {
639 VAR *v;
640 time_t startt;
641 char buf[100];
642
643 v = ve->var;
644 if (!k->p_uvalid) {
645 /*
646 * Minimum width is less than header - we don't
647 * need to check it every time.
648 */
649 if (mode == PRINTMODE)
650 (void)printf("%*s", v->width, "-");
651 return;
652 }
653 startt = k->p_ustart_sec;
654
655 /* assume all times are the same length */
656 if (mode != WIDTHMODE || v->width == 0) {
657 (void)strftime(buf, sizeof(buf) -1, "%c",
658 localtime(&startt));
659 strprintorsetwidth(v, buf, mode);
660 }
661 }
662
663 void
664 wchan(k, ve, mode)
665 struct kinfo_proc2 *k;
666 VARENT *ve;
667 int mode;
668 {
669 VAR *v;
670 char *buf;
671
672 v = ve->var;
673 if (k->p_wchan) {
674 if (k->p_wmesg) {
675 strprintorsetwidth(v, k->p_wmesg, mode);
676 v->width = min(v->width, WMESGLEN);
677 } else {
678 (void)asprintf(&buf, "%-*llx", v->width,
679 (long long)k->p_wchan);
680 if (buf == NULL)
681 err(1, "%s", "");
682 strprintorsetwidth(v, buf, mode);
683 v->width = min(v->width, WMESGLEN);
684 free(buf);
685 }
686 } else {
687 if (mode == PRINTMODE)
688 (void)printf("%-*s", v->width, "-");
689 }
690 }
691
692 #define pgtok(a) (((a)*getpagesize())/1024)
693
694 void
695 vsize(k, ve, mode)
696 struct kinfo_proc2 *k;
697 VARENT *ve;
698 int mode;
699 {
700 VAR *v;
701
702 v = ve->var;
703 intprintorsetwidth(v,
704 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
705 }
706
707 void
708 rssize(k, ve, mode)
709 struct kinfo_proc2 *k;
710 VARENT *ve;
711 int mode;
712 {
713 VAR *v;
714
715 v = ve->var;
716 /* XXX don't have info about shared */
717 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
718 }
719
720 void
721 p_rssize(k, ve, mode) /* doesn't account for text */
722 struct kinfo_proc2 *k;
723 VARENT *ve;
724 int mode;
725 {
726 VAR *v;
727
728 v = ve->var;
729 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
730 }
731
732 void
733 cputime(k, ve, mode)
734 struct kinfo_proc2 *k;
735 VARENT *ve;
736 int mode;
737 {
738 VAR *v;
739 long secs;
740 long psecs; /* "parts" of a second. first micro, then centi */
741 int fmtlen;
742
743 v = ve->var;
744 if (P_ZOMBIE(k) || k->p_uvalid == 0) {
745 secs = 0;
746 psecs = 0;
747 } else {
748 /*
749 * This counts time spent handling interrupts. We could
750 * fix this, but it is not 100% trivial (and interrupt
751 * time fractions only work on the sparc anyway). XXX
752 */
753 secs = k->p_rtime_sec;
754 psecs = k->p_rtime_usec;
755 if (sumrusage) {
756 secs += k->p_uctime_sec;
757 psecs += k->p_uctime_usec;
758 }
759 /*
760 * round and scale to 100's
761 */
762 psecs = (psecs + 5000) / 10000;
763 secs += psecs / 100;
764 psecs = psecs % 100;
765 }
766 if (mode == WIDTHMODE) {
767 /*
768 * Ugg, this is the only field where a value of 0 longer
769 * than the column title, and log10(0) isn't good enough.
770 * Use SECSPERMIN, because secs is divided by that when
771 * passed to log10().
772 */
773 if (secs == 0 && v->longestp == 0)
774 secs = SECSPERMIN;
775 if (secs > v->longestp) {
776 /* "+6" for the "%02ld.%02ld" in the printf() below */
777 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
778 v->longestp = secs;
779 if (fmtlen > v->width)
780 v->width = fmtlen;
781 }
782 } else {
783 printf("%*ld:%02ld.%02ld", v->width - 6, secs / SECSPERMIN,
784 secs % SECSPERMIN, psecs);
785 }
786 }
787
788 double
789 getpcpu(k)
790 struct kinfo_proc2 *k;
791 {
792 static int failure;
793
794 if (!nlistread)
795 failure = (kd) ? donlist() : 1;
796 if (failure)
797 return (0.0);
798
799 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
800
801 /* XXX - I don't like this */
802 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 ||
803 k->p_stat == SZOMB || k->p_stat == SDEAD)
804 return (0.0);
805 if (rawcpu)
806 return (100.0 * fxtofl(k->p_pctcpu));
807 return (100.0 * fxtofl(k->p_pctcpu) /
808 (1.0 - exp(k->p_swtime * log(ccpu))));
809 }
810
811 void
812 pcpu(k, ve, mode)
813 struct kinfo_proc2 *k;
814 VARENT *ve;
815 int mode;
816 {
817 VAR *v;
818
819 v = ve->var;
820 doubleprintorsetwidth(v, getpcpu(k), 1, mode);
821 }
822
823 double
824 getpmem(k)
825 struct kinfo_proc2 *k;
826 {
827 static int failure;
828 double fracmem;
829 int szptudot;
830
831 if (!nlistread)
832 failure = (kd) ? donlist() : 1;
833 if (failure)
834 return (0.0);
835
836 if ((k->p_flag & P_INMEM) == 0)
837 return (0.0);
838 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
839 szptudot = uspace/getpagesize();
840 /* XXX don't have info about shared */
841 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
842 return (100.0 * fracmem);
843 }
844
845 void
846 pmem(k, ve, mode)
847 struct kinfo_proc2 *k;
848 VARENT *ve;
849 int mode;
850 {
851 VAR *v;
852
853 v = ve->var;
854 doubleprintorsetwidth(v, getpmem(k), 1, mode);
855 }
856
857 void
858 pagein(k, ve, mode)
859 struct kinfo_proc2 *k;
860 VARENT *ve;
861 int mode;
862 {
863 VAR *v;
864
865 v = ve->var;
866 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
867 }
868
869 void
870 maxrss(k, ve, mode)
871 struct kinfo_proc2 *k;
872 VARENT *ve;
873 int mode;
874 {
875 VAR *v;
876
877 v = ve->var;
878 /* No need to check width! */
879 if (mode == PRINTMODE)
880 (void)printf("%*s", v->width, "-");
881 }
882
883 void
884 tsize(k, ve, mode)
885 struct kinfo_proc2 *k;
886 VARENT *ve;
887 int mode;
888 {
889 VAR *v;
890
891 v = ve->var;
892 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
893 }
894
895 /*
896 * Generic output routines. Print fields from various prototype
897 * structures.
898 */
899 static void
900 printval(bp, v, mode)
901 void *bp;
902 VAR *v;
903 int mode;
904 {
905 static char ofmt[32] = "%";
906 int width, vok, fmtlen;
907 char *fcp, *cp, *obuf;
908 enum type type;
909 long long val;
910 unsigned long long uval;
911
912 /*
913 * Note that the "INF127" check is nonsensical for types
914 * that are or can be signed.
915 */
916 #define GET(type) (*(type *)bp)
917 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
918
919 #define VSIGN 1
920 #define VUNSIGN 2
921 #define VPTR 3
922
923 if (mode == WIDTHMODE) {
924 vok = 0;
925 switch (v->type) {
926 case CHAR:
927 val = GET(char);
928 vok = VSIGN;
929 break;
930 case UCHAR:
931 uval = CHK_INF127(GET(u_char));
932 vok = VUNSIGN;
933 break;
934 case SHORT:
935 val = GET(short);
936 vok = VSIGN;
937 break;
938 case USHORT:
939 uval = CHK_INF127(GET(u_short));
940 vok = VUNSIGN;
941 break;
942 case INT32:
943 val = GET(int32_t);
944 vok = VSIGN;
945 break;
946 case INT:
947 val = GET(int);
948 vok = VSIGN;
949 break;
950 case UINT:
951 case UINT32:
952 uval = CHK_INF127(GET(u_int));
953 vok = VUNSIGN;
954 break;
955 case LONG:
956 val = GET(long);
957 vok = VSIGN;
958 break;
959 case ULONG:
960 uval = CHK_INF127(GET(u_long));
961 vok = VUNSIGN;
962 break;
963 case KPTR:
964 uval = (unsigned long long)GET(u_int64_t);
965 vok = VPTR;
966 break;
967 case KPTR24:
968 uval = (unsigned long long)GET(u_int64_t);
969 uval &= 0xffffff;
970 vok = VPTR;
971 break;
972 default:
973 /* nothing... */;
974 }
975 switch (vok) {
976 case VSIGN:
977 if (val < 0 && val < v->longestn) {
978 fmtlen = (int)log10((double)-val) + 2;
979 v->longestn = val;
980 if (fmtlen > v->width)
981 v->width = fmtlen;
982 } else if (val > 0 && val > v->longestp) {
983 fmtlen = (int)log10((double)val) + 1;
984 v->longestp = val;
985 if (fmtlen > v->width)
986 v->width = fmtlen;
987 }
988 return;
989 case VUNSIGN:
990 if (uval > v->longestu) {
991 fmtlen = (int)log10((double)uval) + 1;
992 v->longestu = uval;
993 v->width = fmtlen;
994 }
995 return;
996 case VPTR:
997 fmtlen = 0;
998 while (uval > 0) {
999 uval >>= 4;
1000 fmtlen++;
1001 }
1002 if (fmtlen > v->width)
1003 v->width = fmtlen;
1004 return;
1005 }
1006 }
1007
1008 width = v->width;
1009 cp = ofmt + 1;
1010 fcp = v->fmt;
1011 if (v->flag & LJUST)
1012 *cp++ = '-';
1013 *cp++ = '*';
1014 while ((*cp++ = *fcp++) != '\0')
1015 continue;
1016
1017 switch (v->type) {
1018 case INT32:
1019 if (sizeof(int32_t) == sizeof(int))
1020 type = INT;
1021 else if (sizeof(int32_t) == sizeof(long))
1022 type = LONG;
1023 else
1024 errx(1, "unknown conversion for type %d", v->type);
1025 break;
1026 case UINT32:
1027 if (sizeof(u_int32_t) == sizeof(u_int))
1028 type = UINT;
1029 else if (sizeof(u_int32_t) == sizeof(u_long))
1030 type = ULONG;
1031 else
1032 errx(1, "unknown conversion for type %d", v->type);
1033 break;
1034 default:
1035 type = v->type;
1036 break;
1037 }
1038
1039 switch (type) {
1040 case CHAR:
1041 (void)printf(ofmt, width, GET(char));
1042 return;
1043 case UCHAR:
1044 (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1045 return;
1046 case SHORT:
1047 (void)printf(ofmt, width, GET(short));
1048 return;
1049 case USHORT:
1050 (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1051 return;
1052 case INT:
1053 (void)printf(ofmt, width, GET(int));
1054 return;
1055 case UINT:
1056 (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1057 return;
1058 case LONG:
1059 (void)printf(ofmt, width, GET(long));
1060 return;
1061 case ULONG:
1062 (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1063 return;
1064 case KPTR:
1065 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t));
1066 return;
1067 case KPTR24:
1068 (void)printf(ofmt, width,
1069 (unsigned long long)GET(u_int64_t) & 0xffffff);
1070 return;
1071 case SIGLIST:
1072 {
1073 sigset_t *s = (sigset_t *)(void *)bp;
1074 size_t i;
1075 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
1076 char buf[SIGSETSIZE * 8 + 1];
1077
1078 for (i = 0; i < SIGSETSIZE; i++)
1079 (void)snprintf(&buf[i * 8], 9, "%.8x",
1080 s->__bits[(SIGSETSIZE - 1) - i]);
1081
1082 /* Skip leading zeroes */
1083 for (i = 0; buf[i]; i++)
1084 if (buf[i] != '0')
1085 break;
1086
1087 if (buf[i] == '\0')
1088 i--;
1089 (void)asprintf(&obuf, ofmt, width, &buf[i]);
1090 }
1091 break;
1092 default:
1093 errx(1, "unknown type %d", v->type);
1094 }
1095 if (obuf == NULL)
1096 err(1, "%s", "");
1097 if (mode == WIDTHMODE) {
1098 /* Skip leading spaces. */
1099 cp = strrchr(obuf, ' ');
1100 if (cp == NULL)
1101 cp = obuf;
1102 else
1103 cp++; /* skip last space */
1104 }
1105 else
1106 cp = obuf;
1107 strprintorsetwidth(v, cp, mode);
1108 free(obuf);
1109 #undef GET
1110 #undef CHK_INF127
1111 }
1112
1113 void
1114 pvar(k, ve, mode)
1115 struct kinfo_proc2 *k;
1116 VARENT *ve;
1117 int mode;
1118 {
1119 VAR *v;
1120
1121 v = ve->var;
1122 printval((char *)k + v->off, v, mode);
1123 }
1124