print.c revision 1.89 1 /* $NetBSD: print.c,v 1.89 2004/03/27 14:55:24 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.89 2004/03/27 14:55:24 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 printed_something = 0;
884 fmtlen = v->width;
885
886 if (days > 0) {
887 (void)printf("%*d", fmtlen - 9, days);
888 printed_something = 1;
889 } else if (fmtlen > 9) {
890 (void)printf("%*s", fmtlen - 9, "");
891 }
892 if (fmtlen > 9)
893 fmtlen = 9;
894
895 if (printed_something) {
896 (void)printf("-%.*d", fmtlen - 7, hours);
897 printed_something = 1;
898 } else if (hours > 0) {
899 (void)printf("%*d", fmtlen - 6, hours);
900 printed_something = 1;
901 } else if (fmtlen > 6) {
902 (void)printf("%*s", fmtlen - 6, "");
903 }
904 if (fmtlen > 6)
905 fmtlen = 6;
906
907 /* Don't need to set fmtlen or printed_something any more... */
908 if (printed_something) {
909 (void)printf(":%.*d", fmtlen - 4, mins);
910 } else if (mins > 0) {
911 (void)printf("%*d", fmtlen - 3, mins);
912 } else if (fmtlen > 3) {
913 (void)printf("%*s", fmtlen - 3, "0");
914 }
915
916 (void)printf(":%.2d", secs);
917 }
918 }
919
920 void
921 wchan(void *arg, VARENT *ve, int mode)
922 {
923 struct kinfo_lwp *l;
924 VAR *v;
925 char *buf;
926
927 l = arg;
928 v = ve->var;
929 if (l->l_wchan) {
930 if (l->l_wmesg) {
931 strprintorsetwidth(v, l->l_wmesg, mode);
932 v->width = min(v->width, KI_WMESGLEN);
933 } else {
934 (void)asprintf(&buf, "%-*" PRIx64, v->width,
935 l->l_wchan);
936 if (buf == NULL)
937 err(1, "%s", "");
938 strprintorsetwidth(v, buf, mode);
939 v->width = min(v->width, KI_WMESGLEN);
940 free(buf);
941 }
942 } else {
943 if (mode == PRINTMODE)
944 (void)printf("%-*s", v->width, "-");
945 }
946 }
947
948 #define pgtok(a) (((a)*getpagesize())/1024)
949
950 void
951 vsize(void *arg, VARENT *ve, int mode)
952 {
953 struct kinfo_proc2 *k;
954 VAR *v;
955
956 k = arg;
957 v = ve->var;
958 intprintorsetwidth(v,
959 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
960 }
961
962 void
963 rssize(void *arg, VARENT *ve, int mode)
964 {
965 struct kinfo_proc2 *k;
966 VAR *v;
967
968 k = arg;
969 v = ve->var;
970 /* XXX don't have info about shared */
971 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
972 }
973
974 void
975 p_rssize(void *arg, VARENT *ve, int mode) /* doesn't account for text */
976 {
977 struct kinfo_proc2 *k;
978 VAR *v;
979
980 k = arg;
981 v = ve->var;
982 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
983 }
984
985 void
986 cputime(void *arg, VARENT *ve, int mode)
987 {
988 struct kinfo_proc2 *k;
989 VAR *v;
990 int32_t secs;
991 int32_t psecs; /* "parts" of a second. first micro, then centi */
992 int fmtlen;
993
994 k = arg;
995 v = ve->var;
996 if (P_ZOMBIE(k) || k->p_uvalid == 0) {
997 secs = 0;
998 psecs = 0;
999 } else {
1000 /*
1001 * This counts time spent handling interrupts. We could
1002 * fix this, but it is not 100% trivial (and interrupt
1003 * time fractions only work on the sparc anyway). XXX
1004 */
1005 secs = k->p_rtime_sec;
1006 psecs = k->p_rtime_usec;
1007 if (sumrusage) {
1008 secs += k->p_uctime_sec;
1009 psecs += k->p_uctime_usec;
1010 }
1011 /*
1012 * round and scale to 100's
1013 */
1014 psecs = (psecs + 5000) / 10000;
1015 secs += psecs / 100;
1016 psecs = psecs % 100;
1017 }
1018 if (mode == WIDTHMODE) {
1019 /*
1020 * Ugg, this is the only field where a value of 0 is longer
1021 * than the column title.
1022 * Use SECSPERMIN, because secs is divided by that when
1023 * passed to iwidth().
1024 */
1025 if (secs == 0)
1026 secs = SECSPERMIN;
1027
1028 if (secs > v->longestp) {
1029 v->longestp = secs;
1030 /* "+6" for the ":%02ld.%02ld" in the printf() below */
1031 fmtlen = iwidth(secs / SECSPERMIN) + 6;
1032 if (fmtlen > v->width)
1033 v->width = fmtlen;
1034 }
1035 } else {
1036 (void)printf("%*ld:%02ld.%02ld", v->width - 6,
1037 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
1038 (long)psecs);
1039 }
1040 }
1041
1042 double
1043 getpcpu(k)
1044 struct kinfo_proc2 *k;
1045 {
1046 static int failure;
1047
1048 if (!nlistread)
1049 failure = (kd) ? donlist() : 1;
1050 if (failure)
1051 return (0.0);
1052
1053 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
1054
1055 /* XXX - I don't like this */
1056 if (k->p_swtime == 0 || (k->p_flag & L_INMEM) == 0 ||
1057 k->p_stat == SZOMB)
1058 return (0.0);
1059 if (rawcpu)
1060 return (100.0 * fxtofl(k->p_pctcpu));
1061 return (100.0 * fxtofl(k->p_pctcpu) /
1062 (1.0 - exp(k->p_swtime * log(ccpu))));
1063 }
1064
1065 void
1066 pcpu(void *arg, VARENT *ve, int mode)
1067 {
1068 struct kinfo_proc2 *k;
1069 VAR *v;
1070
1071 k = arg;
1072 v = ve->var;
1073 doubleprintorsetwidth(v, getpcpu(k), 1, mode);
1074 }
1075
1076 double
1077 getpmem(k)
1078 struct kinfo_proc2 *k;
1079 {
1080 static int failure;
1081 double fracmem;
1082 int szptudot;
1083
1084 if (!nlistread)
1085 failure = (kd) ? donlist() : 1;
1086 if (failure)
1087 return (0.0);
1088
1089 if ((k->p_flag & L_INMEM) == 0)
1090 return (0.0);
1091 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
1092 szptudot = uspace/getpagesize();
1093 /* XXX don't have info about shared */
1094 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
1095 return (100.0 * fracmem);
1096 }
1097
1098 void
1099 pmem(void *arg, VARENT *ve, int mode)
1100 {
1101 struct kinfo_proc2 *k;
1102 VAR *v;
1103
1104 k = arg;
1105 v = ve->var;
1106 doubleprintorsetwidth(v, getpmem(k), 1, mode);
1107 }
1108
1109 void
1110 pagein(void *arg, VARENT *ve, int mode)
1111 {
1112 struct kinfo_proc2 *k;
1113 VAR *v;
1114
1115 k = arg;
1116 v = ve->var;
1117 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
1118 }
1119
1120 void
1121 maxrss(void *arg, VARENT *ve, int mode)
1122 {
1123 VAR *v;
1124
1125 v = ve->var;
1126 /* No need to check width! */
1127 if (mode == PRINTMODE)
1128 (void)printf("%*s", v->width, "-");
1129 }
1130
1131 void
1132 tsize(void *arg, VARENT *ve, int mode)
1133 {
1134 struct kinfo_proc2 *k;
1135 VAR *v;
1136
1137 k = arg;
1138 v = ve->var;
1139 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
1140 }
1141
1142 /*
1143 * Generic output routines. Print fields from various prototype
1144 * structures.
1145 */
1146 static void
1147 printval(bp, v, mode)
1148 void *bp;
1149 VAR *v;
1150 int mode;
1151 {
1152 static char ofmt[32] = "%";
1153 int width, vok, fmtlen;
1154 char *fcp, *cp;
1155 int64_t val;
1156 u_int64_t uval;
1157
1158 /*
1159 * Note that the "INF127" check is nonsensical for types
1160 * that are or can be signed.
1161 */
1162 #define GET(type) (*(type *)bp)
1163 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
1164
1165 #define VSIGN 1
1166 #define VUNSIGN 2
1167 #define VPTR 3
1168
1169 if (mode == WIDTHMODE) {
1170 vok = 0;
1171 switch (v->type) {
1172 case CHAR:
1173 val = GET(char);
1174 vok = VSIGN;
1175 break;
1176 case UCHAR:
1177 uval = CHK_INF127(GET(u_char));
1178 vok = VUNSIGN;
1179 break;
1180 case SHORT:
1181 val = GET(short);
1182 vok = VSIGN;
1183 break;
1184 case USHORT:
1185 uval = CHK_INF127(GET(u_short));
1186 vok = VUNSIGN;
1187 break;
1188 case INT32:
1189 val = GET(int32_t);
1190 vok = VSIGN;
1191 break;
1192 case INT:
1193 val = GET(int);
1194 vok = VSIGN;
1195 break;
1196 case UINT:
1197 case UINT32:
1198 uval = CHK_INF127(GET(u_int));
1199 vok = VUNSIGN;
1200 break;
1201 case LONG:
1202 val = GET(long);
1203 vok = VSIGN;
1204 break;
1205 case ULONG:
1206 uval = CHK_INF127(GET(u_long));
1207 vok = VUNSIGN;
1208 break;
1209 case KPTR:
1210 uval = GET(u_int64_t);
1211 vok = VPTR;
1212 break;
1213 case KPTR24:
1214 uval = GET(u_int64_t);
1215 uval &= 0xffffff;
1216 vok = VPTR;
1217 break;
1218 case INT64:
1219 val = GET(int64_t);
1220 vok = VSIGN;
1221 break;
1222 case UINT64:
1223 uval = CHK_INF127(GET(u_int64_t));
1224 vok = VUNSIGN;
1225 break;
1226
1227 case SIGLIST:
1228 default:
1229 /* nothing... */;
1230 }
1231 switch (vok) {
1232 case VSIGN:
1233 if (val < 0 && val < v->longestn) {
1234 v->longestn = val;
1235 fmtlen = iwidth(-val) + 1;
1236 if (fmtlen > v->width)
1237 v->width = fmtlen;
1238 } else if (val > 0 && val > v->longestp) {
1239 v->longestp = val;
1240 fmtlen = iwidth(val);
1241 if (fmtlen > v->width)
1242 v->width = fmtlen;
1243 }
1244 return;
1245 case VUNSIGN:
1246 if (uval > v->longestu) {
1247 v->longestu = uval;
1248 v->width = iwidth(uval);
1249 }
1250 return;
1251 case VPTR:
1252 fmtlen = 0;
1253 while (uval > 0) {
1254 uval >>= 4;
1255 fmtlen++;
1256 }
1257 if (fmtlen > v->width)
1258 v->width = fmtlen;
1259 return;
1260 }
1261 }
1262
1263 width = v->width;
1264 cp = ofmt + 1;
1265 fcp = v->fmt;
1266 if (v->flag & LJUST)
1267 *cp++ = '-';
1268 *cp++ = '*';
1269 while ((*cp++ = *fcp++) != '\0')
1270 continue;
1271
1272 switch (v->type) {
1273 case CHAR:
1274 (void)printf(ofmt, width, GET(char));
1275 return;
1276 case UCHAR:
1277 (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1278 return;
1279 case SHORT:
1280 (void)printf(ofmt, width, GET(short));
1281 return;
1282 case USHORT:
1283 (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1284 return;
1285 case INT:
1286 (void)printf(ofmt, width, GET(int));
1287 return;
1288 case UINT:
1289 (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1290 return;
1291 case LONG:
1292 (void)printf(ofmt, width, GET(long));
1293 return;
1294 case ULONG:
1295 (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1296 return;
1297 case KPTR:
1298 (void)printf(ofmt, width, GET(u_int64_t));
1299 return;
1300 case KPTR24:
1301 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
1302 return;
1303 case INT32:
1304 (void)printf(ofmt, width, GET(int32_t));
1305 return;
1306 case UINT32:
1307 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
1308 return;
1309 case SIGLIST:
1310 {
1311 sigset_t *s = (sigset_t *)(void *)bp;
1312 size_t i;
1313 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
1314 char buf[SIGSETSIZE * 8 + 1];
1315
1316 for (i = 0; i < SIGSETSIZE; i++)
1317 (void)snprintf(&buf[i * 8], 9, "%.8x",
1318 s->__bits[(SIGSETSIZE - 1) - i]);
1319
1320 /* Skip leading zeroes */
1321 for (i = 0; buf[i] == '0'; i++)
1322 continue;
1323
1324 if (buf[i] == '\0')
1325 i--;
1326 strprintorsetwidth(v, buf + i, mode);
1327 #undef SIGSETSIZE
1328 }
1329 return;
1330 case INT64:
1331 (void)printf(ofmt, width, GET(int64_t));
1332 return;
1333 case UINT64:
1334 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
1335 return;
1336 default:
1337 errx(1, "unknown type %d", v->type);
1338 }
1339 #undef GET
1340 #undef CHK_INF127
1341 }
1342
1343 void
1344 pvar(void *arg, VARENT *ve, int mode)
1345 {
1346 VAR *v;
1347
1348 v = ve->var;
1349 if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) {
1350 if (mode == PRINTMODE)
1351 (void)printf("%*s", v->width, "-");
1352 return;
1353 }
1354
1355 (void)printval((char *)arg + v->off, v, mode);
1356 }
1357
1358 void
1359 putimeval(void *arg, VARENT *ve, int mode)
1360 {
1361 VAR *v = ve->var;
1362 struct kinfo_proc2 *k = arg;
1363 ulong secs = *(uint32_t *)((char *)arg + v->off);
1364 ulong usec = *(uint32_t *)((char *)arg + v->off + sizeof (uint32_t));
1365 int fmtlen;
1366
1367 if (!k->p_uvalid) {
1368 if (mode == PRINTMODE)
1369 (void)printf("%*s", v->width, "-");
1370 return;
1371 }
1372
1373 if (mode == WIDTHMODE) {
1374 if (secs == 0)
1375 /* non-zero so fmtlen is calculated at least once */
1376 secs = 1;
1377 if (secs > v->longestu) {
1378 v->longestu = secs;
1379 if (secs <= 999)
1380 /* sss.ssssss */
1381 fmtlen = iwidth(secs) + 6 + 1;
1382 else
1383 /* hh:mm:ss.ss */
1384 fmtlen = iwidth((secs + 1) / SECSPERHOUR)
1385 + 2 + 1 + 2 + 1 + 2 + 1;
1386 if (fmtlen > v->width)
1387 v->width = fmtlen;
1388 }
1389 return;
1390 }
1391
1392 if (secs < 999)
1393 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
1394 else {
1395 uint h, m;
1396 usec += 5000;
1397 if (usec >= 1000000) {
1398 usec -= 1000000;
1399 secs++;
1400 }
1401 m = secs / SECSPERMIN;
1402 secs -= m * SECSPERMIN;
1403 h = m / MINSPERHOUR;
1404 m -= h * MINSPERHOUR;
1405 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
1406 usec / 10000u );
1407 }
1408 }
1409