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