xref: /netbsd/bin/ps/print.c (revision eed3c295)
1 /*	$NetBSD: print.c,v 1.138 2022/01/26 11:48:53 andvar 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1990, 1993, 1994
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  */
60 
61 #include <sys/cdefs.h>
62 #ifndef lint
63 #if 0
64 static char sccsid[] = "@(#)print.c	8.6 (Berkeley) 4/16/94";
65 #else
66 __RCSID("$NetBSD: print.c,v 1.138 2022/01/26 11:48:53 andvar Exp $");
67 #endif
68 #endif /* not lint */
69 
70 #include <sys/param.h>
71 #include <sys/time.h>
72 #include <sys/resource.h>
73 #include <sys/sysctl.h>
74 #include <sys/lwp.h>
75 #include <sys/proc.h>
76 #include <sys/stat.h>
77 #include <sys/ucred.h>
78 #include <sys/sysctl.h>
79 #include <sys/acct.h>
80 #include <sys/ktrace.h>
81 
82 #include <err.h>
83 #include <grp.h>
84 #include <kvm.h>
85 #include <math.h>
86 #include <nlist.h>
87 #include <pwd.h>
88 #include <stddef.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <time.h>
93 #include <util.h>
94 #include <tzfile.h>
95 #include <unistd.h>
96 #include <signal.h>
97 
98 #include "ps.h"
99 
100 static char *cmdpart(char *);
101 static void  printval(void *, VAR *, enum mode);
102 static int   titlecmp(char *, char **);
103 
104 static void  doubleprintorsetwidth(VAR *, double, int, enum mode);
105 static void  intprintorsetwidth(VAR *, int, enum mode);
106 static void  strprintorsetwidth(VAR *, const char *, enum mode);
107 
108 static time_t now;
109 
110 #define	min(a,b)	((a) <= (b) ? (a) : (b))
111 
112 /* pre-NetBSD 5.x support. */
113 #ifndef LSDEAD
114 #define LSDEAD 6
115 #endif
116 
117 static void __attribute__((__format__(__strftime__, 3, 0)))
safe_strftime(char * buf,size_t bufsiz,const char * fmt,const struct tm * tp)118 safe_strftime(char *buf, size_t bufsiz, const char *fmt,
119     const struct tm *tp)
120 {
121 	if (tp == NULL || strftime(buf, bufsiz, fmt, tp) == 0)
122 		strlcpy(buf, "-", sizeof(buf));
123 }
124 
125 static int
iwidth(u_int64_t v)126 iwidth(u_int64_t v)
127 {
128 	u_int64_t nlim, lim;
129 	int w = 1;
130 
131 	for (lim = 10; v >= lim; lim = nlim) {
132 		nlim = lim * 10;
133 		w++;
134 		if (nlim < lim)
135 			break;
136 	}
137 	return w;
138 }
139 
140 static char *
cmdpart(char * arg0)141 cmdpart(char *arg0)
142 {
143 	char *cp;
144 
145 	return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
146 }
147 
148 void
printheader(void)149 printheader(void)
150 {
151 	int len;
152 	VAR *v;
153 	struct varent *vent;
154 	static int firsttime = 1;
155 	static int noheader = 0;
156 
157 	/*
158 	 * If all the columns have user-specified null headers,
159 	 * don't print the blank header line at all.
160 	 */
161 	if (firsttime) {
162 		SIMPLEQ_FOREACH(vent, &displaylist, next) {
163 			if (vent->var->header[0])
164 				break;
165 		}
166 		if (vent == NULL) {
167 			noheader = 1;
168 			firsttime = 0;
169 		}
170 
171 	}
172 	if (noheader)
173 		return;
174 
175 	SIMPLEQ_FOREACH(vent, &displaylist, next) {
176 		v = vent->var;
177 		if (firsttime) {
178 			len = strlen(v->header);
179 			if (len > v->width)
180 				v->width = len;
181 			totwidth += v->width + 1;	/* +1 for space */
182 		}
183 		if (v->flag & LJUST) {
184 			if (SIMPLEQ_NEXT(vent, next) == NULL)	/* last one */
185 				(void)printf("%s", v->header);
186 			else
187 				(void)printf("%-*s", v->width,
188 				    v->header);
189 		} else
190 			(void)printf("%*s", v->width, v->header);
191 		if (SIMPLEQ_NEXT(vent, next) != NULL)
192 			(void)putchar(' ');
193 	}
194 	(void)putchar('\n');
195 	if (firsttime) {
196 		firsttime = 0;
197 		totwidth--;	/* take off last space */
198 	}
199 }
200 
201 /*
202  * Return 1 if the command name in the argument vector (u-area) does
203  * not match the command name (p_comm)
204  */
205 static int
titlecmp(char * name,char ** argv)206 titlecmp(char *name, char **argv)
207 {
208 	char *title;
209 	int namelen;
210 
211 
212 	/* no argument vector == no match; system processes/threads do that */
213 	if (argv == 0 || argv[0] == 0)
214 		return (1);
215 
216 	title = cmdpart(argv[0]);
217 
218 	/* the basename matches */
219 	if (!strcmp(name, title))
220 		return (0);
221 
222 	/* handle login shells, by skipping the leading - */
223 	if (title[0] == '-' && !strcmp(name, title + 1))
224 		return (0);
225 
226 	namelen = strlen(name);
227 
228 	/* handle daemons that report activity as daemonname: activity */
229 	if (argv[1] == 0 &&
230 	    !strncmp(name, title, namelen) &&
231 	    title[namelen + 0] == ':' &&
232 	    title[namelen + 1] == ' ')
233 		return (0);
234 
235 	return (1);
236 }
237 
238 static void
doubleprintorsetwidth(VAR * v,double val,int prec,enum mode mode)239 doubleprintorsetwidth(VAR *v, double val, int prec, enum mode mode)
240 {
241 	int fmtlen;
242 
243 	if (mode == WIDTHMODE) {
244 		if (val < 0.0 && val < v->longestnd) {
245 			fmtlen = (int)log10(-val) + prec + 2;
246 			v->longestnd = val;
247 			if (fmtlen > v->width)
248 				v->width = fmtlen;
249 		} else if (val > 0.0 && val > v->longestpd) {
250 			fmtlen = (int)log10(val) + prec + 1;
251 			v->longestpd = val;
252 			if (fmtlen > v->width)
253 				v->width = fmtlen;
254 		}
255 	} else {
256 		(void)printf("%*.*f", v->width, prec, val);
257 	}
258 }
259 
260 static void
intprintorsetwidth(VAR * v,int val,enum mode mode)261 intprintorsetwidth(VAR *v, int val, enum mode mode)
262 {
263 	int fmtlen;
264 
265 	if (mode == WIDTHMODE) {
266 		if (val < 0 && val < v->longestn) {
267 			v->longestn = val;
268 			fmtlen = iwidth(-val) + 1;
269 			if (fmtlen > v->width)
270 				v->width = fmtlen;
271 		} else if (val > 0 && val > v->longestp) {
272 			v->longestp = val;
273 			fmtlen = iwidth(val);
274 			if (fmtlen > v->width)
275 				v->width = fmtlen;
276 		}
277 	} else
278 		(void)printf("%*d", v->width, val);
279 }
280 
281 static void
strprintorsetwidth(VAR * v,const char * str,enum mode mode)282 strprintorsetwidth(VAR *v, const char *str, enum mode mode)
283 {
284 	int len;
285 
286 	if (mode == WIDTHMODE) {
287 		len = strlen(str);
288 		if (len > v->width)
289 			v->width = len;
290 	} else {
291 		if (v->flag & LJUST)
292 			(void)printf("%-*.*s", v->width, v->width, str);
293 		else
294 			(void)printf("%*.*s", v->width, v->width, str);
295 	}
296 }
297 
298 void
command(struct pinfo * pi,VARENT * ve,enum mode mode)299 command(struct pinfo *pi, VARENT *ve, enum mode mode)
300 {
301 	struct kinfo_proc2 *ki = pi->ki;
302 	VAR *v;
303 	int left;
304 	char **argv, **p, *name;
305 
306 	if (mode == WIDTHMODE)
307 		return;
308 
309 	v = ve->var;
310 	if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
311 		if (SIMPLEQ_NEXT(ve, next) == NULL) {
312 			left = termwidth - (totwidth - v->width);
313 			if (left < 1) /* already wrapped, just use std width */
314 				left = v->width;
315 		} else
316 			left = v->width;
317 	} else
318 		left = -1;
319 	if (needenv && kd) {
320 		argv = kvm_getenvv2(kd, ki, termwidth);
321 		if ((p = argv) != NULL) {
322 			while (*p) {
323 				fmt_puts(*p, &left);
324 				p++;
325 				fmt_putc(' ', &left);
326 			}
327 		}
328 	}
329 	if (needcomm) {
330 		if (pi->prefix)
331 			(void)fmt_puts(pi->prefix, &left);
332 		name = ki->p_comm;
333 		if (!commandonly) {
334 			argv = kvm_getargv2(kd, ki, termwidth);
335 			if ((p = argv) != NULL) {
336 				while (*p) {
337 					fmt_puts(*p, &left);
338 					p++;
339 					fmt_putc(' ', &left);
340 					if (v->flag & ARGV0)
341 						break;
342 				}
343 				if (!(v->flag & ARGV0) &&
344 				    titlecmp(name, argv)) {
345 					/*
346 					 * append the real command name within
347 					 * parentheses, if the command name
348 					 * does not match the one in the
349 					 * argument vector
350 					 */
351 					fmt_putc('(', &left);
352 					fmt_puts(name, &left);
353 					fmt_putc(')', &left);
354 				}
355 			} else {
356 				/*
357 				 * Commands that don't set an argv vector
358 				 * are printed with square brackets if they
359 				 * are system commands.  Otherwise they are
360 				 * printed within parentheses.
361 				 */
362 				if (ki->p_flag & P_SYSTEM) {
363 					fmt_putc('[', &left);
364 					fmt_puts(name, &left);
365 					fmt_putc(']', &left);
366 				} else {
367 					fmt_putc('(', &left);
368 					fmt_puts(name, &left);
369 					fmt_putc(')', &left);
370 				}
371 			}
372 		} else {
373 			fmt_puts(name, &left);
374 		}
375 	}
376 	if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
377 		(void)printf("%*s", left, "");
378 }
379 
380 void
groups(struct pinfo * pi,VARENT * ve,enum mode mode)381 groups(struct pinfo *pi, VARENT *ve, enum mode mode)
382 {
383 	struct kinfo_proc2 *ki = pi->ki;
384 	VAR *v;
385 	int left, i;
386 	char buf[16], *p;
387 
388 	if (mode == WIDTHMODE)
389 		return;
390 
391 	v = ve->var;
392 	if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
393 		if (SIMPLEQ_NEXT(ve, next) == NULL) {
394 			left = termwidth - (totwidth - v->width);
395 			if (left < 1) /* already wrapped, just use std width */
396 				left = v->width;
397 		} else
398 			left = v->width;
399 	} else
400 		left = -1;
401 
402 	if (ki->p_ngroups == 0)
403 		fmt_putc('-', &left);
404 
405 	for (i = 0; i < ki->p_ngroups; i++) {
406 		(void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]);
407 		if (i)
408 			fmt_putc(' ', &left);
409 		for (p = &buf[0]; *p; p++)
410 			fmt_putc(*p, &left);
411 	}
412 
413 	if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
414 		(void)printf("%*s", left, "");
415 }
416 
417 void
groupnames(struct pinfo * pi,VARENT * ve,enum mode mode)418 groupnames(struct pinfo *pi, VARENT *ve, enum mode mode)
419 {
420 	struct kinfo_proc2 *ki = pi->ki;
421 	VAR *v;
422 	int left, i;
423 	const char *p;
424 
425 	if (mode == WIDTHMODE)
426 		return;
427 
428 	v = ve->var;
429 	if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
430 		if (SIMPLEQ_NEXT(ve, next) == NULL) {
431 			left = termwidth - (totwidth - v->width);
432 			if (left < 1) /* already wrapped, just use std width */
433 				left = v->width;
434 		} else
435 			left = v->width;
436 	} else
437 		left = -1;
438 
439 	if (ki->p_ngroups == 0)
440 		fmt_putc('-', &left);
441 
442 	for (i = 0; i < ki->p_ngroups; i++) {
443 		if (i)
444 			fmt_putc(' ', &left);
445 		for (p = group_from_gid(ki->p_groups[i], 0); *p; p++)
446 			fmt_putc(*p, &left);
447 	}
448 
449 	if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
450 		(void)printf("%*s", left, "");
451 }
452 
453 void
ucomm(struct pinfo * pi,VARENT * ve,enum mode mode)454 ucomm(struct pinfo *pi, VARENT *ve, enum mode mode)
455 {
456 	struct kinfo_proc2 *k = pi->ki;
457 	char buf[MAXPATHLEN], *p;
458 	VAR *v;
459 
460 	v = ve->var;
461 	if (pi->prefix)
462 		snprintf(p = buf, sizeof(buf), "%s%s", pi->prefix, k->p_comm);
463 	else
464 		p = k->p_comm;
465 	strprintorsetwidth(v, p, mode);
466 }
467 
468 void
emul(struct pinfo * pi,VARENT * ve,enum mode mode)469 emul(struct pinfo *pi, VARENT *ve, enum mode mode)
470 {
471 	struct kinfo_proc2 *k = pi->ki;
472 	VAR *v;
473 
474 	v = ve->var;
475 	strprintorsetwidth(v, k->p_ename, mode);
476 }
477 
478 void
logname(struct pinfo * pi,VARENT * ve,enum mode mode)479 logname(struct pinfo *pi, VARENT *ve, enum mode mode)
480 {
481 	struct kinfo_proc2 *k = pi->ki;
482 	VAR *v;
483 
484 	v = ve->var;
485 	strprintorsetwidth(v, k->p_login, mode);
486 }
487 
488 void
state(struct pinfo * pi,VARENT * ve,enum mode mode)489 state(struct pinfo *pi, VARENT *ve, enum mode mode)
490 {
491 	struct kinfo_proc2 *k = pi->ki;
492 	int flag, is_zombie;
493 	char *cp;
494 	VAR *v;
495 	char buf[16];
496 
497 	is_zombie = 0;
498 	v = ve->var;
499 	flag = k->p_flag;
500 	cp = buf;
501 
502 	/*
503 	 * NOTE: There are historical letters, which are no longer used:
504 	 *
505 	 * - W: indicated that process is swapped out.
506 	 * - L: indicated non-zero l_holdcnt (i.e. that process was
507 	 *   prevented from swapping-out.
508 	 *
509 	 * These letters should not be used for new states to avoid
510 	 * conflicts with old applications which might depend on them.
511 	 */
512 	switch (k->p_stat) {
513 
514 	case LSSTOP:
515 		*cp = 'T';
516 		break;
517 
518 	case LSSLEEP:
519 		if (flag & L_SINTR)	/* interruptable (long) */
520 			*cp = (int)k->p_slptime >= maxslp ? 'I' : 'S';
521 		else
522 			*cp = 'D';
523 		break;
524 
525 	case LSRUN:
526 	case LSIDL:
527 		*cp = 'R';
528 		break;
529 
530 	case LSONPROC:
531 		*cp = 'O';
532 		break;
533 
534 	case LSZOMB:
535 		*cp = 'Z';
536 		is_zombie = 1;
537 		break;
538 
539 	case LSSUSPENDED:
540 		*cp = 'U';
541 		break;
542 
543 	default:
544 		*cp = '?';
545 	}
546 	cp++;
547 	if (k->p_nice < NZERO)
548 		*cp++ = '<';
549 	else if (k->p_nice > NZERO)
550 		*cp++ = 'N';
551 	if (flag & P_TRACED)
552 		*cp++ = 'X';
553 	if (flag & P_WEXIT && !is_zombie)
554 		*cp++ = 'E';
555 	if (flag & P_PPWAIT)
556 		*cp++ = 'V';
557 	if (flag & P_SYSTEM)
558 		*cp++ = 'K';
559 	if (k->p_eflag & EPROC_SLEADER)
560 		*cp++ = 's';
561 	if (flag & P_SA)
562 		*cp++ = 'a';
563 	else if (k->p_nlwps > 1)
564 		*cp++ = 'l';
565 	if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
566 		*cp++ = '+';
567 	*cp = '\0';
568 	strprintorsetwidth(v, buf, mode);
569 }
570 
571 void
lstate(struct pinfo * pi,VARENT * ve,enum mode mode)572 lstate(struct pinfo *pi, VARENT *ve, enum mode mode)
573 {
574 	struct kinfo_lwp *k = pi->li;
575 	int flag;
576 	char *cp;
577 	VAR *v;
578 	char buf[16];
579 
580 	v = ve->var;
581 	flag = k->l_flag;
582 	cp = buf;
583 
584 	switch (k->l_stat) {
585 
586 	case LSSTOP:
587 		*cp = 'T';
588 		break;
589 
590 	case LSSLEEP:
591 		if (flag & L_SINTR)	/* interruptible (long) */
592 			*cp = (int)k->l_slptime >= maxslp ? 'I' : 'S';
593 		else
594 			*cp = 'D';
595 		break;
596 
597 	case LSRUN:
598 	case LSIDL:
599 		*cp = 'R';
600 		break;
601 
602 	case LSONPROC:
603 		*cp = 'O';
604 		break;
605 
606 	case LSZOMB:
607 	case LSDEAD:
608 		*cp = 'Z';
609 		break;
610 
611 	case LSSUSPENDED:
612 		*cp = 'U';
613 		break;
614 
615 	default:
616 		*cp = '?';
617 	}
618 	cp++;
619 	if (flag & L_SYSTEM)
620 		*cp++ = 'K';
621 	if (flag & L_SA)
622 		*cp++ = 'a';
623 	if (flag & L_DETACHED)
624 		*cp++ = '-';
625 	*cp = '\0';
626 	strprintorsetwidth(v, buf, mode);
627 }
628 
629 void
pnice(struct pinfo * pi,VARENT * ve,enum mode mode)630 pnice(struct pinfo *pi, VARENT *ve, enum mode mode)
631 {
632 	struct kinfo_proc2 *k = pi->ki;
633 	VAR *v;
634 
635 	v = ve->var;
636 	intprintorsetwidth(v, k->p_nice - NZERO, mode);
637 }
638 
639 void
pri(struct pinfo * pi,VARENT * ve,enum mode mode)640 pri(struct pinfo *pi, VARENT *ve, enum mode mode)
641 {
642 	struct kinfo_lwp *l = pi->li;
643 	VAR *v;
644 
645 	v = ve->var;
646 	intprintorsetwidth(v, l->l_priority, mode);
647 }
648 
649 void
usrname(struct pinfo * pi,VARENT * ve,enum mode mode)650 usrname(struct pinfo *pi, VARENT *ve, enum mode mode)
651 {
652 	struct kinfo_proc2 *k = pi->ki;
653 	VAR *v;
654 
655 	v = ve->var;
656 	strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
657 }
658 
659 void
runame(struct pinfo * pi,VARENT * ve,enum mode mode)660 runame(struct pinfo *pi, VARENT *ve, enum mode mode)
661 {
662 	struct kinfo_proc2 *k = pi->ki;
663 	VAR *v;
664 
665 	v = ve->var;
666 	strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
667 }
668 
669 void
svuname(struct pinfo * pi,VARENT * ve,enum mode mode)670 svuname(struct pinfo *pi, VARENT *ve, enum mode mode)
671 {
672 	struct kinfo_proc2 *k = pi->ki;
673 	VAR *v;
674 
675 	v = ve->var;
676 	strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
677 }
678 
679 void
gname(struct pinfo * pi,VARENT * ve,enum mode mode)680 gname(struct pinfo *pi, VARENT *ve, enum mode mode)
681 {
682 	struct kinfo_proc2 *k = pi->ki;
683 	VAR *v;
684 
685 	v = ve->var;
686 	strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
687 }
688 
689 void
rgname(struct pinfo * pi,VARENT * ve,enum mode mode)690 rgname(struct pinfo *pi, VARENT *ve, enum mode mode)
691 {
692 	struct kinfo_proc2 *k = pi->ki;
693 	VAR *v;
694 
695 	v = ve->var;
696 	strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
697 }
698 
699 void
svgname(struct pinfo * pi,VARENT * ve,enum mode mode)700 svgname(struct pinfo *pi, VARENT *ve, enum mode mode)
701 {
702 	struct kinfo_proc2 *k = pi->ki;
703 	VAR *v;
704 
705 	v = ve->var;
706 	strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
707 }
708 
709 void
tdev(struct pinfo * pi,VARENT * ve,enum mode mode)710 tdev(struct pinfo *pi, VARENT *ve, enum mode mode)
711 {
712 	struct kinfo_proc2 *k = pi->ki;
713 	VAR *v;
714 	dev_t dev;
715 	char buff[16];
716 
717 	v = ve->var;
718 	dev = k->p_tdev;
719 	if (dev == NODEV) {
720 		if (mode == PRINTMODE)
721 			(void)printf("%*s", v->width, "?");
722 		else
723 			if (v->width < 2)
724 				v->width = 2;
725 	} else {
726 		(void)snprintf(buff, sizeof(buff),
727 		    "%lld/%lld", (long long)major(dev), (long long)minor(dev));
728 		strprintorsetwidth(v, buff, mode);
729 	}
730 }
731 
732 void
tname(struct pinfo * pi,VARENT * ve,enum mode mode)733 tname(struct pinfo *pi, VARENT *ve, enum mode mode)
734 {
735 	struct kinfo_proc2 *k = pi->ki;
736 	VAR *v;
737 	dev_t dev;
738 	const char *ttname;
739 	int noctty;
740 
741 	v = ve->var;
742 	dev = k->p_tdev;
743 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
744 		if (mode == PRINTMODE)
745 			(void)printf("%-*s", v->width, "?");
746 		else
747 			if (v->width < 2)
748 				v->width = 2;
749 	} else {
750 		noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
751 		if (mode == WIDTHMODE) {
752 			int fmtlen;
753 
754 			fmtlen = strlen(ttname) + noctty;
755 			if (v->width < fmtlen)
756 				v->width = fmtlen;
757 		} else {
758 			if (noctty)
759 				(void)printf("%-*s-", v->width - 1, ttname);
760 			else
761 				(void)printf("%-*s", v->width, ttname);
762 		}
763 	}
764 }
765 
766 void
longtname(struct pinfo * pi,VARENT * ve,enum mode mode)767 longtname(struct pinfo *pi, VARENT *ve, enum mode mode)
768 {
769 	struct kinfo_proc2 *k = pi->ki;
770 	VAR *v;
771 	dev_t dev;
772 	const char *ttname;
773 
774 	v = ve->var;
775 	dev = k->p_tdev;
776 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
777 		if (mode == PRINTMODE)
778 			(void)printf("%-*s", v->width, "?");
779 		else
780 			if (v->width < 2)
781 				v->width = 2;
782 	} else {
783 		strprintorsetwidth(v, ttname, mode);
784 	}
785 }
786 
787 void
started(struct pinfo * pi,VARENT * ve,enum mode mode)788 started(struct pinfo *pi, VARENT *ve, enum mode mode)
789 {
790 	struct kinfo_proc2 *k = pi->ki;
791 	VAR *v;
792 	time_t startt;
793 	struct tm *tp;
794 	char buf[100], *cp;
795 
796 	v = ve->var;
797 	if (!k->p_uvalid) {
798 		if (mode == PRINTMODE)
799 			(void)printf("%*s", v->width, "-");
800 		return;
801 	}
802 
803 	startt = k->p_ustart_sec;
804 	tp = localtime(&startt);
805 	if (now == 0)
806 		(void)time(&now);
807 	if (now - k->p_ustart_sec < SECSPERDAY)
808 		safe_strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp);
809 	else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
810 		safe_strftime(buf, sizeof(buf) - 1, "%a%I%p", tp);
811 	else
812 		safe_strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
813 	/* %e and %l can start with a space. */
814 	cp = buf;
815 	if (*cp == ' ')
816 		cp++;
817 	strprintorsetwidth(v, cp, mode);
818 }
819 
820 void
lstarted(struct pinfo * pi,VARENT * ve,enum mode mode)821 lstarted(struct pinfo *pi, VARENT *ve, enum mode mode)
822 {
823 	struct kinfo_proc2 *k = pi->ki;
824 	VAR *v;
825 	time_t startt;
826 	char buf[100];
827 
828 	v = ve->var;
829 	startt = k->p_ustart_sec;
830 
831 	if (mode == WIDTHMODE) {
832 		/*
833 		 * We only need to set the width once, as we assume
834 		 * that all times are the same length.  We do need to
835 		 * check against the header length as well, as "no
836 		 * header" mode for this variable will set the field
837 		 * width to the length of the header anyway (ref: the
838 		 * P1003.1-2004 comment in findvar()).
839 		 *
840 		 * XXX: The hardcoded "STARTED" string.  Better or
841 		 * worse than a "<= 7" or some other arbitrary number?
842 		 */
843 		if (v->width > (int)sizeof("STARTED") - 1) {
844 			return;
845 		}
846 	} else {
847 		if (!k->p_uvalid) {
848 			(void)printf("%*s", v->width, "-");
849 			return;
850 		}
851 	}
852 	safe_strftime(buf, sizeof(buf) - 1, "%c", localtime(&startt));
853 	strprintorsetwidth(v, buf, mode);
854 }
855 
856 void
elapsed(struct pinfo * pi,VARENT * ve,enum mode mode)857 elapsed(struct pinfo *pi, VARENT *ve, enum mode mode)
858 {
859 	struct kinfo_proc2 *k = pi->ki;
860 	VAR *v;
861 	int32_t origseconds, secs, mins, hours, days;
862 	int fmtlen, printed_something;
863 
864 	v = ve->var;
865 	if (k->p_uvalid == 0) {
866 		origseconds = 0;
867 	} else {
868 		if (now == 0)
869 			(void)time(&now);
870 		origseconds = now - k->p_ustart_sec;
871 		if (origseconds < 0) {
872 			/*
873 			 * Don't try to be fancy if the machine's
874 			 * clock has been rewound to before the
875 			 * process "started".
876 			 */
877 			origseconds = 0;
878 		}
879 	}
880 
881 	secs = origseconds;
882 	mins = secs / SECSPERMIN;
883 	secs %= SECSPERMIN;
884 	hours = mins / MINSPERHOUR;
885 	mins %= MINSPERHOUR;
886 	days = hours / HOURSPERDAY;
887 	hours %= HOURSPERDAY;
888 
889 	if (mode == WIDTHMODE) {
890 		if (origseconds == 0)
891 			/* non-zero so fmtlen is calculated at least once */
892 			origseconds = 1;
893 
894 		if (origseconds > v->longestp) {
895 			v->longestp = origseconds;
896 
897 			if (days > 0) {
898 				/* +9 for "-hh:mm:ss" */
899 				fmtlen = iwidth(days) + 9;
900 			} else if (hours > 0) {
901 				/* +6 for "mm:ss" */
902 				fmtlen = iwidth(hours) + 6;
903 			} else {
904 				/* +3 for ":ss" */
905 				fmtlen = iwidth(mins) + 3;
906 			}
907 
908 			if (fmtlen > v->width)
909 				v->width = fmtlen;
910 		}
911 	} else {
912 		printed_something = 0;
913 		fmtlen = v->width;
914 
915 		if (days > 0) {
916 			(void)printf("%*d", fmtlen - 9, days);
917 			printed_something = 1;
918 		} else if (fmtlen > 9) {
919 			(void)printf("%*s", fmtlen - 9, "");
920 		}
921 		if (fmtlen > 9)
922 			fmtlen = 9;
923 
924 		if (printed_something) {
925 			(void)printf("-%.*d", fmtlen - 7, hours);
926 			printed_something = 1;
927 		} else if (hours > 0) {
928 			(void)printf("%*d", fmtlen - 6, hours);
929 			printed_something = 1;
930 		} else if (fmtlen > 6) {
931 			(void)printf("%*s", fmtlen - 6, "");
932 		}
933 		if (fmtlen > 6)
934 			fmtlen = 6;
935 
936 		/* Don't need to set fmtlen or printed_something any more... */
937 		if (printed_something) {
938 			(void)printf(":%.*d", fmtlen - 4, mins);
939 		} else if (mins > 0) {
940 			(void)printf("%*d", fmtlen - 3, mins);
941 		} else if (fmtlen > 3) {
942 			(void)printf("%*s", fmtlen - 3, "0");
943 		}
944 
945 		(void)printf(":%.2d", secs);
946 	}
947 }
948 
949 void
wchan(struct pinfo * pi,VARENT * ve,enum mode mode)950 wchan(struct pinfo *pi, VARENT *ve, enum mode mode)
951 {
952 	struct kinfo_lwp *l = pi->li;
953 	VAR *v;
954 
955 	v = ve->var;
956 	if (l->l_wmesg[0]) {
957 		strprintorsetwidth(v, l->l_wmesg, mode);
958 		v->width = min(v->width, KI_WMESGLEN);
959 	} else {
960 		if (mode == PRINTMODE)
961 			(void)printf("%-*s", v->width, "-");
962 	}
963 }
964 
965 #define	pgtok(a)        (((a)*(size_t)getpagesize())/1024)
966 
967 void
vsize(struct pinfo * pi,VARENT * ve,enum mode mode)968 vsize(struct pinfo *pi, VARENT *ve, enum mode mode)
969 {
970 	struct kinfo_proc2 *k = pi->ki;
971 	VAR *v;
972 
973 	v = ve->var;
974 	intprintorsetwidth(v, pgtok(k->p_vm_msize), mode);
975 }
976 
977 void
rssize(struct pinfo * pi,VARENT * ve,enum mode mode)978 rssize(struct pinfo *pi, VARENT *ve, enum mode mode)
979 {
980 	struct kinfo_proc2 *k = pi->ki;
981 	VAR *v;
982 
983 	v = ve->var;
984 	/* XXX don't have info about shared */
985 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
986 }
987 
988 void
p_rssize(struct pinfo * pi,VARENT * ve,enum mode mode)989 p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode)	/* doesn't account for text */
990 {
991 	struct kinfo_proc2 *k = pi->ki;
992 	VAR *v;
993 
994 	v = ve->var;
995 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
996 }
997 
998 void
cpuid(struct pinfo * pi,VARENT * ve,enum mode mode)999 cpuid(struct pinfo *pi, VARENT *ve, enum mode mode)
1000 {
1001 	struct kinfo_lwp *l = pi->li;
1002 	VAR *v;
1003 
1004 	v = ve->var;
1005 	intprintorsetwidth(v, l->l_cpuid, mode);
1006 }
1007 
1008 static void
cputime1(int32_t secs,int32_t psecs,VAR * v,enum mode mode)1009 cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode)
1010 {
1011 	int fmtlen;
1012 
1013 	/*
1014 	 * round and scale to 100's
1015 	 */
1016 	psecs = (psecs + 5000) / 10000;
1017 	secs += psecs / 100;
1018 	psecs = psecs % 100;
1019 
1020 	if (mode == WIDTHMODE) {
1021 		/*
1022 		 * Ugg, this is the only field where a value of 0 is longer
1023 		 * than the column title.
1024 		 * Use SECSPERMIN, because secs is divided by that when
1025 		 * passed to iwidth().
1026 		 */
1027 		if (secs == 0)
1028 			secs = SECSPERMIN;
1029 
1030 		if (secs > v->longestp) {
1031 			v->longestp = secs;
1032 			/* "+6" for the ":%02ld.%02ld" in the printf() below */
1033 			fmtlen = iwidth(secs / SECSPERMIN) + 6;
1034 			if (fmtlen > v->width)
1035 				v->width = fmtlen;
1036 		}
1037 	} else {
1038 		(void)printf("%*ld:%02ld.%02ld", v->width - 6,
1039 		    (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
1040 		    (long)psecs);
1041 	}
1042 }
1043 
1044 void
cputime(struct pinfo * pi,VARENT * ve,enum mode mode)1045 cputime(struct pinfo *pi, VARENT *ve, enum mode mode)
1046 {
1047 	struct kinfo_proc2 *k = pi->ki;
1048 	VAR *v;
1049 	int32_t secs;
1050 	int32_t psecs;	/* "parts" of a second. first micro, then centi */
1051 
1052 	v = ve->var;
1053 
1054 	/*
1055 	 * This counts time spent handling interrupts.  We could
1056 	 * fix this, but it is not 100% trivial (and interrupt
1057 	 * time fractions only work on the sparc anyway).	XXX
1058 	 */
1059 	secs = k->p_rtime_sec;
1060 	psecs = k->p_rtime_usec;
1061 	if (sumrusage) {
1062 		secs += k->p_uctime_sec;
1063 		psecs += k->p_uctime_usec;
1064 	}
1065 
1066 	cputime1(secs, psecs, v, mode);
1067 }
1068 
1069 void
lcputime(struct pinfo * pi,VARENT * ve,enum mode mode)1070 lcputime(struct pinfo *pi, VARENT *ve, enum mode mode)
1071 {
1072 	struct kinfo_lwp *l = pi->li;
1073 	VAR *v;
1074 	int32_t secs;
1075 	int32_t psecs;	/* "parts" of a second. first micro, then centi */
1076 
1077 	v = ve->var;
1078 
1079 	secs = l->l_rtime_sec;
1080 	psecs = l->l_rtime_usec;
1081 
1082 	cputime1(secs, psecs, v, mode);
1083 }
1084 
1085 void
pcpu(struct pinfo * pi,VARENT * ve,enum mode mode)1086 pcpu(struct pinfo *pi, VARENT *ve, enum mode mode)
1087 {
1088 	VAR *v;
1089 	double dbl;
1090 
1091 	v = ve->var;
1092 	dbl = pi->pcpu;
1093 	doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode);
1094 }
1095 
1096 double
getpmem(const struct kinfo_proc2 * k)1097 getpmem(const struct kinfo_proc2 *k)
1098 {
1099 	double fracmem;
1100 	int szptudot;
1101 
1102 	if (!nlistread)
1103 		donlist();
1104 
1105 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
1106 	szptudot = uspace/getpagesize();
1107 	/* XXX don't have info about shared */
1108 	fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
1109 	return (100.0 * fracmem);
1110 }
1111 
1112 void
pmem(struct pinfo * pi,VARENT * ve,enum mode mode)1113 pmem(struct pinfo *pi, VARENT *ve, enum mode mode)
1114 {
1115 	struct kinfo_proc2 *k = pi->ki;
1116 	VAR *v;
1117 
1118 	v = ve->var;
1119 	doubleprintorsetwidth(v, getpmem(k), 1, mode);
1120 }
1121 
1122 void
pagein(struct pinfo * pi,VARENT * ve,enum mode mode)1123 pagein(struct pinfo *pi, VARENT *ve, enum mode mode)
1124 {
1125 	struct kinfo_proc2 *k = pi->ki;
1126 	VAR *v;
1127 
1128 	v = ve->var;
1129 	intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
1130 }
1131 
1132 void
maxrss(struct pinfo * pi,VARENT * ve,enum mode mode)1133 maxrss(struct pinfo *pi, VARENT *ve, enum mode mode)
1134 {
1135 	VAR *v;
1136 
1137 	v = ve->var;
1138 	/* No need to check width! */
1139 	if (mode == PRINTMODE)
1140 		(void)printf("%*s", v->width, "-");
1141 }
1142 
1143 void
tsize(struct pinfo * pi,VARENT * ve,enum mode mode)1144 tsize(struct pinfo *pi, VARENT *ve, enum mode mode)
1145 {
1146 	struct kinfo_proc2 *k = pi->ki;
1147 	VAR *v;
1148 
1149 	v = ve->var;
1150 	intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
1151 }
1152 
1153 static void
printsig(VAR * v,const sigset_t * s,enum mode mode)1154 printsig(VAR *v, const sigset_t *s, enum mode mode)
1155 {
1156 #define	SIGSETSIZE	__arraycount(s->__bits)
1157 	if ((v->flag & ALTPR) == 0) {
1158 		char buf[SIGSETSIZE * 8 + 1];
1159 		size_t i;
1160 
1161 		for (i = 0; i < SIGSETSIZE; i++)
1162 			(void)snprintf(&buf[i * 8], 9, "%.8x",
1163 			    s->__bits[(SIGSETSIZE - 1) - i]);
1164 
1165 		/* Skip leading zeroes */
1166 		for (i = 0; buf[i] == '0'; i++)
1167 			continue;
1168 
1169 		if (buf[i] == '\0')
1170 			i--;
1171 		strprintorsetwidth(v, buf + i, mode);
1172 	} else {
1173 		size_t maxlen = 1024, len = 0;
1174 		char *buf = emalloc(maxlen);
1175 		*buf = '\0';
1176 		for (size_t i = 0; i < SIGSETSIZE; i++) {
1177 			uint32_t m = s->__bits[i];
1178 			for (uint32_t j = 0; j < 32; j++) {
1179 				if ((m & (1 << j)) == 0)
1180 					continue;
1181 				const char *n = signalname(j + 1);
1182 				size_t sn = strlen(n);
1183 				if (len)
1184 					sn++;
1185 				if (len + sn >= maxlen) {
1186 					maxlen += 1024;
1187 					buf = erealloc(buf, maxlen);
1188 				}
1189 				snprintf(buf + len, sn + 1, "%s%s",
1190 				    len == 0 ? "" : ",", n);
1191 				len += sn;
1192 			}
1193 		}
1194 		strprintorsetwidth(v, buf, mode);
1195 		free(buf);
1196 #undef SIGSETSIZE
1197 	}
1198 }
1199 
1200 static void
printflag(VAR * v,int flag,enum mode mode)1201 printflag(VAR *v, int flag, enum mode mode)
1202 {
1203 	char buf[1024];
1204 	const char *fmt;
1205 
1206 	switch (v->type) {
1207 	case PROCFLAG:
1208 		fmt = __SYSCTL_PROC_FLAG_BITS;
1209 		break;
1210 	case KTRACEFLAG:
1211 		fmt = __KTRACE_FLAG_BITS;
1212 		break;
1213 	case PROCACFLAG:
1214 		fmt = __ACCT_FLAG_BITS;
1215 		break;
1216 	default:
1217 		err(EXIT_FAILURE, "Bad type %d", v->type);
1218 	}
1219 
1220 	snprintb(buf, sizeof(buf), fmt, (unsigned)flag);
1221 	strprintorsetwidth(v, buf, mode);
1222 }
1223 
1224 /*
1225  * Generic output routines.  Print fields from various prototype
1226  * structures.
1227  */
1228 static void
printval(void * bp,VAR * v,enum mode mode)1229 printval(void *bp, VAR *v, enum mode mode)
1230 {
1231 	static char ofmt[32] = "%";
1232 	int width, vok, fmtlen;
1233 	const char *fcp;
1234 	char *cp;
1235 	int64_t val;
1236 	u_int64_t uval;
1237 
1238 	val = 0;	/* XXXGCC -Wuninitialized [hpcarm] */
1239 	uval = 0;	/* XXXGCC -Wuninitialized [hpcarm] */
1240 
1241 	/*
1242 	 * Note that the "INF127" check is nonsensical for types
1243 	 * that are or can be signed.
1244 	 */
1245 #define	GET(type)		(*(type *)bp)
1246 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
1247 
1248 #define	VSIGN	1
1249 #define	VUNSIGN	2
1250 #define	VPTR	3
1251 
1252 	if (mode == WIDTHMODE) {
1253 		vok = 0;
1254 		switch (v->type) {
1255 		case CHAR:
1256 			val = GET(char);
1257 			vok = VSIGN;
1258 			break;
1259 		case UCHAR:
1260 			uval = CHK_INF127(GET(u_char));
1261 			vok = VUNSIGN;
1262 			break;
1263 		case SHORT:
1264 			val = GET(short);
1265 			vok = VSIGN;
1266 			break;
1267 		case PROCACFLAG:
1268 			if (v->flag & ALTPR)
1269 				break;
1270 			/*FALLTHROUGH*/
1271 		case USHORT:
1272 			uval = CHK_INF127(GET(u_short));
1273 			vok = VUNSIGN;
1274 			break;
1275 		case INT32:
1276 			val = GET(int32_t);
1277 			vok = VSIGN;
1278 			break;
1279 		case KTRACEFLAG:
1280 		case PROCFLAG:
1281 			if (v->flag & ALTPR)
1282 				break;
1283 			/*FALLTHROUGH*/
1284 		case INT:
1285 			val = GET(int);
1286 			vok = VSIGN;
1287 			break;
1288 		case UINT:
1289 		case UINT32:
1290 			uval = CHK_INF127(GET(u_int));
1291 			vok = VUNSIGN;
1292 			break;
1293 		case LONG:
1294 			val = GET(long);
1295 			vok = VSIGN;
1296 			break;
1297 		case ULONG:
1298 			uval = CHK_INF127(GET(u_long));
1299 			vok = VUNSIGN;
1300 			break;
1301 		case KPTR:
1302 			uval = GET(u_int64_t);
1303 			vok = VPTR;
1304 			break;
1305 		case KPTR24:
1306 			uval = GET(u_int64_t);
1307 			uval &= 0xffffff;
1308 			vok = VPTR;
1309 			break;
1310 		case INT64:
1311 			val = GET(int64_t);
1312 			vok = VSIGN;
1313 			break;
1314 		case UINT64:
1315 			uval = CHK_INF127(GET(u_int64_t));
1316 			vok = VUNSIGN;
1317 			break;
1318 
1319 		case SIGLIST:
1320 		default:
1321 			/* nothing... */;
1322 		}
1323 		switch (vok) {
1324 		case VSIGN:
1325 			if (val < 0 && val < v->longestn) {
1326 				v->longestn = val;
1327 				fmtlen = iwidth(-val) + 1;
1328 				if (fmtlen > v->width)
1329 					v->width = fmtlen;
1330 			} else if (val > 0 && val > v->longestp) {
1331 				v->longestp = val;
1332 				fmtlen = iwidth(val);
1333 				if (fmtlen > v->width)
1334 					v->width = fmtlen;
1335 			}
1336 			return;
1337 		case VUNSIGN:
1338 			if (uval > v->longestu) {
1339 				v->longestu = uval;
1340 				v->width = iwidth(uval);
1341 			}
1342 			return;
1343 		case VPTR:
1344 			fmtlen = 0;
1345 			while (uval > 0) {
1346 				uval >>= 4;
1347 				fmtlen++;
1348 			}
1349 			if (fmtlen > v->width)
1350 				v->width = fmtlen;
1351 			return;
1352 		}
1353 	}
1354 
1355 	width = v->width;
1356 	cp = ofmt + 1;
1357 	fcp = v->fmt;
1358 	if (v->flag & LJUST)
1359 		*cp++ = '-';
1360 	*cp++ = '*';
1361 	while ((*cp++ = *fcp++) != '\0')
1362 		continue;
1363 
1364 	switch (v->type) {
1365 	case CHAR:
1366 		(void)printf(ofmt, width, GET(char));
1367 		return;
1368 	case UCHAR:
1369 		(void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1370 		return;
1371 	case SHORT:
1372 		(void)printf(ofmt, width, GET(short));
1373 		return;
1374 	case PROCACFLAG:
1375 		if (v->flag & ALTPR) {
1376 			printflag(v, CHK_INF127(GET(u_short)), mode);
1377 			return;
1378 		}
1379 		/*FALLTHROUGH*/
1380 	case USHORT:
1381 		(void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1382 		return;
1383 	case KTRACEFLAG:
1384 	case PROCFLAG:
1385 		if (v->flag & ALTPR) {
1386 			printflag(v, GET(int), mode);
1387 			return;
1388 		}
1389 		/*FALLTHROUGH*/
1390 	case INT:
1391 		(void)printf(ofmt, width, GET(int));
1392 		return;
1393 	case UINT:
1394 		(void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1395 		return;
1396 	case LONG:
1397 		(void)printf(ofmt, width, GET(long));
1398 		return;
1399 	case ULONG:
1400 		(void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1401 		return;
1402 	case KPTR:
1403 		(void)printf(ofmt, width, GET(u_int64_t));
1404 		return;
1405 	case KPTR24:
1406 		(void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
1407 		return;
1408 	case INT32:
1409 		(void)printf(ofmt, width, GET(int32_t));
1410 		return;
1411 	case UINT32:
1412 		(void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
1413 		return;
1414 	case INT64:
1415 		(void)printf(ofmt, width, GET(int64_t));
1416 		return;
1417 	case UINT64:
1418 		(void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
1419 		return;
1420 	case SIGLIST:
1421 		printsig(v, (const sigset_t *)(void *)bp, mode);
1422 		return;
1423 	default:
1424 		errx(EXIT_FAILURE, "unknown type %d", v->type);
1425 	}
1426 #undef GET
1427 #undef CHK_INF127
1428 }
1429 
1430 void
pvar(struct pinfo * pi,VARENT * ve,enum mode mode)1431 pvar(struct pinfo *pi, VARENT *ve, enum mode mode)
1432 {
1433 	VAR *v = ve->var;
1434 	char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
1435 
1436 	if ((v->flag & UAREA) && !pi->ki->p_uvalid) {
1437 		if (mode == PRINTMODE)
1438 			(void)printf("%*s", v->width, "-");
1439 		return;
1440 	}
1441 
1442 	(void)printval(b + v->off, v, mode);
1443 }
1444 
1445 void
putimeval(struct pinfo * pi,VARENT * ve,enum mode mode)1446 putimeval(struct pinfo *pi, VARENT *ve, enum mode mode)
1447 {
1448 	VAR *v = ve->var;
1449 	struct kinfo_proc2 *k = pi->ki;
1450 	char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
1451 	ulong secs = *(uint32_t *)(b + v->off);
1452 	ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t));
1453 	int fmtlen;
1454 
1455 	if (!k->p_uvalid) {
1456 		if (mode == PRINTMODE)
1457 			(void)printf("%*s", v->width, "-");
1458 		return;
1459 	}
1460 
1461 	if (mode == WIDTHMODE) {
1462 		if (secs == 0)
1463 			/* non-zero so fmtlen is calculated at least once */
1464 			secs = 1;
1465 		if (secs > v->longestu) {
1466 			v->longestu = secs;
1467 			if (secs <= 999)
1468 				/* sss.ssssss */
1469 				fmtlen = iwidth(secs) + 6 + 1;
1470 			else
1471 				/* hh:mm:ss.ss */
1472 				fmtlen = iwidth((secs + 1) / SECSPERHOUR)
1473 					+ 2 + 1 + 2 + 1 + 2 + 1;
1474 			if (fmtlen > v->width)
1475 				v->width = fmtlen;
1476 		}
1477 		return;
1478 	}
1479 
1480 	if (secs < 999)
1481 		(void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
1482 	else {
1483 		uint h, m;
1484 		usec += 5000;
1485 		if (usec >= 1000000) {
1486 			usec -= 1000000;
1487 			secs++;
1488 		}
1489 		m = secs / SECSPERMIN;
1490 		secs -= m * SECSPERMIN;
1491 		h = m / MINSPERHOUR;
1492 		m -= h * MINSPERHOUR;
1493 		(void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
1494 		    usec / 10000u );
1495 	}
1496 }
1497 
1498 void
lname(struct pinfo * pi,VARENT * ve,enum mode mode)1499 lname(struct pinfo *pi, VARENT *ve, enum mode mode)
1500 {
1501 	struct kinfo_lwp *l = pi->li;
1502 	VAR *v;
1503 
1504 	v = ve->var;
1505 	if (l->l_name[0] != '\0') {
1506 		strprintorsetwidth(v, l->l_name, mode);
1507 		v->width = min(v->width, KI_LNAMELEN);
1508 	} else {
1509 		if (mode == PRINTMODE)
1510 			(void)printf("%-*s", v->width, "-");
1511 	}
1512 }
1513