print.c revision 1.74 1 /* $NetBSD: print.c,v 1.74 2002/06/19 08:11:55 jdolecek 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.74 2002/06/19 08:11:55 jdolecek 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 = kvm_getargv2(kd, ki, termwidth);
303 if ((p = argv) != NULL) {
304 while (*p) {
305 fmt_puts(*p, &left);
306 p++;
307 fmt_putc(' ', &left);
308 }
309 if (titlecmp(name, argv)) {
310 /*
311 * append the real command name within
312 * parentheses, if the command name
313 * does not match the one in the
314 * argument vector
315 */
316 fmt_putc('(', &left);
317 fmt_puts(name, &left);
318 fmt_putc(')', &left);
319 }
320 } else {
321 /*
322 * Commands that don't set an argv vector
323 * are printed with square brackets if they
324 * are system commands. Otherwise they are
325 * printed within parentheses.
326 */
327 if (ki->p_flag & P_SYSTEM) {
328 fmt_putc('[', &left);
329 fmt_puts(name, &left);
330 fmt_putc(']', &left);
331 } else {
332 fmt_putc('(', &left);
333 fmt_puts(name, &left);
334 fmt_putc(')', &left);
335 }
336 }
337 } else {
338 fmt_puts(name, &left);
339 }
340 }
341 if (ve->next && left > 0)
342 printf("%*s", left, "");
343 }
344
345 void
346 ucomm(k, ve, mode)
347 struct kinfo_proc2 *k;
348 VARENT *ve;
349 int mode;
350 {
351 VAR *v;
352
353 v = ve->var;
354 strprintorsetwidth(v, k->p_comm, mode);
355 }
356
357 void
358 logname(k, ve, mode)
359 struct kinfo_proc2 *k;
360 VARENT *ve;
361 int mode;
362 {
363 VAR *v;
364
365 v = ve->var;
366 strprintorsetwidth(v, k->p_login, mode);
367 }
368
369 void
370 state(k, ve, mode)
371 struct kinfo_proc2 *k;
372 VARENT *ve;
373 int mode;
374 {
375 int flag, is_zombie;
376 char *cp;
377 VAR *v;
378 char buf[16];
379
380 is_zombie = 0;
381 v = ve->var;
382 flag = k->p_flag;
383 cp = buf;
384
385 switch (k->p_stat) {
386
387 case SSTOP:
388 *cp = 'T';
389 break;
390
391 case SSLEEP:
392 if (flag & P_SINTR) /* interuptable (long) */
393 *cp = k->p_slptime >= maxslp ? 'I' : 'S';
394 else
395 *cp = 'D';
396 break;
397
398 case SRUN:
399 case SIDL:
400 case SONPROC:
401 *cp = 'R';
402 break;
403
404 case SZOMB:
405 case SDEAD:
406 *cp = 'Z';
407 is_zombie = 1;
408 break;
409
410 default:
411 *cp = '?';
412 }
413 cp++;
414 if (flag & P_INMEM) {
415 } else
416 *cp++ = 'W';
417 if (k->p_nice < NZERO)
418 *cp++ = '<';
419 else if (k->p_nice > NZERO)
420 *cp++ = 'N';
421 if (flag & P_TRACED)
422 *cp++ = 'X';
423 if (flag & P_SYSTRACE)
424 *cp++ = 'x';
425 if (flag & P_WEXIT && !is_zombie)
426 *cp++ = 'E';
427 if (flag & P_PPWAIT)
428 *cp++ = 'V';
429 if (flag & P_SYSTEM)
430 *cp++ = 'K';
431 /* system process might have this too, don't need to double up */
432 else if (k->p_holdcnt)
433 *cp++ = 'L';
434 if (k->p_eflag & EPROC_SLEADER)
435 *cp++ = 's';
436 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
437 *cp++ = '+';
438 *cp = '\0';
439 strprintorsetwidth(v, buf, mode);
440 }
441
442 void
443 pnice(k, ve, mode)
444 struct kinfo_proc2 *k;
445 VARENT *ve;
446 int mode;
447 {
448 VAR *v;
449
450 v = ve->var;
451 intprintorsetwidth(v, k->p_nice - NZERO, mode);
452 }
453
454 void
455 pri(k, ve, mode)
456 struct kinfo_proc2 *k;
457 VARENT *ve;
458 int mode;
459 {
460 VAR *v;
461
462 v = ve->var;
463 intprintorsetwidth(v, k->p_priority - PZERO, mode);
464 }
465
466 void
467 uname(k, ve, mode)
468 struct kinfo_proc2 *k;
469 VARENT *ve;
470 int mode;
471 {
472 VAR *v;
473
474 v = ve->var;
475 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
476 }
477
478 void
479 runame(k, ve, mode)
480 struct kinfo_proc2 *k;
481 VARENT *ve;
482 int mode;
483 {
484 VAR *v;
485
486 v = ve->var;
487 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
488 }
489
490 void
491 tdev(k, ve, mode)
492 struct kinfo_proc2 *k;
493 VARENT *ve;
494 int mode;
495 {
496 VAR *v;
497 dev_t dev;
498 char buff[16];
499
500 v = ve->var;
501 dev = k->p_tdev;
502 if (dev == NODEV) {
503 /*
504 * Minimum width is width of header - we don't
505 * need to check it every time.
506 */
507 if (mode == PRINTMODE)
508 (void)printf("%*s", v->width, "??");
509 } else {
510 (void)snprintf(buff, sizeof(buff),
511 "%d/%d", major(dev), minor(dev));
512 strprintorsetwidth(v, buff, mode);
513 }
514 }
515
516 void
517 tname(k, ve, mode)
518 struct kinfo_proc2 *k;
519 VARENT *ve;
520 int mode;
521 {
522 VAR *v;
523 dev_t dev;
524 const char *ttname;
525 int noctty;
526
527 v = ve->var;
528 dev = k->p_tdev;
529 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
530 /*
531 * Minimum width is width of header - we don't
532 * need to check it every time.
533 */
534 if (mode == PRINTMODE)
535 (void)printf("%-*s", v->width, "??");
536 } else {
537 if (strncmp(ttname, "tty", 3) == 0 ||
538 strncmp(ttname, "dty", 3) == 0)
539 ttname += 3;
540 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
541 if (mode == WIDTHMODE) {
542 int fmtlen;
543
544 fmtlen = strlen(ttname) + noctty;
545 if (v->width < fmtlen)
546 v->width = fmtlen;
547 } else {
548 if (noctty)
549 printf("%-*s-", v->width - 1, ttname);
550 else
551 printf("%-*s", v->width, ttname);
552 }
553 }
554 }
555
556 void
557 longtname(k, ve, mode)
558 struct kinfo_proc2 *k;
559 VARENT *ve;
560 int mode;
561 {
562 VAR *v;
563 dev_t dev;
564 const char *ttname;
565
566 v = ve->var;
567 dev = k->p_tdev;
568 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
569 /*
570 * Minimum width is width of header - we don't
571 * need to check it every time.
572 */
573 if (mode == PRINTMODE)
574 (void)printf("%-*s", v->width, "??");
575 }
576 else {
577 strprintorsetwidth(v, ttname, mode);
578 }
579 }
580
581 void
582 started(k, ve, mode)
583 struct kinfo_proc2 *k;
584 VARENT *ve;
585 int mode;
586 {
587 VAR *v;
588 static time_t now;
589 time_t startt;
590 struct tm *tp;
591 char buf[100], *cp;
592
593 v = ve->var;
594 if (!k->p_uvalid) {
595 if (mode == PRINTMODE)
596 (void)printf("%*s", v->width, "-");
597 return;
598 }
599
600 startt = k->p_ustart_sec;
601 tp = localtime(&startt);
602 if (!now)
603 (void)time(&now);
604 if (now - k->p_ustart_sec < SECSPERDAY)
605 /* I *hate* SCCS... */
606 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
607 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
608 /* I *hate* SCCS... */
609 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
610 else
611 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
612 /* %e and %l can start with a space. */
613 cp = buf;
614 if (*cp == ' ')
615 cp++;
616 strprintorsetwidth(v, cp, mode);
617 }
618
619 void
620 lstarted(k, ve, mode)
621 struct kinfo_proc2 *k;
622 VARENT *ve;
623 int mode;
624 {
625 VAR *v;
626 time_t startt;
627 char buf[100];
628
629 v = ve->var;
630 if (!k->p_uvalid) {
631 /*
632 * Minimum width is less than header - we don't
633 * need to check it every time.
634 */
635 if (mode == PRINTMODE)
636 (void)printf("%*s", v->width, "-");
637 return;
638 }
639 startt = k->p_ustart_sec;
640
641 /* assume all times are the same length */
642 if (mode != WIDTHMODE || v->width == 0) {
643 (void)strftime(buf, sizeof(buf) -1, "%c",
644 localtime(&startt));
645 strprintorsetwidth(v, buf, mode);
646 }
647 }
648
649 void
650 wchan(k, ve, mode)
651 struct kinfo_proc2 *k;
652 VARENT *ve;
653 int mode;
654 {
655 VAR *v;
656 char *buf;
657
658 v = ve->var;
659 if (k->p_wchan) {
660 if (k->p_wmesg) {
661 strprintorsetwidth(v, k->p_wmesg, mode);
662 v->width = min(v->width, WMESGLEN);
663 } else {
664 (void)asprintf(&buf, "%-*llx", v->width,
665 (long long)k->p_wchan);
666 if (buf == NULL)
667 err(1, "%s", "");
668 strprintorsetwidth(v, buf, mode);
669 v->width = min(v->width, WMESGLEN);
670 free(buf);
671 }
672 } else {
673 if (mode == PRINTMODE)
674 (void)printf("%-*s", v->width, "-");
675 }
676 }
677
678 #define pgtok(a) (((a)*getpagesize())/1024)
679
680 void
681 vsize(k, ve, mode)
682 struct kinfo_proc2 *k;
683 VARENT *ve;
684 int mode;
685 {
686 VAR *v;
687
688 v = ve->var;
689 intprintorsetwidth(v,
690 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
691 }
692
693 void
694 rssize(k, ve, mode)
695 struct kinfo_proc2 *k;
696 VARENT *ve;
697 int mode;
698 {
699 VAR *v;
700
701 v = ve->var;
702 /* XXX don't have info about shared */
703 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
704 }
705
706 void
707 p_rssize(k, ve, mode) /* doesn't account for text */
708 struct kinfo_proc2 *k;
709 VARENT *ve;
710 int mode;
711 {
712 VAR *v;
713
714 v = ve->var;
715 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
716 }
717
718 void
719 cputime(k, ve, mode)
720 struct kinfo_proc2 *k;
721 VARENT *ve;
722 int mode;
723 {
724 VAR *v;
725 int32_t secs;
726 int32_t psecs; /* "parts" of a second. first micro, then centi */
727 int fmtlen;
728
729 v = ve->var;
730 if (P_ZOMBIE(k) || k->p_uvalid == 0) {
731 secs = 0;
732 psecs = 0;
733 } else {
734 /*
735 * This counts time spent handling interrupts. We could
736 * fix this, but it is not 100% trivial (and interrupt
737 * time fractions only work on the sparc anyway). XXX
738 */
739 secs = k->p_rtime_sec;
740 psecs = k->p_rtime_usec;
741 if (sumrusage) {
742 secs += k->p_uctime_sec;
743 psecs += k->p_uctime_usec;
744 }
745 /*
746 * round and scale to 100's
747 */
748 psecs = (psecs + 5000) / 10000;
749 secs += psecs / 100;
750 psecs = psecs % 100;
751 }
752 if (mode == WIDTHMODE) {
753 /*
754 * Ugg, this is the only field where a value of 0 longer
755 * than the column title, and log10(0) isn't good enough.
756 * Use SECSPERMIN, because secs is divided by that when
757 * passed to log10().
758 */
759 if (secs == 0 && v->longestp == 0)
760 secs = SECSPERMIN;
761 if (secs > v->longestp) {
762 /* "+6" for the "%02ld.%02ld" in the printf() below */
763 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
764 v->longestp = secs;
765 if (fmtlen > v->width)
766 v->width = fmtlen;
767 }
768 } else {
769 printf("%*ld:%02ld.%02ld", v->width - 6, (long)(secs / SECSPERMIN),
770 (long)(secs % SECSPERMIN), (long)psecs);
771 }
772 }
773
774 double
775 getpcpu(k)
776 struct kinfo_proc2 *k;
777 {
778 static int failure;
779
780 if (!nlistread)
781 failure = (kd) ? donlist() : 1;
782 if (failure)
783 return (0.0);
784
785 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
786
787 /* XXX - I don't like this */
788 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 ||
789 k->p_stat == SZOMB || k->p_stat == SDEAD)
790 return (0.0);
791 if (rawcpu)
792 return (100.0 * fxtofl(k->p_pctcpu));
793 return (100.0 * fxtofl(k->p_pctcpu) /
794 (1.0 - exp(k->p_swtime * log(ccpu))));
795 }
796
797 void
798 pcpu(k, ve, mode)
799 struct kinfo_proc2 *k;
800 VARENT *ve;
801 int mode;
802 {
803 VAR *v;
804
805 v = ve->var;
806 doubleprintorsetwidth(v, getpcpu(k), 1, mode);
807 }
808
809 double
810 getpmem(k)
811 struct kinfo_proc2 *k;
812 {
813 static int failure;
814 double fracmem;
815 int szptudot;
816
817 if (!nlistread)
818 failure = (kd) ? donlist() : 1;
819 if (failure)
820 return (0.0);
821
822 if ((k->p_flag & P_INMEM) == 0)
823 return (0.0);
824 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
825 szptudot = uspace/getpagesize();
826 /* XXX don't have info about shared */
827 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
828 return (100.0 * fracmem);
829 }
830
831 void
832 pmem(k, ve, mode)
833 struct kinfo_proc2 *k;
834 VARENT *ve;
835 int mode;
836 {
837 VAR *v;
838
839 v = ve->var;
840 doubleprintorsetwidth(v, getpmem(k), 1, mode);
841 }
842
843 void
844 pagein(k, ve, mode)
845 struct kinfo_proc2 *k;
846 VARENT *ve;
847 int mode;
848 {
849 VAR *v;
850
851 v = ve->var;
852 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
853 }
854
855 void
856 maxrss(k, ve, mode)
857 struct kinfo_proc2 *k;
858 VARENT *ve;
859 int mode;
860 {
861 VAR *v;
862
863 v = ve->var;
864 /* No need to check width! */
865 if (mode == PRINTMODE)
866 (void)printf("%*s", v->width, "-");
867 }
868
869 void
870 tsize(k, ve, mode)
871 struct kinfo_proc2 *k;
872 VARENT *ve;
873 int mode;
874 {
875 VAR *v;
876
877 v = ve->var;
878 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
879 }
880
881 /*
882 * Generic output routines. Print fields from various prototype
883 * structures.
884 */
885 static void
886 printval(bp, v, mode)
887 void *bp;
888 VAR *v;
889 int mode;
890 {
891 static char ofmt[32] = "%";
892 int width, vok, fmtlen;
893 char *fcp, *cp, *obuf;
894 enum type type;
895 long long val;
896 unsigned long long uval;
897
898 /*
899 * Note that the "INF127" check is nonsensical for types
900 * that are or can be signed.
901 */
902 #define GET(type) (*(type *)bp)
903 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
904
905 #define VSIGN 1
906 #define VUNSIGN 2
907 #define VPTR 3
908
909 if (mode == WIDTHMODE) {
910 vok = 0;
911 switch (v->type) {
912 case CHAR:
913 val = GET(char);
914 vok = VSIGN;
915 break;
916 case UCHAR:
917 uval = CHK_INF127(GET(u_char));
918 vok = VUNSIGN;
919 break;
920 case SHORT:
921 val = GET(short);
922 vok = VSIGN;
923 break;
924 case USHORT:
925 uval = CHK_INF127(GET(u_short));
926 vok = VUNSIGN;
927 break;
928 case INT32:
929 val = GET(int32_t);
930 vok = VSIGN;
931 break;
932 case INT:
933 val = GET(int);
934 vok = VSIGN;
935 break;
936 case UINT:
937 case UINT32:
938 uval = CHK_INF127(GET(u_int));
939 vok = VUNSIGN;
940 break;
941 case LONG:
942 val = GET(long);
943 vok = VSIGN;
944 break;
945 case ULONG:
946 uval = CHK_INF127(GET(u_long));
947 vok = VUNSIGN;
948 break;
949 case KPTR:
950 uval = (unsigned long long)GET(u_int64_t);
951 vok = VPTR;
952 break;
953 case KPTR24:
954 uval = (unsigned long long)GET(u_int64_t);
955 uval &= 0xffffff;
956 vok = VPTR;
957 break;
958 case INT64:
959 val = (long long)GET(int64_t);
960 vok = VSIGN;
961 break;
962 case UINT64:
963 uval = (unsigned long long)CHK_INF127(GET(u_int64_t));
964 vok = VUNSIGN;
965 break;
966
967 default:
968 /* nothing... */;
969 }
970 switch (vok) {
971 case VSIGN:
972 if (val < 0 && val < v->longestn) {
973 fmtlen = (int)log10((double)-val) + 2;
974 v->longestn = val;
975 if (fmtlen > v->width)
976 v->width = fmtlen;
977 } else if (val > 0 && val > v->longestp) {
978 fmtlen = (int)log10((double)val) + 1;
979 v->longestp = val;
980 if (fmtlen > v->width)
981 v->width = fmtlen;
982 }
983 return;
984 case VUNSIGN:
985 if (uval > v->longestu) {
986 fmtlen = (int)log10((double)uval) + 1;
987 v->longestu = uval;
988 v->width = fmtlen;
989 }
990 return;
991 case VPTR:
992 fmtlen = 0;
993 while (uval > 0) {
994 uval >>= 4;
995 fmtlen++;
996 }
997 if (fmtlen > v->width)
998 v->width = fmtlen;
999 return;
1000 }
1001 }
1002
1003 width = v->width;
1004 cp = ofmt + 1;
1005 fcp = v->fmt;
1006 if (v->flag & LJUST)
1007 *cp++ = '-';
1008 *cp++ = '*';
1009 while ((*cp++ = *fcp++) != '\0')
1010 continue;
1011
1012 switch (v->type) {
1013 case INT32:
1014 if (sizeof(int32_t) == sizeof(int))
1015 type = INT;
1016 else if (sizeof(int32_t) == sizeof(long))
1017 type = LONG;
1018 else
1019 errx(1, "unknown conversion for type %d", v->type);
1020 break;
1021 case UINT32:
1022 if (sizeof(u_int32_t) == sizeof(u_int))
1023 type = UINT;
1024 else if (sizeof(u_int32_t) == sizeof(u_long))
1025 type = ULONG;
1026 else
1027 errx(1, "unknown conversion for type %d", v->type);
1028 break;
1029 default:
1030 type = v->type;
1031 break;
1032 }
1033
1034 switch (type) {
1035 case CHAR:
1036 (void)printf(ofmt, width, GET(char));
1037 return;
1038 case UCHAR:
1039 (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1040 return;
1041 case SHORT:
1042 (void)printf(ofmt, width, GET(short));
1043 return;
1044 case USHORT:
1045 (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1046 return;
1047 case INT:
1048 (void)printf(ofmt, width, GET(int));
1049 return;
1050 case UINT:
1051 (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1052 return;
1053 case LONG:
1054 (void)printf(ofmt, width, GET(long));
1055 return;
1056 case ULONG:
1057 (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1058 return;
1059 case KPTR:
1060 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t));
1061 return;
1062 case KPTR24:
1063 (void)printf(ofmt, width,
1064 (unsigned long long)GET(u_int64_t) & 0xffffff);
1065 return;
1066 case SIGLIST:
1067 {
1068 sigset_t *s = (sigset_t *)(void *)bp;
1069 size_t i;
1070 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
1071 char buf[SIGSETSIZE * 8 + 1];
1072
1073 for (i = 0; i < SIGSETSIZE; i++)
1074 (void)snprintf(&buf[i * 8], 9, "%.8x",
1075 s->__bits[(SIGSETSIZE - 1) - i]);
1076
1077 /* Skip leading zeroes */
1078 for (i = 0; buf[i]; i++)
1079 if (buf[i] != '0')
1080 break;
1081
1082 if (buf[i] == '\0')
1083 i--;
1084 (void)asprintf(&obuf, ofmt, width, &buf[i]);
1085 }
1086 break;
1087 case INT64:
1088 (void)printf(ofmt, width, (long long)GET(int64_t));
1089 return;
1090 case UINT64:
1091 (void)printf(ofmt, width, (unsigned long long)CHK_INF127(GET(u_int64_t)));
1092 return;
1093 default:
1094 errx(1, "unknown type %d", v->type);
1095 }
1096 if (obuf == NULL)
1097 err(1, "%s", "");
1098 if (mode == WIDTHMODE) {
1099 /* Skip leading spaces. */
1100 cp = strrchr(obuf, ' ');
1101 if (cp == NULL)
1102 cp = obuf;
1103 else
1104 cp++; /* skip last space */
1105 }
1106 else
1107 cp = obuf;
1108 strprintorsetwidth(v, cp, mode);
1109 free(obuf);
1110 #undef GET
1111 #undef CHK_INF127
1112 }
1113
1114 void
1115 pvar(k, ve, mode)
1116 struct kinfo_proc2 *k;
1117 VARENT *ve;
1118 int mode;
1119 {
1120 VAR *v;
1121
1122 v = ve->var;
1123 printval((char *)k + v->off, v, mode);
1124 }
1125