xref: /netbsd-src/bin/ps/print.c (revision 7cc2f76925f078d01ddc9e640a98f4ccfc9f8c3b)
1 /*	$NetBSD: print.c,v 1.57 2000/10/23 05:54:06 simonb Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Simon Burge.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1990, 1993, 1994
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *	This product includes software developed by the University of
54  *	California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  */
71 
72 #include <sys/cdefs.h>
73 #ifndef lint
74 #if 0
75 static char sccsid[] = "@(#)print.c	8.6 (Berkeley) 4/16/94";
76 #else
77 __RCSID("$NetBSD: print.c,v 1.57 2000/10/23 05:54:06 simonb Exp $");
78 #endif
79 #endif /* not lint */
80 
81 #include <sys/param.h>
82 #include <sys/time.h>
83 #include <sys/resource.h>
84 #include <sys/proc.h>
85 #include <sys/stat.h>
86 #include <sys/ucred.h>
87 #include <sys/sysctl.h>
88 
89 #include <err.h>
90 #include <kvm.h>
91 #include <math.h>
92 #include <nlist.h>
93 #include <pwd.h>
94 #include <stddef.h>
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <time.h>
99 #include <tzfile.h>
100 #include <unistd.h>
101 
102 #include "ps.h"
103 
104 static char *cmdpart __P((char *));
105 static void  printval __P((void *, VAR *, int));
106 static int   titlecmp __P((char *, char **));
107 
108 static void  doubleprintorsetwidth __P((VAR *, double, int, int));
109 static void  intprintorsetwidth __P((VAR *, int, int));
110 static void  strprintorsetwidth __P((VAR *, const char *, int));
111 
112 #define	min(a,b)	((a) <= (b) ? (a) : (b))
113 #define	max(a,b)	((a) >= (b) ? (a) : (b))
114 
115 static char *
116 cmdpart(arg0)
117 	char *arg0;
118 {
119 	char *cp;
120 
121 	return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
122 }
123 
124 void
125 printheader()
126 {
127 	int len;
128 	VAR *v;
129 	struct varent *vent;
130 	static int firsttime = 1;
131 
132 	for (vent = vhead; vent; vent = vent->next) {
133 		v = vent->var;
134 		if (firsttime) {
135 			len = strlen(v->header);
136 			if (len > v->width)
137 				v->width = len;
138 			totwidth += v->width + 1;	/* +1 for space */
139 		}
140 		if (v->flag & LJUST) {
141 			if (vent->next == NULL)	/* last one */
142 				(void)printf("%s", v->header);
143 			else
144 				(void)printf("%-*s", v->width,
145 				    v->header);
146 		} else
147 			(void)printf("%*s", v->width, v->header);
148 		if (vent->next != NULL)
149 			(void)putchar(' ');
150 	}
151 	(void)putchar('\n');
152 	if (firsttime) {
153 		firsttime = 0;
154 		totwidth--;	/* take off last space */
155 	}
156 }
157 
158 static int
159 titlecmp(name, argv)
160 	char *name;
161 	char **argv;
162 {
163 	char *title;
164 	int namelen;
165 
166 	if (argv == 0 || argv[0] == 0)
167 		return (1);
168 
169 	title = cmdpart(argv[0]);
170 
171 	if (!strcmp(name, title))
172 		return (0);
173 
174 	if (title[0] == '-' && !strcmp(name, title+1))
175 		return (0);
176 
177 	namelen = strlen(name);
178 
179 	if (argv[1] == 0 &&
180 	    !strncmp(name, title, namelen) &&
181 	    title[namelen + 0] == ':' &&
182 	    title[namelen + 1] == ' ')
183 		return (0);
184 
185 	return (1);
186 }
187 
188 static void
189 doubleprintorsetwidth(v, val, prec, mode)
190 	VAR *v;
191 	double val;
192 	int prec;
193 	int mode;
194 {
195 	int fmtlen;
196 
197 	if (mode == WIDTHMODE) {
198 		if (val < 0.0 && val < v->longestnd) {
199 			fmtlen = (int)log10(-val) + prec + 2;
200 			v->longestnd = val;
201 			if (fmtlen > v->width)
202 				v->width = fmtlen;
203 		} else if (val > 0.0 && val > v->longestpd) {
204 			fmtlen = (int)log10(val) + prec + 1;
205 			v->longestpd = val;
206 			if (fmtlen > v->width)
207 				v->width = fmtlen;
208 		}
209 	} else {
210 		printf("%*.*f", v->width, prec, val);
211 	}
212 }
213 
214 static void
215 intprintorsetwidth(v, val, mode)
216 	VAR *v;
217 	int val;
218 	int mode;
219 {
220 	int fmtlen;
221 
222 	if (mode == WIDTHMODE) {
223 		if (val < 0 && val < v->longestn) {
224 			fmtlen = (int)log10((double)-val) + 2;
225 			v->longestn = val;
226 			if (fmtlen > v->width)
227 				v->width = fmtlen;
228 		} else if (val > 0 && val > v->longestp) {
229 			fmtlen = (int)log10((double)val) + 1;
230 			v->longestp = val;
231 			if (fmtlen > v->width)
232 				v->width = fmtlen;
233 		}
234 	} else
235 		printf("%*d", v->width, val);
236 }
237 
238 static void
239 strprintorsetwidth(v, str, mode)
240 	VAR *v;
241 	const char *str;
242 {
243 	int len;
244 
245 	if (mode == WIDTHMODE) {
246 		len = strlen(str);
247 		if (len > v->width)
248 			v->width = len;
249 	} else {
250 		if (v->flag & LJUST)
251 			printf("%-*.*s", v->width, v->width, str);
252 		else
253 			printf("%*.*s", v->width, v->width, str);
254 	}
255 }
256 
257 void
258 command(ki, ve, mode)
259 	struct kinfo_proc2 *ki;
260 	VARENT *ve;
261 	int mode;
262 {
263 	VAR *v;
264 	int left;
265 	char **argv, **p, *name;
266 
267 	if (mode == WIDTHMODE)
268 		return;
269 
270 	v = ve->var;
271 	if (ve->next != NULL || termwidth != UNLIMITED) {
272 		if (ve->next == NULL) {
273 			left = termwidth - (totwidth - v->width);
274 			if (left < 1) /* already wrapped, just use std width */
275 				left = v->width;
276 		} else
277 			left = v->width;
278 	} else
279 		left = -1;
280 	if (needenv && kd) {
281 		argv = kvm_getenvv2(kd, ki, termwidth);
282 		if ((p = argv) != NULL) {
283 			while (*p) {
284 				fmt_puts(*p, &left);
285 				p++;
286 				fmt_putc(' ', &left);
287 			}
288 		}
289 	}
290 	if (needcomm) {
291 		name = ki->p_comm;
292 		if (!commandonly) {
293 			argv = NULL;
294 			if (!use_procfs)
295 				argv = kvm_getargv2(kd, ki, termwidth);
296 			else
297 				argv = procfs_getargv(ki, termwidth);
298 			if ((p = argv) != NULL) {
299 				while (*p) {
300 					fmt_puts(*p, &left);
301 					p++;
302 					fmt_putc(' ', &left);
303 				}
304 			}
305 			if (titlecmp(name, argv)) {
306 				fmt_putc('(', &left);
307 				fmt_puts(name, &left);
308 				fmt_putc(')', &left);
309 			}
310 			if (use_procfs && argv) {
311 				free(argv[0]);
312 				free(argv);
313 			}
314 		} else {
315 			fmt_puts(name, &left);
316 		}
317 	}
318 	if (ve->next && left > 0)
319 		printf("%*s", left, "");
320 }
321 
322 void
323 ucomm(k, ve, mode)
324 	struct kinfo_proc2 *k;
325 	VARENT *ve;
326 	int mode;
327 {
328 	VAR *v;
329 
330 	v = ve->var;
331 	strprintorsetwidth(v, k->p_comm, mode);
332 }
333 
334 void
335 logname(k, ve, mode)
336 	struct kinfo_proc2 *k;
337 	VARENT *ve;
338 	int mode;
339 {
340 	VAR *v;
341 
342 	v = ve->var;
343 	strprintorsetwidth(v, k->p_login, mode);
344 }
345 
346 void
347 state(k, ve, mode)
348 	struct kinfo_proc2 *k;
349 	VARENT *ve;
350 	int mode;
351 {
352 	int flag, is_zombie;
353 	char *cp;
354 	VAR *v;
355 	char buf[16];
356 
357 	is_zombie = 0;
358 	v = ve->var;
359 	flag = k->p_flag;
360 	cp = buf;
361 
362 	switch (k->p_stat) {
363 
364 	case SSTOP:
365 		*cp = 'T';
366 		break;
367 
368 	case SSLEEP:
369 		if (flag & P_SINTR)	/* interuptable (long) */
370 			*cp = k->p_slptime >= MAXSLP ? 'I' : 'S';
371 		else
372 			*cp = 'D';
373 		break;
374 
375 	case SRUN:
376 	case SIDL:
377 	case SONPROC:
378 		*cp = 'R';
379 		break;
380 
381 	case SZOMB:
382 	case SDEAD:
383 		*cp = 'Z';
384 		is_zombie = 1;
385 		break;
386 
387 	default:
388 		*cp = '?';
389 	}
390 	cp++;
391 	if (flag & P_INMEM) {
392 	} else
393 		*cp++ = 'W';
394 	if (k->p_nice < NZERO)
395 		*cp++ = '<';
396 	else if (k->p_nice > NZERO)
397 		*cp++ = 'N';
398 	if (flag & P_TRACED)
399 		*cp++ = 'X';
400 	if (flag & P_WEXIT && !is_zombie)
401 		*cp++ = 'E';
402 	if (flag & P_PPWAIT)
403 		*cp++ = 'V';
404 	if (flag & P_SYSTEM)
405 		*cp++ = 'K';
406 	/* system process might have this too, don't need to double up */
407 	else if (k->p_holdcnt)
408 		*cp++ = 'L';
409 	if (k->p_eflag & EPROC_SLEADER)
410 		*cp++ = 's';
411 	if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
412 		*cp++ = '+';
413 	*cp = '\0';
414 	strprintorsetwidth(v, buf, mode);
415 }
416 
417 void
418 pnice(k, ve, mode)
419 	struct kinfo_proc2 *k;
420 	VARENT *ve;
421 	int mode;
422 {
423 	VAR *v;
424 
425 	v = ve->var;
426 	intprintorsetwidth(v, k->p_nice - NZERO, mode);
427 }
428 
429 void
430 pri(k, ve, mode)
431 	struct kinfo_proc2 *k;
432 	VARENT *ve;
433 	int mode;
434 {
435 	VAR *v;
436 
437 	v = ve->var;
438 	intprintorsetwidth(v, k->p_priority - PZERO, mode);
439 }
440 
441 void
442 uname(k, ve, mode)
443 	struct kinfo_proc2 *k;
444 	VARENT *ve;
445 	int mode;
446 {
447 	VAR *v;
448 
449 	v = ve->var;
450 	strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
451 }
452 
453 void
454 runame(k, ve, mode)
455 	struct kinfo_proc2 *k;
456 	VARENT *ve;
457 	int mode;
458 {
459 	VAR *v;
460 
461 	v = ve->var;
462 	strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
463 }
464 
465 void
466 tdev(k, ve, mode)
467 	struct kinfo_proc2 *k;
468 	VARENT *ve;
469 	int mode;
470 {
471 	VAR *v;
472 	dev_t dev;
473 	char buff[16];
474 
475 	v = ve->var;
476 	dev = k->p_tdev;
477 	if (dev == NODEV) {
478 		/*
479 		 * Minimum width is width of header - we don't
480 		 * need to check it every time.
481 		 */
482 		if (mode == PRINTMODE)
483 			(void)printf("%*s", v->width, "??");
484 	} else {
485 		(void)snprintf(buff, sizeof(buff),
486 		    "%d/%d", major(dev), minor(dev));
487 		strprintorsetwidth(v, buff, mode);
488 	}
489 }
490 
491 void
492 tname(k, ve, mode)
493 	struct kinfo_proc2 *k;
494 	VARENT *ve;
495 	int mode;
496 {
497 	VAR *v;
498 	dev_t dev;
499 	const char *ttname;
500 	int noctty;
501 
502 	v = ve->var;
503 	dev = k->p_tdev;
504 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
505 		/*
506 		 * Minimum width is width of header - we don't
507 		 * need to check it every time.
508 		 */
509 		if (mode == PRINTMODE)
510 			(void)printf("%-*s", v->width, "??");
511 	} else {
512 		if (strncmp(ttname, "tty", 3) == 0 ||
513 		    strncmp(ttname, "dty", 3) == 0)
514 			ttname += 3;
515 		noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
516 		if (mode == WIDTHMODE) {
517 			int fmtlen;
518 
519 			fmtlen = strlen(ttname) + noctty;
520 			if (v->width < fmtlen)
521 				v->width = fmtlen;
522 		} else {
523 			if (noctty)
524 				printf("%-*s-", v->width - 1, ttname);
525 			else
526 				printf("%-*s", v->width, ttname);
527 		}
528 	}
529 }
530 
531 void
532 longtname(k, ve, mode)
533 	struct kinfo_proc2 *k;
534 	VARENT *ve;
535 	int mode;
536 {
537 	VAR *v;
538 	dev_t dev;
539 	const char *ttname;
540 
541 	v = ve->var;
542 	dev = k->p_tdev;
543 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
544 		/*
545 		 * Minimum width is width of header - we don't
546 		 * need to check it every time.
547 		 */
548 		if (mode == PRINTMODE)
549 			(void)printf("%-*s", v->width, "??");
550 	}
551 	else {
552 		strprintorsetwidth(v, ttname, mode);
553 	}
554 }
555 
556 void
557 started(k, ve, mode)
558 	struct kinfo_proc2 *k;
559 	VARENT *ve;
560 	int mode;
561 {
562 	VAR *v;
563 	static time_t now;
564 	time_t startt;
565 	struct tm *tp;
566 	char buf[100], *cp;
567 
568 	/*
569 	 * XXX: The maximum width of this field is the same as the header
570 	 *      "STARTED" for locales that have 3 letter abbreviated month
571 	 *      names and 2 letter am/pm descriptions.
572 	 */
573 	if (mode == WIDTHMODE)
574 		return;
575 
576 	v = ve->var;
577 	if (!k->p_uvalid) {
578 		if (mode == PRINTMODE)
579 			(void)printf("%*s", v->width, "-");
580 		return;
581 	}
582 
583 	startt = k->p_ustart_sec;
584 	tp = localtime(&startt);
585 	if (!now)
586 		(void)time(&now);
587 	if (now - k->p_ustart_sec < SECSPERDAY)
588 		/* I *hate* SCCS... */
589 		(void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
590 	else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
591 		/* I *hate* SCCS... */
592 		(void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
593 	else
594 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
595 	/* %e and %l can start with a space. */
596 	cp = buf;
597 	if (*cp == ' ')
598 		cp++;
599 	strprintorsetwidth(v, cp, mode);
600 }
601 
602 void
603 lstarted(k, ve, mode)
604 	struct kinfo_proc2 *k;
605 	VARENT *ve;
606 	int mode;
607 {
608 	VAR *v;
609 	time_t startt;
610 	char buf[100];
611 
612 	v = ve->var;
613 	if (!k->p_uvalid) {
614 		/*
615 		 * Minimum width is less than header - we don't
616 		 * need to check it every time.
617 		 */
618 		if (mode == PRINTMODE)
619 			(void)printf("%*s", v->width, "-");
620 		return;
621 	}
622 	startt = k->p_ustart_sec;
623 
624 	/* assume all times are the same length */
625 	if (mode != WIDTHMODE || v->width == 0) {
626 		(void)strftime(buf, sizeof(buf) -1, "%c",
627 		    localtime(&startt));
628 		strprintorsetwidth(v, buf, mode);
629 	}
630 }
631 
632 void
633 wchan(k, ve, mode)
634 	struct kinfo_proc2 *k;
635 	VARENT *ve;
636 	int mode;
637 {
638 	VAR *v;
639 	char *buf;
640 
641 	v = ve->var;
642 	if (k->p_wchan) {
643 		if (k->p_wmesg) {
644 			strprintorsetwidth(v, k->p_wmesg, mode);
645 			v->width = min(v->width, WMESGLEN);
646 		} else {
647 			(void)asprintf(&buf, "%-*llx", v->width,
648 			    (long long)k->p_wchan);
649 			if (buf == NULL)
650 				err(1, "%s", "");
651 			strprintorsetwidth(v, buf, mode);
652 			v->width = min(v->width, WMESGLEN);
653 			free(buf);
654 		}
655 	} else {
656 		if (mode == PRINTMODE)
657 			(void)printf("%-*s", v->width, "-");
658 	}
659 }
660 
661 #define pgtok(a)        (((a)*getpagesize())/1024)
662 
663 void
664 vsize(k, ve, mode)
665 	struct kinfo_proc2 *k;
666 	VARENT *ve;
667 	int mode;
668 {
669 	VAR *v;
670 
671 	v = ve->var;
672 	intprintorsetwidth(v,
673 	    pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
674 }
675 
676 void
677 rssize(k, ve, mode)
678 	struct kinfo_proc2 *k;
679 	VARENT *ve;
680 	int mode;
681 {
682 	VAR *v;
683 
684 	v = ve->var;
685 	/* XXX don't have info about shared */
686 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
687 }
688 
689 void
690 p_rssize(k, ve, mode)		/* doesn't account for text */
691 	struct kinfo_proc2 *k;
692 	VARENT *ve;
693 	int mode;
694 {
695 	VAR *v;
696 
697 	v = ve->var;
698 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
699 }
700 
701 void
702 cputime(k, ve, mode)
703 	struct kinfo_proc2 *k;
704 	VARENT *ve;
705 	int mode;
706 {
707 	VAR *v;
708 	long secs;
709 	long psecs;	/* "parts" of a second. first micro, then centi */
710 	int fmtlen;
711 
712 	v = ve->var;
713 	if (P_ZOMBIE(k) || k->p_uvalid == 0) {
714 		secs = 0;
715 		psecs = 0;
716 	} else {
717 		/*
718 		 * This counts time spent handling interrupts.  We could
719 		 * fix this, but it is not 100% trivial (and interrupt
720 		 * time fractions only work on the sparc anyway).	XXX
721 		 */
722 		secs = k->p_rtime_sec;
723 		psecs = k->p_rtime_usec;
724 		if (sumrusage) {
725 			secs += k->p_uctime_sec;
726 			psecs += k->p_uctime_usec;
727 		}
728 		/*
729 		 * round and scale to 100's
730 		 */
731 		psecs = (psecs + 5000) / 10000;
732 		secs += psecs / 100;
733 		psecs = psecs % 100;
734 	}
735 	if (mode == WIDTHMODE) {
736 		/*
737 		 * Ugg, this is the only field where a value of 0 longer
738 		 * than the column title, and log10(0) isn't good enough.
739 		 * Use SECSPERMIN, because secs is divided by that when
740 		 * passed to log10().
741 		 */
742 		if (secs == 0 && v->longestp == 0)
743 			secs = SECSPERMIN;
744 		if (secs > v->longestp) {
745 			/* "+6" for the "%02ld.%02ld" in the printf() below */
746 			fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
747 			v->longestp = secs;
748 			if (fmtlen > v->width)
749 				v->width = fmtlen;
750 		}
751 	} else {
752 		printf("%*ld:%02ld.%02ld", v->width - 6, secs / SECSPERMIN,
753 		    secs % SECSPERMIN, psecs);
754 	}
755 }
756 
757 double
758 getpcpu(k)
759 	struct kinfo_proc2 *k;
760 {
761 	static int failure;
762 
763 	if (!nlistread)
764 		failure = (kd) ? donlist() : 1;
765 	if (failure)
766 		return (0.0);
767 
768 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
769 
770 	/* XXX - I don't like this */
771 	if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 ||
772 	    k->p_stat == SZOMB || k->p_stat == SDEAD)
773 		return (0.0);
774 	if (rawcpu)
775 		return (100.0 * fxtofl(k->p_pctcpu));
776 	return (100.0 * fxtofl(k->p_pctcpu) /
777 		(1.0 - exp(k->p_swtime * log(ccpu))));
778 }
779 
780 void
781 pcpu(k, ve, mode)
782 	struct kinfo_proc2 *k;
783 	VARENT *ve;
784 	int mode;
785 {
786 	VAR *v;
787 
788 	v = ve->var;
789 	doubleprintorsetwidth(v, getpcpu(k), 1, mode);
790 }
791 
792 double
793 getpmem(k)
794 	struct kinfo_proc2 *k;
795 {
796 	static int failure;
797 	double fracmem;
798 	int szptudot;
799 
800 	if (!nlistread)
801 		failure = (kd) ? donlist() : 1;
802 	if (failure)
803 		return (0.0);
804 
805 	if ((k->p_flag & P_INMEM) == 0)
806 		return (0.0);
807 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
808 	szptudot = USPACE/getpagesize();
809 	/* XXX don't have info about shared */
810 	fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
811 	return (100.0 * fracmem);
812 }
813 
814 void
815 pmem(k, ve, mode)
816 	struct kinfo_proc2 *k;
817 	VARENT *ve;
818 	int mode;
819 {
820 	VAR *v;
821 
822 	v = ve->var;
823 	doubleprintorsetwidth(v, getpmem(k), 1, mode);
824 }
825 
826 void
827 pagein(k, ve, mode)
828 	struct kinfo_proc2 *k;
829 	VARENT *ve;
830 	int mode;
831 {
832 	VAR *v;
833 
834 	v = ve->var;
835 	intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
836 }
837 
838 void
839 maxrss(k, ve, mode)
840 	struct kinfo_proc2 *k;
841 	VARENT *ve;
842 	int mode;
843 {
844 	VAR *v;
845 
846 	v = ve->var;
847 	/* No need to check width! */
848 	if (mode == PRINTMODE)
849 		(void)printf("%*s", v->width, "-");
850 }
851 
852 void
853 tsize(k, ve, mode)
854 	struct kinfo_proc2 *k;
855 	VARENT *ve;
856 	int mode;
857 {
858 	VAR *v;
859 
860 	v = ve->var;
861 	intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
862 }
863 
864 /*
865  * Generic output routines.  Print fields from various prototype
866  * structures.
867  */
868 static void
869 printval(bp, v, mode)
870 	void *bp;
871 	VAR *v;
872 	int mode;
873 {
874 	static char ofmt[32] = "%";
875 	int width, vok, fmtlen;
876 	char *fcp, *cp, *obuf;
877 	enum type type;
878 	long long val;
879 	unsigned long long uval;
880 
881 	/*
882 	 * Note that the "INF127" check is nonsensical for types
883 	 * that are or can be signed.
884 	 */
885 #define	GET(type)		(*(type *)bp)
886 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
887 
888 #define	VSIGN	1
889 #define	VUNSIGN	2
890 #define	VPTR	3
891 
892 	if (mode == WIDTHMODE) {
893 		vok = 0;
894 		switch (v->type) {
895 		case CHAR:
896 			val = GET(char);
897 			vok = VSIGN;
898 			break;
899 		case UCHAR:
900 			uval = CHK_INF127(GET(u_char));
901 			vok = VUNSIGN;
902 			break;
903 		case SHORT:
904 			val = GET(short);
905 			vok = VSIGN;
906 			break;
907 		case USHORT:
908 			uval = CHK_INF127(GET(u_short));
909 			vok = VUNSIGN;
910 			break;
911 		case INT32:
912 			val = GET(int32_t);
913 			vok = VSIGN;
914 			break;
915 		case INT:
916 			val = GET(int);
917 			vok = VSIGN;
918 			break;
919 		case UINT:
920 		case UINT32:
921 			uval = CHK_INF127(GET(u_int));
922 			vok = VUNSIGN;
923 			break;
924 		case LONG:
925 			val = GET(long);
926 			vok = VSIGN;
927 			break;
928 		case ULONG:
929 			uval = CHK_INF127(GET(u_long));
930 			vok = VUNSIGN;
931 			break;
932 		case KPTR:
933 			uval = GET(u_long);
934 			vok = VPTR;
935 			break;
936 		case KPTR24:
937 			uval = GET(u_long) & 0xffffff;
938 			vok = VPTR;
939 			break;
940 		default:
941 			/* nothing... */;
942 		}
943 		switch (vok) {
944 		case VSIGN:
945 			if (val < 0  && val < v->longestn) {
946 				fmtlen = (int)log10((double)-val) + 2;
947 				v->longestn = val;
948 				if (fmtlen > v->width)
949 					v->width = fmtlen;
950 			} else if (val > 0 && val > v->longestp) {
951 				fmtlen = (int)log10((double)val) + 1;
952 				v->longestp = val;
953 				if (fmtlen > v->width)
954 					v->width = fmtlen;
955 			}
956 			return;
957 		case VUNSIGN:
958 			if (uval > v->longestu) {
959 				fmtlen = (int)log10((double)uval) + 1;
960 				v->longestu = uval;
961 				v->width = fmtlen;
962 			}
963 			return;
964 		case VPTR:
965 			fmtlen = 0;
966 			while (uval > 0) {
967 				uval >>= 4;
968 				fmtlen++;
969 			}
970 			if (fmtlen > v->width)
971 				v->width = fmtlen;
972 			return;
973 		}
974 	}
975 
976 	width = v->width;
977 	cp = ofmt + 1;
978 	fcp = v->fmt;
979 	if (v->flag & LJUST)
980 		*cp++ = '-';
981 	*cp++ = '*';
982 	while ((*cp++ = *fcp++) != '\0')
983 		continue;
984 
985 	switch (v->type) {
986 	case INT32:
987 		if (sizeof(int32_t) == sizeof(int))
988 			type = INT;
989 		else if (sizeof(int32_t) == sizeof(long))
990 			type = LONG;
991 		else
992 			errx(1, "unknown conversion for type %d", v->type);
993 		break;
994 	case UINT32:
995 		if (sizeof(u_int32_t) == sizeof(u_int))
996 			type = UINT;
997 		else if (sizeof(u_int32_t) == sizeof(u_long))
998 			type = ULONG;
999 		else
1000 			errx(1, "unknown conversion for type %d", v->type);
1001 		break;
1002 	default:
1003 		type = v->type;
1004 		break;
1005 	}
1006 
1007 	switch (type) {
1008 	case CHAR:
1009 		(void)printf(ofmt, width, GET(char));
1010 		return;
1011 	case UCHAR:
1012 		(void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1013 		return;
1014 	case SHORT:
1015 		(void)printf(ofmt, width, GET(short));
1016 		return;
1017 	case USHORT:
1018 		(void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1019 		return;
1020 	case INT:
1021 		(void)printf(ofmt, width, GET(int));
1022 		return;
1023 	case UINT:
1024 		(void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1025 		return;
1026 	case LONG:
1027 		(void)printf(ofmt, width, GET(long));
1028 		return;
1029 	case ULONG:
1030 		(void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1031 		return;
1032 	case KPTR:
1033 		(void)printf(ofmt, width, GET(u_long));
1034 		return;
1035 	case KPTR24:
1036 		(void)printf(ofmt, width, GET(u_long) & 0xffffff);
1037 		return;
1038 	case SIGLIST:
1039 		{
1040 			sigset_t *s = (sigset_t *)(void *)bp;
1041 			size_t i;
1042 #define SIGSETSIZE	(sizeof(s->__bits) / sizeof(s->__bits[0]))
1043 			char buf[SIGSETSIZE * 8 + 1];
1044 
1045 			for (i = 0; i < SIGSETSIZE; i++)
1046 				(void)snprintf(&buf[i * 8], 9, "%.8x",
1047 				    s->__bits[(SIGSETSIZE - 1) - i]);
1048 
1049 			/* Skip leading zeroes */
1050 			for (i = 0; buf[i]; i++)
1051 				if (buf[i] != '0')
1052 					break;
1053 
1054 			if (buf[i] == '\0')
1055 				i--;
1056 			(void)asprintf(&obuf, ofmt, width, &buf[i]);
1057 		}
1058 		break;
1059 	default:
1060 		errx(1, "unknown type %d", v->type);
1061 	}
1062 	if (obuf == NULL)
1063 		err(1, "%s", "");
1064 	if (mode == WIDTHMODE) {
1065 		/* Skip leading spaces. */
1066 		cp = strrchr(obuf, ' ');
1067 		if (cp == NULL)
1068 			cp = obuf;
1069 		else
1070 			cp++;	/* skip last space */
1071 	}
1072 	else
1073 		cp = obuf;
1074 	strprintorsetwidth(v, cp, mode);
1075 	free(obuf);
1076 #undef GET
1077 #undef CHK_INF127
1078 }
1079 
1080 void
1081 pvar(k, ve, mode)
1082 	struct kinfo_proc2 *k;
1083 	VARENT *ve;
1084 	int mode;
1085 {
1086 	VAR *v;
1087 
1088 	v = ve->var;
1089 	printval((char *)k + v->off, v, mode);
1090 }
1091