print.c revision 1.77 1 /* $NetBSD: print.c,v 1.77 2003/03/01 05:41:56 atatat 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.77 2003/03/01 05:41:56 atatat 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/lwp.h>
85 #include <sys/proc.h>
86 #include <sys/stat.h>
87 #include <sys/ucred.h>
88 #include <sys/sysctl.h>
89
90 #include <err.h>
91 #include <grp.h>
92 #include <kvm.h>
93 #include <math.h>
94 #include <nlist.h>
95 #include <pwd.h>
96 #include <stddef.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #include <time.h>
101 #include <tzfile.h>
102 #include <unistd.h>
103
104 #include "ps.h"
105
106 static char *cmdpart __P((char *));
107 static void printval __P((void *, VAR *, int));
108 static int titlecmp __P((char *, char **));
109
110 static void doubleprintorsetwidth __P((VAR *, double, int, int));
111 static void intprintorsetwidth __P((VAR *, int, int));
112 static void strprintorsetwidth __P((VAR *, const char *, int));
113
114 #define min(a,b) ((a) <= (b) ? (a) : (b))
115 #define max(a,b) ((a) >= (b) ? (a) : (b))
116
117 static char *
118 cmdpart(arg0)
119 char *arg0;
120 {
121 char *cp;
122
123 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
124 }
125
126 void
127 printheader()
128 {
129 int len;
130 VAR *v;
131 struct varent *vent;
132 static int firsttime = 1;
133
134 for (vent = vhead; vent; vent = vent->next) {
135 v = vent->var;
136 if (firsttime) {
137 len = strlen(v->header);
138 if (len > v->width)
139 v->width = len;
140 totwidth += v->width + 1; /* +1 for space */
141 }
142 if (v->flag & LJUST) {
143 if (vent->next == NULL) /* last one */
144 (void)printf("%s", v->header);
145 else
146 (void)printf("%-*s", v->width,
147 v->header);
148 } else
149 (void)printf("%*s", v->width, v->header);
150 if (vent->next != NULL)
151 (void)putchar(' ');
152 }
153 (void)putchar('\n');
154 if (firsttime) {
155 firsttime = 0;
156 totwidth--; /* take off last space */
157 }
158 }
159
160 /*
161 * Return 1 if the the command name in the argument vector (u-area) does
162 * not match the command name (p_comm)
163 */
164 static int
165 titlecmp(name, argv)
166 char *name;
167 char **argv;
168 {
169 char *title;
170 int namelen;
171
172
173 /* no argument vector == no match; system processes/threads do that */
174 if (argv == 0 || argv[0] == 0)
175 return (1);
176
177 title = cmdpart(argv[0]);
178
179 /* the basename matches */
180 if (!strcmp(name, title))
181 return (0);
182
183 /* handle login shells, by skipping the leading - */
184 if (title[0] == '-' && !strcmp(name, title+1))
185 return (0);
186
187 namelen = strlen(name);
188
189 /* handle daemons that report activity as daemonname: activity */
190 if (argv[1] == 0 &&
191 !strncmp(name, title, namelen) &&
192 title[namelen + 0] == ':' &&
193 title[namelen + 1] == ' ')
194 return (0);
195
196 return (1);
197 }
198
199 static void
200 doubleprintorsetwidth(v, val, prec, mode)
201 VAR *v;
202 double val;
203 int prec;
204 int mode;
205 {
206 int fmtlen;
207
208 if (mode == WIDTHMODE) {
209 if (val < 0.0 && val < v->longestnd) {
210 fmtlen = (int)log10(-val) + prec + 2;
211 v->longestnd = val;
212 if (fmtlen > v->width)
213 v->width = fmtlen;
214 } else if (val > 0.0 && val > v->longestpd) {
215 fmtlen = (int)log10(val) + prec + 1;
216 v->longestpd = val;
217 if (fmtlen > v->width)
218 v->width = fmtlen;
219 }
220 } else {
221 printf("%*.*f", v->width, prec, val);
222 }
223 }
224
225 static void
226 intprintorsetwidth(v, val, mode)
227 VAR *v;
228 int val;
229 int mode;
230 {
231 int fmtlen;
232
233 if (mode == WIDTHMODE) {
234 if (val < 0 && val < v->longestn) {
235 fmtlen = (int)log10((double)-val) + 2;
236 v->longestn = val;
237 if (fmtlen > v->width)
238 v->width = fmtlen;
239 } else if (val > 0 && val > v->longestp) {
240 fmtlen = (int)log10((double)val) + 1;
241 v->longestp = val;
242 if (fmtlen > v->width)
243 v->width = fmtlen;
244 }
245 } else
246 printf("%*d", v->width, val);
247 }
248
249 static void
250 strprintorsetwidth(v, str, mode)
251 VAR *v;
252 const char *str;
253 {
254 int len;
255
256 if (mode == WIDTHMODE) {
257 len = strlen(str);
258 if (len > v->width)
259 v->width = len;
260 } else {
261 if (v->flag & LJUST)
262 printf("%-*.*s", v->width, v->width, str);
263 else
264 printf("%*.*s", v->width, v->width, str);
265 }
266 }
267
268 void
269 command(arg, ve, mode)
270 void *arg;
271 VARENT *ve;
272 int mode;
273 {
274 struct kinfo_proc2 *ki;
275 VAR *v;
276 int left;
277 char **argv, **p, *name;
278
279 if (mode == WIDTHMODE)
280 return;
281
282 ki = arg;
283 v = ve->var;
284 if (ve->next != NULL || termwidth != UNLIMITED) {
285 if (ve->next == NULL) {
286 left = termwidth - (totwidth - v->width);
287 if (left < 1) /* already wrapped, just use std width */
288 left = v->width;
289 } else
290 left = v->width;
291 } else
292 left = -1;
293 if (needenv && kd) {
294 argv = kvm_getenvv2(kd, ki, termwidth);
295 if ((p = argv) != NULL) {
296 while (*p) {
297 fmt_puts(*p, &left);
298 p++;
299 fmt_putc(' ', &left);
300 }
301 }
302 }
303 if (needcomm) {
304 name = ki->p_comm;
305 if (!commandonly) {
306 argv = kvm_getargv2(kd, 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 } else {
325 /*
326 * Commands that don't set an argv vector
327 * are printed with square brackets if they
328 * are system commands. Otherwise they are
329 * printed within parentheses.
330 */
331 if (ki->p_flag & P_SYSTEM) {
332 fmt_putc('[', &left);
333 fmt_puts(name, &left);
334 fmt_putc(']', &left);
335 } else {
336 fmt_putc('(', &left);
337 fmt_puts(name, &left);
338 fmt_putc(')', &left);
339 }
340 }
341 } else {
342 fmt_puts(name, &left);
343 }
344 }
345 if (ve->next && left > 0)
346 printf("%*s", left, "");
347 }
348
349 void
350 groups(arg, ve, mode)
351 void *arg;
352 VARENT *ve;
353 int mode;
354 {
355 struct kinfo_proc2 *ki;
356 VAR *v;
357 int left, i;
358 char buf[16], *p;
359
360 if (mode == WIDTHMODE)
361 return;
362
363 ki = arg;
364 v = ve->var;
365 if (ve->next != NULL || termwidth != UNLIMITED) {
366 if (ve->next == NULL) {
367 left = termwidth - (totwidth - v->width);
368 if (left < 1) /* already wrapped, just use std width */
369 left = v->width;
370 } else
371 left = v->width;
372 } else
373 left = -1;
374
375 if (ki->p_ngroups == 0) {
376 fmt_putc('-', &left);
377 return;
378 }
379
380 for (i = 0; i < ki->p_ngroups; i++) {
381 (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]);
382 if (i)
383 fmt_putc(' ', &left);
384 for (p = &buf[0]; *p; p++)
385 fmt_putc(*p, &left);
386 }
387
388 if (ve->next && left > 0)
389 printf("%*s", left, "");
390 }
391
392 void
393 groupnames(arg, ve, mode)
394 void *arg;
395 VARENT *ve;
396 int mode;
397 {
398 struct kinfo_proc2 *ki;
399 VAR *v;
400 int left, i;
401 const char *p;
402
403 if (mode == WIDTHMODE)
404 return;
405
406 ki = arg;
407 v = ve->var;
408 if (ve->next != NULL || termwidth != UNLIMITED) {
409 if (ve->next == NULL) {
410 left = termwidth - (totwidth - v->width);
411 if (left < 1) /* already wrapped, just use std width */
412 left = v->width;
413 } else
414 left = v->width;
415 } else
416 left = -1;
417
418 if (ki->p_ngroups == 0) {
419 fmt_putc('-', &left);
420 return;
421 }
422
423 for (i = 0; i < ki->p_ngroups; i++) {
424 if (i)
425 fmt_putc(' ', &left);
426 for (p = group_from_gid(ki->p_groups[i], 0); *p; p++)
427 fmt_putc(*p, &left);
428 }
429
430 if (ve->next && left > 0)
431 printf("%*s", left, "");
432 }
433
434 void
435 ucomm(arg, ve, mode)
436 void *arg;
437 VARENT *ve;
438 int mode;
439 {
440 struct kinfo_proc2 *k;
441 VAR *v;
442
443 k = arg;
444 v = ve->var;
445 strprintorsetwidth(v, k->p_comm, mode);
446 }
447
448 void
449 logname(arg, ve, mode)
450 void *arg;
451 VARENT *ve;
452 int mode;
453 {
454 struct kinfo_proc2 *k;
455 VAR *v;
456
457 k = arg;
458 v = ve->var;
459 strprintorsetwidth(v, k->p_login, mode);
460 }
461
462 void
463 state(arg, ve, mode)
464 void *arg;
465 VARENT *ve;
466 int mode;
467 {
468 struct kinfo_proc2 *k;
469 int flag, is_zombie;
470 char *cp;
471 VAR *v;
472 char buf[16];
473
474 k = arg;
475 is_zombie = 0;
476 v = ve->var;
477 flag = k->p_flag;
478 cp = buf;
479
480 switch (k->p_stat) {
481
482 case LSSTOP:
483 *cp = 'T';
484 break;
485
486 case LSSLEEP:
487 if (flag & L_SINTR) /* interruptable (long) */
488 *cp = k->p_slptime >= maxslp ? 'I' : 'S';
489 else
490 *cp = 'D';
491 break;
492
493 case LSRUN:
494 case LSIDL:
495 case LSONPROC:
496 *cp = 'R';
497 break;
498
499 case LSZOMB:
500 case LSDEAD:
501 *cp = 'Z';
502 is_zombie = 1;
503 break;
504
505 case LSSUSPENDED:
506 *cp = 'U';
507 break;
508
509 default:
510 *cp = '?';
511 }
512 cp++;
513 if (flag & L_INMEM) {
514 } else
515 *cp++ = 'W';
516 if (k->p_nice < NZERO)
517 *cp++ = '<';
518 else if (k->p_nice > NZERO)
519 *cp++ = 'N';
520 if (flag & P_TRACED)
521 *cp++ = 'X';
522 if (flag & P_SYSTRACE)
523 *cp++ = 'x';
524 if (flag & P_WEXIT && !is_zombie)
525 *cp++ = 'E';
526 if (flag & P_PPWAIT)
527 *cp++ = 'V';
528 if (flag & P_SYSTEM)
529 *cp++ = 'K';
530 /* system process might have this too, don't need to double up */
531 else if (k->p_holdcnt)
532 *cp++ = 'L';
533 if (k->p_eflag & EPROC_SLEADER)
534 *cp++ = 's';
535 if (flag & P_SA)
536 *cp++ = 'a';
537 else if (k->p_nlwps > 1)
538 *cp++ = 'l';
539 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
540 *cp++ = '+';
541 *cp = '\0';
542 strprintorsetwidth(v, buf, mode);
543 }
544
545 void
546 lstate(arg, ve, mode)
547 void *arg;
548 VARENT *ve;
549 int mode;
550 {
551 struct kinfo_lwp *k;
552 int flag, is_zombie;
553 char *cp;
554 VAR *v;
555 char buf[16];
556
557 k = arg;
558 is_zombie = 0;
559 v = ve->var;
560 flag = k->l_flag;
561 cp = buf;
562
563 switch (k->l_stat) {
564
565 case LSSTOP:
566 *cp = 'T';
567 break;
568
569 case LSSLEEP:
570 if (flag & L_SINTR) /* interuptable (long) */
571 *cp = k->l_slptime >= maxslp ? 'I' : 'S';
572 else
573 *cp = 'D';
574 break;
575
576 case LSRUN:
577 case LSIDL:
578 case LSONPROC:
579 *cp = 'R';
580 break;
581
582 case LSZOMB:
583 case LSDEAD:
584 *cp = 'Z';
585 is_zombie = 1;
586 break;
587
588 case LSSUSPENDED:
589 *cp = 'U';
590 break;
591
592 default:
593 *cp = '?';
594 }
595 cp++;
596 if (flag & L_INMEM) {
597 } else
598 *cp++ = 'W';
599 if (k->l_holdcnt)
600 *cp++ = 'L';
601 if (flag & L_DETACHED)
602 *cp++ = '-';
603 *cp = '\0';
604 strprintorsetwidth(v, buf, mode);
605 }
606
607 void
608 pnice(arg, ve, mode)
609 void *arg;
610 VARENT *ve;
611 int mode;
612 {
613 struct kinfo_proc2 *k;
614 VAR *v;
615
616 k = arg;
617 v = ve->var;
618 intprintorsetwidth(v, k->p_nice - NZERO, mode);
619 }
620
621 void
622 pri(arg, ve, mode)
623 void *arg;
624 VARENT *ve;
625 int mode;
626 {
627 struct kinfo_lwp *l;
628 VAR *v;
629
630 l = arg;
631 v = ve->var;
632 intprintorsetwidth(v, l->l_priority - PZERO, mode);
633 }
634
635 void
636 uname(arg, ve, mode)
637 void *arg;
638 VARENT *ve;
639 int mode;
640 {
641 struct kinfo_proc2 *k;
642 VAR *v;
643
644 k = arg;
645 v = ve->var;
646 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
647 }
648
649 void
650 runame(arg, ve, mode)
651 void *arg;
652 VARENT *ve;
653 int mode;
654 {
655 struct kinfo_proc2 *k;
656 VAR *v;
657
658 k = arg;
659 v = ve->var;
660 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
661 }
662
663 void
664 svuname(arg, ve, mode)
665 void *arg;
666 VARENT *ve;
667 int mode;
668 {
669 struct kinfo_proc2 *k;
670 VAR *v;
671
672 k = arg;
673 v = ve->var;
674 strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
675 }
676
677 void
678 gname(arg, ve, mode)
679 void *arg;
680 VARENT *ve;
681 int mode;
682 {
683 struct kinfo_proc2 *k;
684 VAR *v;
685
686 k = arg;
687 v = ve->var;
688 strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
689 }
690
691 void
692 rgname(arg, ve, mode)
693 void *arg;
694 VARENT *ve;
695 int mode;
696 {
697 struct kinfo_proc2 *k;
698 VAR *v;
699
700 k = arg;
701 v = ve->var;
702 strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
703 }
704
705 void
706 svgname(arg, ve, mode)
707 void *arg;
708 VARENT *ve;
709 int mode;
710 {
711 struct kinfo_proc2 *k;
712 VAR *v;
713
714 k = arg;
715 v = ve->var;
716 strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
717 }
718
719 void
720 tdev(arg, ve, mode)
721 void *arg;
722 VARENT *ve;
723 int mode;
724 {
725 struct kinfo_proc2 *k;
726 VAR *v;
727 dev_t dev;
728 char buff[16];
729
730 k = arg;
731 v = ve->var;
732 dev = k->p_tdev;
733 if (dev == NODEV) {
734 /*
735 * Minimum width is width of header - we don't
736 * need to check it every time.
737 */
738 if (mode == PRINTMODE)
739 (void)printf("%*s", v->width, "??");
740 } else {
741 (void)snprintf(buff, sizeof(buff),
742 "%d/%d", major(dev), minor(dev));
743 strprintorsetwidth(v, buff, mode);
744 }
745 }
746
747 void
748 tname(arg, ve, mode)
749 void *arg;
750 VARENT *ve;
751 int mode;
752 {
753 struct kinfo_proc2 *k;
754 VAR *v;
755 dev_t dev;
756 const char *ttname;
757 int noctty;
758
759 k = arg;
760 v = ve->var;
761 dev = k->p_tdev;
762 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
763 /*
764 * Minimum width is width of header - we don't
765 * need to check it every time.
766 */
767 if (mode == PRINTMODE)
768 (void)printf("%-*s", v->width, "??");
769 } else {
770 if (strncmp(ttname, "tty", 3) == 0 ||
771 strncmp(ttname, "dty", 3) == 0)
772 ttname += 3;
773 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
774 if (mode == WIDTHMODE) {
775 int fmtlen;
776
777 fmtlen = strlen(ttname) + noctty;
778 if (v->width < fmtlen)
779 v->width = fmtlen;
780 } else {
781 if (noctty)
782 printf("%-*s-", v->width - 1, ttname);
783 else
784 printf("%-*s", v->width, ttname);
785 }
786 }
787 }
788
789 void
790 longtname(arg, ve, mode)
791 void *arg;
792 VARENT *ve;
793 int mode;
794 {
795 struct kinfo_proc2 *k;
796 VAR *v;
797 dev_t dev;
798 const char *ttname;
799
800 k = arg;
801 v = ve->var;
802 dev = k->p_tdev;
803 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
804 /*
805 * Minimum width is width of header - we don't
806 * need to check it every time.
807 */
808 if (mode == PRINTMODE)
809 (void)printf("%-*s", v->width, "??");
810 }
811 else {
812 strprintorsetwidth(v, ttname, mode);
813 }
814 }
815
816 void
817 started(arg, ve, mode)
818 void *arg;
819 VARENT *ve;
820 int mode;
821 {
822 struct kinfo_proc2 *k;
823 VAR *v;
824 static time_t now;
825 time_t startt;
826 struct tm *tp;
827 char buf[100], *cp;
828
829 k = arg;
830 v = ve->var;
831 if (!k->p_uvalid) {
832 if (mode == PRINTMODE)
833 (void)printf("%*s", v->width, "-");
834 return;
835 }
836
837 startt = k->p_ustart_sec;
838 tp = localtime(&startt);
839 if (!now)
840 (void)time(&now);
841 if (now - k->p_ustart_sec < SECSPERDAY)
842 /* I *hate* SCCS... */
843 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
844 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
845 /* I *hate* SCCS... */
846 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
847 else
848 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
849 /* %e and %l can start with a space. */
850 cp = buf;
851 if (*cp == ' ')
852 cp++;
853 strprintorsetwidth(v, cp, mode);
854 }
855
856 void
857 lstarted(arg, ve, mode)
858 void *arg;
859 VARENT *ve;
860 int mode;
861 {
862 struct kinfo_proc2 *k;
863 VAR *v;
864 time_t startt;
865 char buf[100];
866
867 k = arg;
868 v = ve->var;
869 if (!k->p_uvalid) {
870 /*
871 * Minimum width is less than header - we don't
872 * need to check it every time.
873 */
874 if (mode == PRINTMODE)
875 (void)printf("%*s", v->width, "-");
876 return;
877 }
878 startt = k->p_ustart_sec;
879
880 /* assume all times are the same length */
881 if (mode != WIDTHMODE || v->width == 0) {
882 (void)strftime(buf, sizeof(buf) -1, "%c",
883 localtime(&startt));
884 strprintorsetwidth(v, buf, mode);
885 }
886 }
887
888 void
889 wchan(arg, ve, mode)
890 void *arg;
891 VARENT *ve;
892 int mode;
893 {
894 struct kinfo_lwp *l;
895 VAR *v;
896 char *buf;
897
898 l = arg;
899 v = ve->var;
900 if (l->l_wchan) {
901 if (l->l_wmesg) {
902 strprintorsetwidth(v, l->l_wmesg, mode);
903 v->width = min(v->width, WMESGLEN);
904 } else {
905 (void)asprintf(&buf, "%-*llx", v->width,
906 (long long)l->l_wchan);
907 if (buf == NULL)
908 err(1, "%s", "");
909 strprintorsetwidth(v, buf, mode);
910 v->width = min(v->width, WMESGLEN);
911 free(buf);
912 }
913 } else {
914 if (mode == PRINTMODE)
915 (void)printf("%-*s", v->width, "-");
916 }
917 }
918
919 #define pgtok(a) (((a)*getpagesize())/1024)
920
921 void
922 vsize(arg, ve, mode)
923 void *arg;
924 VARENT *ve;
925 int mode;
926 {
927 struct kinfo_proc2 *k;
928 VAR *v;
929
930 k = arg;
931 v = ve->var;
932 intprintorsetwidth(v,
933 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
934 }
935
936 void
937 rssize(arg, ve, mode)
938 void *arg;
939 VARENT *ve;
940 int mode;
941 {
942 struct kinfo_proc2 *k;
943 VAR *v;
944
945 k = arg;
946 v = ve->var;
947 /* XXX don't have info about shared */
948 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
949 }
950
951 void
952 p_rssize(arg, ve, mode) /* doesn't account for text */
953 void *arg;
954 VARENT *ve;
955 int mode;
956 {
957 struct kinfo_proc2 *k;
958 VAR *v;
959
960 k = arg;
961 v = ve->var;
962 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
963 }
964
965 void
966 cputime(arg, ve, mode)
967 void *arg;
968 VARENT *ve;
969 int mode;
970 {
971 struct kinfo_proc2 *k;
972 VAR *v;
973 int32_t secs;
974 int32_t psecs; /* "parts" of a second. first micro, then centi */
975 int fmtlen;
976
977 k = arg;
978 v = ve->var;
979 if (P_ZOMBIE(k) || k->p_uvalid == 0) {
980 secs = 0;
981 psecs = 0;
982 } else {
983 /*
984 * This counts time spent handling interrupts. We could
985 * fix this, but it is not 100% trivial (and interrupt
986 * time fractions only work on the sparc anyway). XXX
987 */
988 secs = k->p_rtime_sec;
989 psecs = k->p_rtime_usec;
990 if (sumrusage) {
991 secs += k->p_uctime_sec;
992 psecs += k->p_uctime_usec;
993 }
994 /*
995 * round and scale to 100's
996 */
997 psecs = (psecs + 5000) / 10000;
998 secs += psecs / 100;
999 psecs = psecs % 100;
1000 }
1001 if (mode == WIDTHMODE) {
1002 /*
1003 * Ugg, this is the only field where a value of 0 longer
1004 * than the column title, and log10(0) isn't good enough.
1005 * Use SECSPERMIN, because secs is divided by that when
1006 * passed to log10().
1007 */
1008 if (secs == 0 && v->longestp == 0)
1009 secs = SECSPERMIN;
1010 if (secs > v->longestp) {
1011 /* "+6" for the "%02ld.%02ld" in the printf() below */
1012 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
1013 v->longestp = secs;
1014 if (fmtlen > v->width)
1015 v->width = fmtlen;
1016 }
1017 } else {
1018 printf("%*ld:%02ld.%02ld", v->width - 6, (long)(secs / SECSPERMIN),
1019 (long)(secs % SECSPERMIN), (long)psecs);
1020 }
1021 }
1022
1023 double
1024 getpcpu(k)
1025 struct kinfo_proc2 *k;
1026 {
1027 static int failure;
1028
1029 if (!nlistread)
1030 failure = (kd) ? donlist() : 1;
1031 if (failure)
1032 return (0.0);
1033
1034 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
1035
1036 /* XXX - I don't like this */
1037 if (k->p_swtime == 0 || (k->p_flag & L_INMEM) == 0 ||
1038 k->p_stat == SZOMB || k->p_stat == SDEAD)
1039 return (0.0);
1040 if (rawcpu)
1041 return (100.0 * fxtofl(k->p_pctcpu));
1042 return (100.0 * fxtofl(k->p_pctcpu) /
1043 (1.0 - exp(k->p_swtime * log(ccpu))));
1044 }
1045
1046 void
1047 pcpu(arg, ve, mode)
1048 void *arg;
1049 VARENT *ve;
1050 int mode;
1051 {
1052 struct kinfo_proc2 *k;
1053 VAR *v;
1054
1055 k = arg;
1056 v = ve->var;
1057 doubleprintorsetwidth(v, getpcpu(k), 1, mode);
1058 }
1059
1060 double
1061 getpmem(k)
1062 struct kinfo_proc2 *k;
1063 {
1064 static int failure;
1065 double fracmem;
1066 int szptudot;
1067
1068 if (!nlistread)
1069 failure = (kd) ? donlist() : 1;
1070 if (failure)
1071 return (0.0);
1072
1073 if ((k->p_flag & L_INMEM) == 0)
1074 return (0.0);
1075 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
1076 szptudot = uspace/getpagesize();
1077 /* XXX don't have info about shared */
1078 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
1079 return (100.0 * fracmem);
1080 }
1081
1082 void
1083 pmem(arg, ve, mode)
1084 void *arg;
1085 VARENT *ve;
1086 int mode;
1087 {
1088 struct kinfo_proc2 *k;
1089 VAR *v;
1090
1091 k = arg;
1092 v = ve->var;
1093 doubleprintorsetwidth(v, getpmem(k), 1, mode);
1094 }
1095
1096 void
1097 pagein(arg, ve, mode)
1098 void *arg;
1099 VARENT *ve;
1100 int mode;
1101 {
1102 struct kinfo_proc2 *k;
1103 VAR *v;
1104
1105 k = arg;
1106 v = ve->var;
1107 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
1108 }
1109
1110 void
1111 maxrss(arg, ve, mode)
1112 void *arg;
1113 VARENT *ve;
1114 int mode;
1115 {
1116 VAR *v;
1117
1118 v = ve->var;
1119 /* No need to check width! */
1120 if (mode == PRINTMODE)
1121 (void)printf("%*s", v->width, "-");
1122 }
1123
1124 void
1125 tsize(arg, ve, mode)
1126 void *arg;
1127 VARENT *ve;
1128 int mode;
1129 {
1130 struct kinfo_proc2 *k;
1131 VAR *v;
1132
1133 k = arg;
1134 v = ve->var;
1135 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
1136 }
1137
1138 /*
1139 * Generic output routines. Print fields from various prototype
1140 * structures.
1141 */
1142 static void
1143 printval(bp, v, mode)
1144 void *bp;
1145 VAR *v;
1146 int mode;
1147 {
1148 static char ofmt[32] = "%";
1149 int width, vok, fmtlen;
1150 char *fcp, *cp, *obuf;
1151 enum type type;
1152 long long val;
1153 unsigned long long uval;
1154
1155 /*
1156 * Note that the "INF127" check is nonsensical for types
1157 * that are or can be signed.
1158 */
1159 #define GET(type) (*(type *)bp)
1160 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
1161
1162 #define VSIGN 1
1163 #define VUNSIGN 2
1164 #define VPTR 3
1165
1166 if (mode == WIDTHMODE) {
1167 vok = 0;
1168 switch (v->type) {
1169 case CHAR:
1170 val = GET(char);
1171 vok = VSIGN;
1172 break;
1173 case UCHAR:
1174 uval = CHK_INF127(GET(u_char));
1175 vok = VUNSIGN;
1176 break;
1177 case SHORT:
1178 val = GET(short);
1179 vok = VSIGN;
1180 break;
1181 case USHORT:
1182 uval = CHK_INF127(GET(u_short));
1183 vok = VUNSIGN;
1184 break;
1185 case INT32:
1186 val = GET(int32_t);
1187 vok = VSIGN;
1188 break;
1189 case INT:
1190 val = GET(int);
1191 vok = VSIGN;
1192 break;
1193 case UINT:
1194 case UINT32:
1195 uval = CHK_INF127(GET(u_int));
1196 vok = VUNSIGN;
1197 break;
1198 case LONG:
1199 val = GET(long);
1200 vok = VSIGN;
1201 break;
1202 case ULONG:
1203 uval = CHK_INF127(GET(u_long));
1204 vok = VUNSIGN;
1205 break;
1206 case KPTR:
1207 uval = (unsigned long long)GET(u_int64_t);
1208 vok = VPTR;
1209 break;
1210 case KPTR24:
1211 uval = (unsigned long long)GET(u_int64_t);
1212 uval &= 0xffffff;
1213 vok = VPTR;
1214 break;
1215 case INT64:
1216 val = (long long)GET(int64_t);
1217 vok = VSIGN;
1218 break;
1219 case UINT64:
1220 uval = (unsigned long long)CHK_INF127(GET(u_int64_t));
1221 vok = VUNSIGN;
1222 break;
1223
1224 default:
1225 /* nothing... */;
1226 }
1227 switch (vok) {
1228 case VSIGN:
1229 if (val < 0 && val < v->longestn) {
1230 fmtlen = (int)log10((double)-val) + 2;
1231 v->longestn = val;
1232 if (fmtlen > v->width)
1233 v->width = fmtlen;
1234 } else if (val > 0 && val > v->longestp) {
1235 fmtlen = (int)log10((double)val) + 1;
1236 v->longestp = val;
1237 if (fmtlen > v->width)
1238 v->width = fmtlen;
1239 }
1240 return;
1241 case VUNSIGN:
1242 if (uval > v->longestu) {
1243 fmtlen = (int)log10((double)uval) + 1;
1244 v->longestu = uval;
1245 v->width = fmtlen;
1246 }
1247 return;
1248 case VPTR:
1249 fmtlen = 0;
1250 while (uval > 0) {
1251 uval >>= 4;
1252 fmtlen++;
1253 }
1254 if (fmtlen > v->width)
1255 v->width = fmtlen;
1256 return;
1257 }
1258 }
1259
1260 width = v->width;
1261 cp = ofmt + 1;
1262 fcp = v->fmt;
1263 if (v->flag & LJUST)
1264 *cp++ = '-';
1265 *cp++ = '*';
1266 while ((*cp++ = *fcp++) != '\0')
1267 continue;
1268
1269 switch (v->type) {
1270 case INT32:
1271 if (sizeof(int32_t) == sizeof(int))
1272 type = INT;
1273 else if (sizeof(int32_t) == sizeof(long))
1274 type = LONG;
1275 else
1276 errx(1, "unknown conversion for type %d", v->type);
1277 break;
1278 case UINT32:
1279 if (sizeof(u_int32_t) == sizeof(u_int))
1280 type = UINT;
1281 else if (sizeof(u_int32_t) == sizeof(u_long))
1282 type = ULONG;
1283 else
1284 errx(1, "unknown conversion for type %d", v->type);
1285 break;
1286 default:
1287 type = v->type;
1288 break;
1289 }
1290
1291 switch (type) {
1292 case CHAR:
1293 (void)printf(ofmt, width, GET(char));
1294 return;
1295 case UCHAR:
1296 (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1297 return;
1298 case SHORT:
1299 (void)printf(ofmt, width, GET(short));
1300 return;
1301 case USHORT:
1302 (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1303 return;
1304 case INT:
1305 (void)printf(ofmt, width, GET(int));
1306 return;
1307 case UINT:
1308 (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1309 return;
1310 case LONG:
1311 (void)printf(ofmt, width, GET(long));
1312 return;
1313 case ULONG:
1314 (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1315 return;
1316 case KPTR:
1317 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t));
1318 return;
1319 case KPTR24:
1320 (void)printf(ofmt, width,
1321 (unsigned long long)GET(u_int64_t) & 0xffffff);
1322 return;
1323 case SIGLIST:
1324 {
1325 sigset_t *s = (sigset_t *)(void *)bp;
1326 size_t i;
1327 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
1328 char buf[SIGSETSIZE * 8 + 1];
1329
1330 for (i = 0; i < SIGSETSIZE; i++)
1331 (void)snprintf(&buf[i * 8], 9, "%.8x",
1332 s->__bits[(SIGSETSIZE - 1) - i]);
1333
1334 /* Skip leading zeroes */
1335 for (i = 0; buf[i]; i++)
1336 if (buf[i] != '0')
1337 break;
1338
1339 if (buf[i] == '\0')
1340 i--;
1341 (void)asprintf(&obuf, ofmt, width, &buf[i]);
1342 }
1343 break;
1344 case INT64:
1345 (void)printf(ofmt, width, (long long)GET(int64_t));
1346 return;
1347 case UINT64:
1348 (void)printf(ofmt, width, (unsigned long long)CHK_INF127(GET(u_int64_t)));
1349 return;
1350 default:
1351 errx(1, "unknown type %d", v->type);
1352 }
1353 if (obuf == NULL)
1354 err(1, "%s", "");
1355 if (mode == WIDTHMODE) {
1356 /* Skip leading spaces. */
1357 cp = strrchr(obuf, ' ');
1358 if (cp == NULL)
1359 cp = obuf;
1360 else
1361 cp++; /* skip last space */
1362 }
1363 else
1364 cp = obuf;
1365 strprintorsetwidth(v, cp, mode);
1366 free(obuf);
1367 #undef GET
1368 #undef CHK_INF127
1369 }
1370
1371 void
1372 pvar(arg, ve, mode)
1373 void *arg;
1374 VARENT *ve;
1375 int mode;
1376 {
1377 VAR *v;
1378
1379 v = ve->var;
1380 printval((char *)arg + v->off, v, mode);
1381 }
1382