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