2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1990, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/param.h>
34 #include <sys/resource.h>
40 #include <sys/sysctl.h>
41 #include <sys/vmmeter.h>
61 #define COMMAND_WIDTH 16
62 #define ARGUMENTS_WIDTH 16
64 #define ps_pgtok(a) (((a) * getpagesize()) / 1024)
72 STAILQ_FOREACH(vent
, &varlist
, next_ve
)
73 if (*vent
->header
!= '\0')
78 STAILQ_FOREACH(vent
, &varlist
, next_ve
) {
80 if (v
->flag
& LJUST
) {
81 if (STAILQ_NEXT(vent
, next_ve
) == NULL
) /* last one */
82 xo_emit("{T:/%hs}", vent
->header
);
84 xo_emit("{T:/%-*hs}", v
->width
, vent
->header
);
86 xo_emit("{T:/%*hs}", v
->width
, vent
->header
);
87 if (STAILQ_NEXT(vent
, next_ve
) != NULL
)
94 arguments(KINFO
*k
, VARENT
*ve
)
98 if ((vis_args
= malloc(strlen(k
->ki_args
) * 4 + 1)) == NULL
)
99 xo_errx(1, "malloc failed");
100 strvis(vis_args
, k
->ki_args
, VIS_TAB
| VIS_NL
| VIS_NOSLASH
);
102 if (STAILQ_NEXT(ve
, next_ve
) != NULL
&& strlen(vis_args
) > ARGUMENTS_WIDTH
)
103 vis_args
[ARGUMENTS_WIDTH
] = '\0';
109 command(KINFO
*k
, VARENT
*ve
)
111 char *vis_args
, *vis_env
, *str
;
114 /* If it is the last field, then don't pad */
115 if (STAILQ_NEXT(ve
, next_ve
) == NULL
) {
116 asprintf(&str
, "%s%s%s%s%s",
117 k
->ki_d
.prefix
? k
->ki_d
.prefix
: "",
119 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? "/" : "",
120 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? k
->ki_p
->ki_tdname
: "",
121 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? k
->ki_p
->ki_moretdname
: "");
123 str
= strdup(k
->ki_p
->ki_comm
);
127 if ((vis_args
= malloc(strlen(k
->ki_args
) * 4 + 1)) == NULL
)
128 xo_errx(1, "malloc failed");
129 strvis(vis_args
, k
->ki_args
, VIS_TAB
| VIS_NL
| VIS_NOSLASH
);
131 if (STAILQ_NEXT(ve
, next_ve
) == NULL
) {
135 if ((vis_env
= malloc(strlen(k
->ki_env
) * 4 + 1))
137 xo_errx(1, "malloc failed");
138 strvis(vis_env
, k
->ki_env
,
139 VIS_TAB
| VIS_NL
| VIS_NOSLASH
);
143 asprintf(&str
, "%s%s%s%s",
144 k
->ki_d
.prefix
? k
->ki_d
.prefix
: "",
145 vis_env
? vis_env
: "",
153 /* ki_d.prefix & ki_env aren't shown for interim fields */
156 if (strlen(str
) > COMMAND_WIDTH
)
157 str
[COMMAND_WIDTH
] = '\0';
164 ucomm(KINFO
*k
, VARENT
*ve
)
168 if (STAILQ_NEXT(ve
, next_ve
) == NULL
) { /* last field, don't pad */
169 asprintf(&str
, "%s%s%s%s%s",
170 k
->ki_d
.prefix
? k
->ki_d
.prefix
: "",
172 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? "/" : "",
173 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? k
->ki_p
->ki_tdname
: "",
174 (showthreads
&& k
->ki_p
->ki_numthreads
> 1) ? k
->ki_p
->ki_moretdname
: "");
176 if (showthreads
&& k
->ki_p
->ki_numthreads
> 1)
177 asprintf(&str
, "%s/%s%s", k
->ki_p
->ki_comm
,
178 k
->ki_p
->ki_tdname
, k
->ki_p
->ki_moretdname
);
180 str
= strdup(k
->ki_p
->ki_comm
);
186 tdnam(KINFO
*k
, VARENT
*ve __unused
)
190 if (showthreads
&& k
->ki_p
->ki_numthreads
> 1)
191 asprintf(&str
, "%s%s", k
->ki_p
->ki_tdname
,
192 k
->ki_p
->ki_moretdname
);
200 logname(KINFO
*k
, VARENT
*ve __unused
)
203 if (*k
->ki_p
->ki_login
== '\0')
205 return (strdup(k
->ki_p
->ki_login
));
209 state(KINFO
*k
, VARENT
*ve __unused
)
216 xo_errx(1, "malloc failed");
218 flag
= k
->ki_p
->ki_flag
;
219 tdflags
= k
->ki_p
->ki_tdflags
; /* XXXKSE */
222 switch (k
->ki_p
->ki_stat
) {
229 if (tdflags
& TDF_SINTR
) /* interruptible (long) */
230 *cp
= k
->ki_p
->ki_slptime
>= MAXSLP
? 'I' : 'S';
256 if (k
->ki_p
->ki_nice
< NZERO
|| k
->ki_p
->ki_pri
.pri_class
== PRI_REALTIME
)
258 else if (k
->ki_p
->ki_nice
> NZERO
|| k
->ki_p
->ki_pri
.pri_class
== PRI_IDLE
)
262 if (flag
& P_WEXIT
&& k
->ki_p
->ki_stat
!= SZOMB
)
266 if ((flag
& P_SYSTEM
) || k
->ki_p
->ki_lock
> 0)
268 if ((k
->ki_p
->ki_cr_flags
& CRED_FLAG_CAPMODE
) != 0)
270 if (k
->ki_p
->ki_kiflag
& KI_SLEADER
)
272 if ((flag
& P_CONTROLT
) && k
->ki_p
->ki_pgid
== k
->ki_p
->ki_tpgid
)
280 #define scalepri(x) ((x) - PZERO)
283 pri(KINFO
*k
, VARENT
*ve __unused
)
287 asprintf(&str
, "%d", scalepri(k
->ki_p
->ki_pri
.pri_level
));
292 upr(KINFO
*k
, VARENT
*ve __unused
)
296 asprintf(&str
, "%d", scalepri(k
->ki_p
->ki_pri
.pri_user
));
302 username(KINFO
*k
, VARENT
*ve __unused
)
305 return (strdup(user_from_uid(k
->ki_p
->ki_uid
, 0)));
309 egroupname(KINFO
*k
, VARENT
*ve __unused
)
312 return (strdup(group_from_gid(k
->ki_p
->ki_groups
[0], 0)));
316 rgroupname(KINFO
*k
, VARENT
*ve __unused
)
319 return (strdup(group_from_gid(k
->ki_p
->ki_rgid
, 0)));
323 runame(KINFO
*k
, VARENT
*ve __unused
)
326 return (strdup(user_from_uid(k
->ki_p
->ki_ruid
, 0)));
330 tdev(KINFO
*k
, VARENT
*ve __unused
)
335 dev
= k
->ki_p
->ki_tdev
;
339 asprintf(&str
, "%#jx", (uintmax_t)dev
);
345 tname(KINFO
*k
, VARENT
*ve __unused
)
350 dev
= k
->ki_p
->ki_tdev
;
351 if (dev
== NODEV
|| (ttname
= devname(dev
, S_IFCHR
)) == NULL
)
354 if (strncmp(ttname
, "tty", 3) == 0 ||
355 strncmp(ttname
, "cua", 3) == 0)
357 if (strncmp(ttname
, "pts/", 4) == 0)
359 asprintf(&str
, "%s%c", ttname
,
360 k
->ki_p
->ki_kiflag
& KI_CTTY
? ' ' : '-');
367 longtname(KINFO
*k
, VARENT
*ve __unused
)
372 dev
= k
->ki_p
->ki_tdev
;
373 if (dev
== NODEV
|| (ttname
= devname(dev
, S_IFCHR
)) == NULL
)
376 return (strdup(ttname
));
380 started(KINFO
*k
, VARENT
*ve __unused
)
390 buf
= malloc(buflen
);
392 xo_errx(1, "malloc failed");
394 then
= k
->ki_p
->ki_start
.tv_sec
;
395 tp
= localtime(&then
);
396 if (now
- k
->ki_p
->ki_start
.tv_sec
< 24 * 3600) {
397 (void)strftime(buf
, buflen
, "%H:%M ", tp
);
398 } else if (now
- k
->ki_p
->ki_start
.tv_sec
< 7 * 86400) {
399 (void)strftime(buf
, buflen
, "%a%H ", tp
);
401 (void)strftime(buf
, buflen
, "%e%b%y", tp
);
406 lstarted(KINFO
*k
, VARENT
*ve __unused
)
415 buf
= malloc(buflen
);
417 xo_errx(1, "malloc failed");
419 then
= k
->ki_p
->ki_start
.tv_sec
;
420 (void)strftime(buf
, buflen
, "%c", localtime(&then
));
425 lockname(KINFO
*k
, VARENT
*ve __unused
)
429 if (k
->ki_p
->ki_kiflag
& KI_LOCKBLOCK
) {
430 if (k
->ki_p
->ki_lockname
[0] != 0)
431 str
= strdup(k
->ki_p
->ki_lockname
);
441 wchan(KINFO
*k
, VARENT
*ve __unused
)
445 if (k
->ki_p
->ki_wchan
) {
446 if (k
->ki_p
->ki_wmesg
[0] != 0)
447 str
= strdup(k
->ki_p
->ki_wmesg
);
449 asprintf(&str
, "%lx", (long)k
->ki_p
->ki_wchan
);
457 nwchan(KINFO
*k
, VARENT
*ve __unused
)
461 if (k
->ki_p
->ki_wchan
)
462 asprintf(&str
, "%0lx", (long)k
->ki_p
->ki_wchan
);
470 mwchan(KINFO
*k
, VARENT
*ve __unused
)
474 if (k
->ki_p
->ki_wchan
) {
475 if (k
->ki_p
->ki_wmesg
[0] != 0)
476 str
= strdup(k
->ki_p
->ki_wmesg
);
478 asprintf(&str
, "%lx", (long)k
->ki_p
->ki_wchan
);
479 } else if (k
->ki_p
->ki_kiflag
& KI_LOCKBLOCK
) {
480 if (k
->ki_p
->ki_lockname
[0]) {
481 str
= strdup(k
->ki_p
->ki_lockname
);
491 vsize(KINFO
*k
, VARENT
*ve __unused
)
495 asprintf(&str
, "%lu", (u_long
)(k
->ki_p
->ki_size
/ 1024));
500 printtime(KINFO
*k
, VARENT
*ve __unused
, long secs
, long psecs
)
501 /* psecs is "parts" of a second. first micro, then centi */
503 static char decimal_point
;
506 if (decimal_point
== '\0')
507 decimal_point
= localeconv()->decimal_point
[0];
512 /* round and scale to 100's */
513 psecs
= (psecs
+ 5000) / 10000;
517 asprintf(&str
, "%ld:%02ld%c%02ld",
518 secs
/ 60, secs
% 60, decimal_point
, psecs
);
523 cputime(KINFO
*k
, VARENT
*ve
)
528 * This counts time spent handling interrupts. We could
529 * fix this, but it is not 100% trivial (and interrupt
530 * time fractions only work on the sparc anyway). XXX
532 secs
= k
->ki_p
->ki_runtime
/ 1000000;
533 psecs
= k
->ki_p
->ki_runtime
% 1000000;
535 secs
+= k
->ki_p
->ki_childtime
.tv_sec
;
536 psecs
+= k
->ki_p
->ki_childtime
.tv_usec
;
538 return (printtime(k
, ve
, secs
, psecs
));
542 cpunum(KINFO
*k
, VARENT
*ve __unused
)
546 if (k
->ki_p
->ki_stat
== SRUN
&& k
->ki_p
->ki_oncpu
!= NOCPU
) {
547 asprintf(&cpu
, "%d", k
->ki_p
->ki_oncpu
);
549 asprintf(&cpu
, "%d", k
->ki_p
->ki_lastcpu
);
555 systime(KINFO
*k
, VARENT
*ve
)
559 secs
= k
->ki_p
->ki_rusage
.ru_stime
.tv_sec
;
560 psecs
= k
->ki_p
->ki_rusage
.ru_stime
.tv_usec
;
562 secs
+= k
->ki_p
->ki_childstime
.tv_sec
;
563 psecs
+= k
->ki_p
->ki_childstime
.tv_usec
;
565 return (printtime(k
, ve
, secs
, psecs
));
569 usertime(KINFO
*k
, VARENT
*ve
)
573 secs
= k
->ki_p
->ki_rusage
.ru_utime
.tv_sec
;
574 psecs
= k
->ki_p
->ki_rusage
.ru_utime
.tv_usec
;
576 secs
+= k
->ki_p
->ki_childutime
.tv_sec
;
577 psecs
+= k
->ki_p
->ki_childutime
.tv_usec
;
579 return (printtime(k
, ve
, secs
, psecs
));
583 elapsed(KINFO
*k
, VARENT
*ve __unused
)
586 int days
, hours
, mins
, secs
;
591 val
= now
- k
->ki_p
->ki_start
.tv_sec
;
592 days
= val
/ (24 * 60 * 60);
594 hours
= val
/ (60 * 60);
599 asprintf(&str
, "%3d-%02d:%02d:%02d", days
, hours
, mins
, secs
);
601 asprintf(&str
, "%02d:%02d:%02d", hours
, mins
, secs
);
603 asprintf(&str
, "%02d:%02d", mins
, secs
);
609 elapseds(KINFO
*k
, VARENT
*ve __unused
)
616 val
= now
- k
->ki_p
->ki_start
.tv_sec
;
617 asprintf(&str
, "%jd", (intmax_t)val
);
622 getpcpu(const KINFO
*k
)
631 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
633 /* XXX - I don't like this */
634 if (k
->ki_p
->ki_swtime
== 0)
637 return (100.0 * fxtofl(k
->ki_p
->ki_pctcpu
));
638 return (100.0 * fxtofl(k
->ki_p
->ki_pctcpu
) /
639 (1.0 - exp(k
->ki_p
->ki_swtime
* log(fxtofl(ccpu
)))));
643 pcpu(KINFO
*k
, VARENT
*ve __unused
)
647 asprintf(&str
, "%.1f", getpcpu(k
));
662 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
663 /* XXX don't have info about shared */
664 fracmem
= ((double)k
->ki_p
->ki_rssize
) / mempages
;
665 return (100.0 * fracmem
);
669 pmem(KINFO
*k
, VARENT
*ve __unused
)
673 asprintf(&str
, "%.1f", getpmem(k
));
678 pagein(KINFO
*k
, VARENT
*ve __unused
)
682 asprintf(&str
, "%ld", k
->ki_valid
? k
->ki_p
->ki_rusage
.ru_majflt
: 0);
688 maxrss(KINFO
*k __unused
, VARENT
*ve __unused
)
696 priorityr(KINFO
*k
, VARENT
*ve __unused
)
698 struct priority
*lpri
;
700 unsigned class, level
;
702 lpri
= &k
->ki_p
->ki_pri
;
703 class = lpri
->pri_class
;
704 level
= lpri
->pri_level
;
706 case RTP_PRIO_REALTIME
:
707 /* alias for PRI_REALTIME */
708 asprintf(&str
, "real:%u", level
- PRI_MIN_REALTIME
);
710 case RTP_PRIO_NORMAL
:
711 /* alias for PRI_TIMESHARE */
712 if (level
>= PRI_MIN_TIMESHARE
)
713 asprintf(&str
, "normal:%u", level
- PRI_MIN_TIMESHARE
);
715 asprintf(&str
, "kernel:%u", level
- PRI_MIN_KERN
);
718 /* alias for PRI_IDLE */
719 asprintf(&str
, "idle:%u", level
- PRI_MIN_IDLE
);
722 /* alias for PRI_ITHD */
723 asprintf(&str
, "intr:%u", level
- PRI_MIN_ITHD
);
726 asprintf(&str
, "%u:%u", class, level
);
733 * Generic output routines. Print fields from various prototype
737 printval(void *bp
, VAR
*v
)
739 static char ofmt
[32] = "%";
745 while ((*cp
++ = *fcp
++));
747 #define CHKINF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
751 (void)asprintf(&str
, ofmt
, *(char *)bp
);
754 (void)asprintf(&str
, ofmt
, *(u_char
*)bp
);
757 (void)asprintf(&str
, ofmt
, *(short *)bp
);
760 (void)asprintf(&str
, ofmt
, *(u_short
*)bp
);
763 (void)asprintf(&str
, ofmt
, *(int *)bp
);
766 (void)asprintf(&str
, ofmt
, CHKINF127(*(u_int
*)bp
));
769 (void)asprintf(&str
, ofmt
, *(long *)bp
);
772 (void)asprintf(&str
, ofmt
, *(u_long
*)bp
);
775 (void)asprintf(&str
, ofmt
, *(u_long
*)bp
);
778 (void)asprintf(&str
, ofmt
, ps_pgtok(*(u_long
*)bp
));
786 kvar(KINFO
*k
, VARENT
*ve
)
791 return (printval((char *)((char *)k
->ki_p
+ v
->off
), v
));
795 rvar(KINFO
*k
, VARENT
*ve
)
802 return (printval((char *)((char *)(&k
->ki_p
->ki_rusage
) + v
->off
), v
));
806 emulname(KINFO
*k
, VARENT
*ve __unused
)
809 return (strdup(k
->ki_p
->ki_emul
));
813 label(KINFO
*k
, VARENT
*ve __unused
)
820 if (mac_prepare_process_label(&proclabel
) == -1) {
821 xo_warn("mac_prepare_process_label");
824 error
= mac_get_pid(k
->ki_p
->ki_pid
, proclabel
);
826 if (mac_to_text(proclabel
, &string
) == -1)
835 loginclass(KINFO
*k
, VARENT
*ve __unused
)
839 * Don't display login class for system processes;
840 * login classes are used for resource limits,
841 * and limits don't apply to system processes.
843 if (k
->ki_p
->ki_flag
& P_SYSTEM
) {
844 return (strdup("-"));
846 return (strdup(k
->ki_p
->ki_loginclass
));
850 jailname(KINFO
*k
, VARENT
*ve __unused
)
854 if (k
->ki_p
->ki_jid
== 0)
855 return (strdup("-"));
856 name
= jail_getname(k
->ki_p
->ki_jid
);
858 return (strdup("-"));