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