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