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