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