print.c revision 1.71 1 /* $NetBSD: print.c,v 1.71 2002/02/21 19:31:03 martin 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.71 2002/02/21 19:31:03 martin 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 v = ve->var;
600 if (!k->p_uvalid) {
601 if (mode == PRINTMODE)
602 (void)printf("%*s", v->width, "-");
603 return;
604 }
605
606 startt = k->p_ustart_sec;
607 tp = localtime(&startt);
608 if (!now)
609 (void)time(&now);
610 if (now - k->p_ustart_sec < SECSPERDAY)
611 /* I *hate* SCCS... */
612 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
613 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
614 /* I *hate* SCCS... */
615 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
616 else
617 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
618 /* %e and %l can start with a space. */
619 cp = buf;
620 if (*cp == ' ')
621 cp++;
622 strprintorsetwidth(v, cp, mode);
623 }
624
625 void
626 lstarted(k, ve, mode)
627 struct kinfo_proc2 *k;
628 VARENT *ve;
629 int mode;
630 {
631 VAR *v;
632 time_t startt;
633 char buf[100];
634
635 v = ve->var;
636 if (!k->p_uvalid) {
637 /*
638 * Minimum width is less than header - we don't
639 * need to check it every time.
640 */
641 if (mode == PRINTMODE)
642 (void)printf("%*s", v->width, "-");
643 return;
644 }
645 startt = k->p_ustart_sec;
646
647 /* assume all times are the same length */
648 if (mode != WIDTHMODE || v->width == 0) {
649 (void)strftime(buf, sizeof(buf) -1, "%c",
650 localtime(&startt));
651 strprintorsetwidth(v, buf, mode);
652 }
653 }
654
655 void
656 wchan(k, ve, mode)
657 struct kinfo_proc2 *k;
658 VARENT *ve;
659 int mode;
660 {
661 VAR *v;
662 char *buf;
663
664 v = ve->var;
665 if (k->p_wchan) {
666 if (k->p_wmesg) {
667 strprintorsetwidth(v, k->p_wmesg, mode);
668 v->width = min(v->width, WMESGLEN);
669 } else {
670 (void)asprintf(&buf, "%-*llx", v->width,
671 (long long)k->p_wchan);
672 if (buf == NULL)
673 err(1, "%s", "");
674 strprintorsetwidth(v, buf, mode);
675 v->width = min(v->width, WMESGLEN);
676 free(buf);
677 }
678 } else {
679 if (mode == PRINTMODE)
680 (void)printf("%-*s", v->width, "-");
681 }
682 }
683
684 #define pgtok(a) (((a)*getpagesize())/1024)
685
686 void
687 vsize(k, ve, mode)
688 struct kinfo_proc2 *k;
689 VARENT *ve;
690 int mode;
691 {
692 VAR *v;
693
694 v = ve->var;
695 intprintorsetwidth(v,
696 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
697 }
698
699 void
700 rssize(k, ve, mode)
701 struct kinfo_proc2 *k;
702 VARENT *ve;
703 int mode;
704 {
705 VAR *v;
706
707 v = ve->var;
708 /* XXX don't have info about shared */
709 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
710 }
711
712 void
713 p_rssize(k, ve, mode) /* doesn't account for text */
714 struct kinfo_proc2 *k;
715 VARENT *ve;
716 int mode;
717 {
718 VAR *v;
719
720 v = ve->var;
721 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
722 }
723
724 void
725 cputime(k, ve, mode)
726 struct kinfo_proc2 *k;
727 VARENT *ve;
728 int mode;
729 {
730 VAR *v;
731 int32_t secs;
732 int32_t psecs; /* "parts" of a second. first micro, then centi */
733 int fmtlen;
734
735 v = ve->var;
736 if (P_ZOMBIE(k) || k->p_uvalid == 0) {
737 secs = 0;
738 psecs = 0;
739 } else {
740 /*
741 * This counts time spent handling interrupts. We could
742 * fix this, but it is not 100% trivial (and interrupt
743 * time fractions only work on the sparc anyway). XXX
744 */
745 secs = k->p_rtime_sec;
746 psecs = k->p_rtime_usec;
747 if (sumrusage) {
748 secs += k->p_uctime_sec;
749 psecs += k->p_uctime_usec;
750 }
751 /*
752 * round and scale to 100's
753 */
754 psecs = (psecs + 5000) / 10000;
755 secs += psecs / 100;
756 psecs = psecs % 100;
757 }
758 if (mode == WIDTHMODE) {
759 /*
760 * Ugg, this is the only field where a value of 0 longer
761 * than the column title, and log10(0) isn't good enough.
762 * Use SECSPERMIN, because secs is divided by that when
763 * passed to log10().
764 */
765 if (secs == 0 && v->longestp == 0)
766 secs = SECSPERMIN;
767 if (secs > v->longestp) {
768 /* "+6" for the "%02ld.%02ld" in the printf() below */
769 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
770 v->longestp = secs;
771 if (fmtlen > v->width)
772 v->width = fmtlen;
773 }
774 } else {
775 printf("%*ld:%02ld.%02ld", v->width - 6, (long)(secs / SECSPERMIN),
776 (long)(secs % SECSPERMIN), (long)psecs);
777 }
778 }
779
780 double
781 getpcpu(k)
782 struct kinfo_proc2 *k;
783 {
784 static int failure;
785
786 if (!nlistread)
787 failure = (kd) ? donlist() : 1;
788 if (failure)
789 return (0.0);
790
791 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
792
793 /* XXX - I don't like this */
794 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 ||
795 k->p_stat == SZOMB || k->p_stat == SDEAD)
796 return (0.0);
797 if (rawcpu)
798 return (100.0 * fxtofl(k->p_pctcpu));
799 return (100.0 * fxtofl(k->p_pctcpu) /
800 (1.0 - exp(k->p_swtime * log(ccpu))));
801 }
802
803 void
804 pcpu(k, ve, mode)
805 struct kinfo_proc2 *k;
806 VARENT *ve;
807 int mode;
808 {
809 VAR *v;
810
811 v = ve->var;
812 doubleprintorsetwidth(v, getpcpu(k), 1, mode);
813 }
814
815 double
816 getpmem(k)
817 struct kinfo_proc2 *k;
818 {
819 static int failure;
820 double fracmem;
821 int szptudot;
822
823 if (!nlistread)
824 failure = (kd) ? donlist() : 1;
825 if (failure)
826 return (0.0);
827
828 if ((k->p_flag & P_INMEM) == 0)
829 return (0.0);
830 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
831 szptudot = uspace/getpagesize();
832 /* XXX don't have info about shared */
833 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
834 return (100.0 * fracmem);
835 }
836
837 void
838 pmem(k, ve, mode)
839 struct kinfo_proc2 *k;
840 VARENT *ve;
841 int mode;
842 {
843 VAR *v;
844
845 v = ve->var;
846 doubleprintorsetwidth(v, getpmem(k), 1, mode);
847 }
848
849 void
850 pagein(k, ve, mode)
851 struct kinfo_proc2 *k;
852 VARENT *ve;
853 int mode;
854 {
855 VAR *v;
856
857 v = ve->var;
858 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
859 }
860
861 void
862 maxrss(k, ve, mode)
863 struct kinfo_proc2 *k;
864 VARENT *ve;
865 int mode;
866 {
867 VAR *v;
868
869 v = ve->var;
870 /* No need to check width! */
871 if (mode == PRINTMODE)
872 (void)printf("%*s", v->width, "-");
873 }
874
875 void
876 tsize(k, ve, mode)
877 struct kinfo_proc2 *k;
878 VARENT *ve;
879 int mode;
880 {
881 VAR *v;
882
883 v = ve->var;
884 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
885 }
886
887 /*
888 * Generic output routines. Print fields from various prototype
889 * structures.
890 */
891 static void
892 printval(bp, v, mode)
893 void *bp;
894 VAR *v;
895 int mode;
896 {
897 static char ofmt[32] = "%";
898 int width, vok, fmtlen;
899 char *fcp, *cp, *obuf;
900 enum type type;
901 long long val;
902 unsigned long long uval;
903
904 /*
905 * Note that the "INF127" check is nonsensical for types
906 * that are or can be signed.
907 */
908 #define GET(type) (*(type *)bp)
909 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
910
911 #define VSIGN 1
912 #define VUNSIGN 2
913 #define VPTR 3
914
915 if (mode == WIDTHMODE) {
916 vok = 0;
917 switch (v->type) {
918 case CHAR:
919 val = GET(char);
920 vok = VSIGN;
921 break;
922 case UCHAR:
923 uval = CHK_INF127(GET(u_char));
924 vok = VUNSIGN;
925 break;
926 case SHORT:
927 val = GET(short);
928 vok = VSIGN;
929 break;
930 case USHORT:
931 uval = CHK_INF127(GET(u_short));
932 vok = VUNSIGN;
933 break;
934 case INT32:
935 val = GET(int32_t);
936 vok = VSIGN;
937 break;
938 case INT:
939 val = GET(int);
940 vok = VSIGN;
941 break;
942 case UINT:
943 case UINT32:
944 uval = CHK_INF127(GET(u_int));
945 vok = VUNSIGN;
946 break;
947 case LONG:
948 val = GET(long);
949 vok = VSIGN;
950 break;
951 case ULONG:
952 uval = CHK_INF127(GET(u_long));
953 vok = VUNSIGN;
954 break;
955 case KPTR:
956 uval = (unsigned long long)GET(u_int64_t);
957 vok = VPTR;
958 break;
959 case KPTR24:
960 uval = (unsigned long long)GET(u_int64_t);
961 uval &= 0xffffff;
962 vok = VPTR;
963 break;
964 default:
965 /* nothing... */;
966 }
967 switch (vok) {
968 case VSIGN:
969 if (val < 0 && val < v->longestn) {
970 fmtlen = (int)log10((double)-val) + 2;
971 v->longestn = val;
972 if (fmtlen > v->width)
973 v->width = fmtlen;
974 } else if (val > 0 && val > v->longestp) {
975 fmtlen = (int)log10((double)val) + 1;
976 v->longestp = val;
977 if (fmtlen > v->width)
978 v->width = fmtlen;
979 }
980 return;
981 case VUNSIGN:
982 if (uval > v->longestu) {
983 fmtlen = (int)log10((double)uval) + 1;
984 v->longestu = uval;
985 v->width = fmtlen;
986 }
987 return;
988 case VPTR:
989 fmtlen = 0;
990 while (uval > 0) {
991 uval >>= 4;
992 fmtlen++;
993 }
994 if (fmtlen > v->width)
995 v->width = fmtlen;
996 return;
997 }
998 }
999
1000 width = v->width;
1001 cp = ofmt + 1;
1002 fcp = v->fmt;
1003 if (v->flag & LJUST)
1004 *cp++ = '-';
1005 *cp++ = '*';
1006 while ((*cp++ = *fcp++) != '\0')
1007 continue;
1008
1009 switch (v->type) {
1010 case INT32:
1011 if (sizeof(int32_t) == sizeof(int))
1012 type = INT;
1013 else if (sizeof(int32_t) == sizeof(long))
1014 type = LONG;
1015 else
1016 errx(1, "unknown conversion for type %d", v->type);
1017 break;
1018 case UINT32:
1019 if (sizeof(u_int32_t) == sizeof(u_int))
1020 type = UINT;
1021 else if (sizeof(u_int32_t) == sizeof(u_long))
1022 type = ULONG;
1023 else
1024 errx(1, "unknown conversion for type %d", v->type);
1025 break;
1026 default:
1027 type = v->type;
1028 break;
1029 }
1030
1031 switch (type) {
1032 case CHAR:
1033 (void)printf(ofmt, width, GET(char));
1034 return;
1035 case UCHAR:
1036 (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1037 return;
1038 case SHORT:
1039 (void)printf(ofmt, width, GET(short));
1040 return;
1041 case USHORT:
1042 (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1043 return;
1044 case INT:
1045 (void)printf(ofmt, width, GET(int));
1046 return;
1047 case UINT:
1048 (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1049 return;
1050 case LONG:
1051 (void)printf(ofmt, width, GET(long));
1052 return;
1053 case ULONG:
1054 (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1055 return;
1056 case KPTR:
1057 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t));
1058 return;
1059 case KPTR24:
1060 (void)printf(ofmt, width,
1061 (unsigned long long)GET(u_int64_t) & 0xffffff);
1062 return;
1063 case SIGLIST:
1064 {
1065 sigset_t *s = (sigset_t *)(void *)bp;
1066 size_t i;
1067 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
1068 char buf[SIGSETSIZE * 8 + 1];
1069
1070 for (i = 0; i < SIGSETSIZE; i++)
1071 (void)snprintf(&buf[i * 8], 9, "%.8x",
1072 s->__bits[(SIGSETSIZE - 1) - i]);
1073
1074 /* Skip leading zeroes */
1075 for (i = 0; buf[i]; i++)
1076 if (buf[i] != '0')
1077 break;
1078
1079 if (buf[i] == '\0')
1080 i--;
1081 (void)asprintf(&obuf, ofmt, width, &buf[i]);
1082 }
1083 break;
1084 default:
1085 errx(1, "unknown type %d", v->type);
1086 }
1087 if (obuf == NULL)
1088 err(1, "%s", "");
1089 if (mode == WIDTHMODE) {
1090 /* Skip leading spaces. */
1091 cp = strrchr(obuf, ' ');
1092 if (cp == NULL)
1093 cp = obuf;
1094 else
1095 cp++; /* skip last space */
1096 }
1097 else
1098 cp = obuf;
1099 strprintorsetwidth(v, cp, mode);
1100 free(obuf);
1101 #undef GET
1102 #undef CHK_INF127
1103 }
1104
1105 void
1106 pvar(k, ve, mode)
1107 struct kinfo_proc2 *k;
1108 VARENT *ve;
1109 int mode;
1110 {
1111 VAR *v;
1112
1113 v = ve->var;
1114 printval((char *)k + v->off, v, mode);
1115 }
1116