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