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