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