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