Add procstat(1), a process inspection utility. This provides both some

of the missing functionality from procfs(4) and new functionality for
monitoring and debugging specific processes.  procstat(1) operates in
the following modes:

  -b  Display binary information for the process.
  -c  Display command line arguments for the process.
  -f  Display file descriptor information for the process.
  -k  Display the stacks of kernel threads in the process.
  -s  Display security credential information for the process.
  -t  Display thread information for the process.
  -v  Display virtual memory mappings for the process.

Further revision and modes are expected.

Testing, ideas, etc:	cognet, sam, Skip Ford <skip at menantico dot com>
			Wesley Shields <wxs at atarininja dot org>
This commit is contained in:
Robert Watson 2007-12-02 23:31:45 +00:00
parent 02b0457cc2
commit 3d91be41d1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=174199
12 changed files with 1459 additions and 0 deletions

15
usr.bin/procstat/Makefile Normal file
View File

@ -0,0 +1,15 @@
# $FreeBSD$
PROG= procstat
MAN= procstat.1
SRCS= procstat.c \
procstat_args.c \
procstat_basic.c \
procstat_bin.c \
procstat_cred.c \
procstat_files.c \
procstat_kstack.c \
procstat_threads.c \
procstat_vm.c
.include <bsd.prog.mk>

114
usr.bin/procstat/procstat.1 Normal file
View File

@ -0,0 +1,114 @@
.\"-
.\" Copyright (c) 2007 Robert N. M. Watson
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd October 30, 2007
.Dt PROCSTAT 1
.Os
.Sh NAME
.Nm procstat
.Nd get detailed process information
.Sh SYNOPSIS
.Nm
.Op Fl h
.Op Fl w Ar interval
.Op Fl b | c | f | k | s | t | v
.Op Fl a | Ar pid ...
.Sh DESCRIPTION
The
.Nm
utility displays detailed information about the processes identified by the
.Ar pid
arguments, or if the
.Fl a
flag is used, all processes.
.Pp
By default, basic process statistics are printed; one of the following
options may be specified in order to select more detailed process information
for printing:
.Bl -tag -width indent
.It Fl b
Display binary information for the process.
.It Fl c
Display command line arguments for the process.
.It Fl f
Display file descriptor information for the process.
.It Fl k
Display the stacks of kernel threads in the process, excluding stacks of
threads currently running on a CPU and threads with stacks swapped to disk.
If the flag is repeated, function offsets as well as function names are
printed.
This feature requires
.Cd "options STACK"
or
.Cd "options DDB"
to be compiled into the kernel.
.It Fl s
Display security credential information for the process.
.It Fl t
Display thread information for the process.
.It Fl v
Display virtual memory mappings for the process.
.El
.Pp
All options generate output in the format of a table, the first field of
which is the process ID to which the row of information corresponds.
The
.Fl h
flag may be used to suppress table headers.
.Pp
The
.Fl w
flag may be used to specify a wait interval at which to repeat the printing
of the requested process information.
If the
.Fl w
flag is not specified, the output will not repeat.
.Pp
Some information, such as VM and file descriptor information, is available
only to the owner of a process or the superuser.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr fstat 1 ,
.Xr ps 1 ,
.Xr sockstat 1 ,
.Xr DDB 4 ,
.Xr stack 9
.Sh AUTHORS
.An Robert N M Watson
.Sh BUGS
Some field values may include spaces, which limits the extent to which the
output of
.Nm
may be mechanically parsed.
.Pp
The display of open file or memory mapping pathnames is implemented using the
kernel's name cache.
It therefore does not work for file systems
that do not use the name cache, such as
.Xr devfs 4 ,
or if the name is not present in the cache due to removal.

252
usr.bin/procstat/procstat.c Normal file
View File

@ -0,0 +1,252 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include "procstat.h"
static int aflag, bflag, cflag, fflag, kflag, sflag, tflag, vflag;
int hflag;
static void
usage(void)
{
fprintf(stderr, "usage: procstat [-h] [-w interval] [-b | -c | -f | "
"-k | -s | -t | -v]\n");
fprintf(stderr, " [-a | pid ...]\n");
exit(EX_USAGE);
}
static void
procstat(pid_t pid, struct kinfo_proc *kipp)
{
if (bflag)
procstat_bin(pid, kipp);
else if (cflag)
procstat_args(pid, kipp);
else if (fflag)
procstat_files(pid, kipp);
else if (kflag)
procstat_kstack(pid, kipp, kflag);
else if (sflag)
procstat_cred(pid, kipp);
else if (tflag)
procstat_threads(pid, kipp);
else if (vflag)
procstat_vm(pid, kipp);
else
procstat_basic(pid, kipp);
}
/*
* Sort processes first by pid and then tid.
*/
static int
kinfo_proc_compare(const void *a, const void *b)
{
int i;
i = ((struct kinfo_proc *)a)->ki_pid -
((struct kinfo_proc *)b)->ki_pid;
if (i != 0)
return (i);
i = ((struct kinfo_proc *)a)->ki_tid -
((struct kinfo_proc *)b)->ki_tid;
return (i);
}
void
kinfo_proc_sort(struct kinfo_proc *kipp, int count)
{
qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare);
}
int
main(int argc, char *argv[])
{
int ch, i, interval, name[4], tmp;
struct kinfo_proc *kipp;
size_t len;
long l;
pid_t pid;
char *dummy;
interval = 0;
while ((ch = getopt(argc, argv, "abcfkhstvw:")) != -1) {
switch (ch) {
case 'a':
aflag++;
break;
case 'b':
bflag++;
break;
case 'c':
cflag++;
break;
case 'f':
fflag++;
break;
case 'k':
kflag++;
break;
case 'h':
hflag++;
break;
case 's':
sflag++;
break;
case 't':
tflag++;
break;
case 'v':
vflag++;
break;
case 'w':
l = strtol(optarg, &dummy, 10);
if (*dummy != '\0')
usage();
if (l < 1 || l > INT_MAX)
usage();
interval = l;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
/* We require that either 0 or 1 mode flags be set. */
tmp = bflag + cflag + fflag + (kflag ? 1 : 0) + sflag + tflag + vflag;
if (!(tmp == 0 || tmp == 1))
usage();
/* We allow -k to be specified up to twice, but not more. */
if (kflag > 2)
usage();
/* Must specify either the -a flag or a list of pids. */
if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0))
usage();
do {
if (aflag) {
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PROC;
len = 0;
if (sysctl(name, 3, NULL, &len, NULL, 0) < 0)
err(-1, "sysctl: kern.proc.all");
kipp = malloc(len);
if (kipp == NULL)
err(-1, "malloc");
if (sysctl(name, 3, kipp, &len, NULL, 0) < 0) {
free(kipp);
err(-1, "sysctl: kern.proc.all");
}
if (len % sizeof(*kipp) != 0)
err(-1, "kinfo_proc mismatch");
if (kipp->ki_structsize != sizeof(*kipp))
err(-1, "kinfo_proc structure mismatch");
kinfo_proc_sort(kipp, len / sizeof(*kipp));
for (i = 0; i < len / sizeof(*kipp); i++) {
procstat(kipp[i].ki_pid, &kipp[i]);
/* Suppress header after first process. */
hflag = 1;
}
free(kipp);
}
for (i = 0; i < argc; i++) {
l = strtol(argv[i], &dummy, 10);
if (*dummy != '\0')
usage();
if (l < 0)
usage();
pid = l;
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID;
name[3] = pid;
len = 0;
if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
err(-1, "sysctl: kern.proc.pid: %d", pid);
kipp = malloc(len);
if (kipp == NULL)
err(-1, "malloc");
if (sysctl(name, 4, kipp, &len, NULL, 0) < 0) {
free(kipp);
err(-1, "sysctl: kern.proc.pid: %d", pid);
}
if (len != sizeof(*kipp))
err(-1, "kinfo_proc mismatch");
if (kipp->ki_structsize != sizeof(*kipp))
errx(-1, "kinfo_proc structure mismatch");
if (kipp->ki_pid != pid)
errx(-1, "kinfo_proc pid mismatch");
procstat(pid, kipp);
free(kipp);
/* Suppress header after first process. */
hflag = 1;
}
if (interval)
sleep(interval);
} while (interval);
exit(0);
}

View File

@ -0,0 +1,46 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef PROCSTAT_H
#define PROCSTAT_H
extern int hflag;
struct kinfo_proc;
void kinfo_proc_sort(struct kinfo_proc *kipp, int count);
void procstat_args(pid_t pid, struct kinfo_proc *kipp);
void procstat_basic(pid_t pid, struct kinfo_proc *kipp);
void procstat_bin(pid_t pid, struct kinfo_proc *kipp);
void procstat_cred(pid_t pid, struct kinfo_proc *kipp);
void procstat_files(pid_t pid, struct kinfo_proc *kipp);
void procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag);
void procstat_threads(pid_t pid, struct kinfo_proc *kipp);
void procstat_vm(pid_t pid, struct kinfo_proc *kipp);
#endif /* !PROCSTAT_H */

View File

@ -0,0 +1,74 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "procstat.h"
static char args[ARG_MAX];
void
procstat_args(pid_t pid, struct kinfo_proc *kipp)
{
int error, name[4];
size_t len;
char *cp;
if (!hflag)
printf("%5s %-70s\n", "PID", "ARGS");
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_ARGS;
name[3] = pid;
len = sizeof(args);
error = sysctl(name, 4, args, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
warn("sysctl: kern.proc.args: %d", pid);
return;
}
if (error < 0)
return;
if (len == 0 || strlen(args) == 0) {
strcpy(args, "-");
len = strlen(args) + 1;
}
printf("%5d ", pid);
for (cp = args; cp < args + len; cp += strlen(cp) + 1)
printf("%s%s", cp != args ? " " : "", cp);
printf("\n");
}

View File

@ -0,0 +1,64 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include "procstat.h"
void
procstat_basic(pid_t pid, struct kinfo_proc *kipp)
{
if (!hflag)
printf("%5s %5s %5s %5s %5s %3s %-8s %-9s %-13s %-12s\n",
"PID", "PPID", "PGID", "SID", "TSID", "THR", "LOGIN",
"WCHAN", "EMUL", "COMM");
printf("%5d ", kipp->ki_pid);
printf("%5d ", kipp->ki_ppid);
printf("%5d ", kipp->ki_pgid);
printf("%5d ", kipp->ki_sid);
printf("%5d ", kipp->ki_tsid);
printf("%3d ", kipp->ki_numthreads);
printf("%-8s ", strlen(kipp->ki_login) ? kipp->ki_login : "-");
if (kipp->ki_kiflag & KI_LOCKBLOCK) {
printf("*%-8s ", strlen(kipp->ki_lockname) ?
kipp->ki_lockname : "-");
} else {
printf("%-9s ", strlen(kipp->ki_wmesg) ?
kipp->ki_wmesg : "-");
}
printf("%-13s ", strcmp(kipp->ki_emul, "null") ? kipp->ki_emul : "-");
printf("%-12s\n", kipp->ki_comm);
}

View File

@ -0,0 +1,68 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "procstat.h"
void
procstat_bin(pid_t pid, struct kinfo_proc *kipp)
{
char pathname[PATH_MAX];
int error, name[4];
size_t len;
if (!hflag)
printf("%5s %-70s\n", "PID", "PATH");
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PATHNAME;
name[3] = pid;
len = sizeof(pathname);
error = sysctl(name, 4, pathname, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
warn("sysctl: kern.proc.pathname: %d", pid);
return;
}
if (error < 0)
return;
if (len == 0 || strlen(pathname) == 0)
strcpy(pathname, "-");
printf("%5d ", pid);
printf("%s\n", pathname);
}

View File

@ -0,0 +1,57 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <stdio.h>
#include "procstat.h"
void
procstat_cred(pid_t pid, struct kinfo_proc *kipp)
{
int i;
if (!hflag)
printf("%5s %5s %5s %5s %5s %5s %5s %-20s\n", "PID", "EUID",
"RUID", "SVUID", "EGID", "RGID", "SVGID", "GROUPS");
printf("%5d ", pid);
printf("%5d ", kipp->ki_uid);
printf("%5d ", kipp->ki_ruid);
printf("%5d ", kipp->ki_svuid);
printf("%5d ", kipp->ki_groups[0]);
printf("%5d ", kipp->ki_rgid);
printf("%5d ", kipp->ki_svgid);
for (i = 0; i < kipp->ki_ngroups; i++)
printf("%s%d", (i > 0) ? "," : "", kipp->ki_groups[i]);
printf("\n");
}

View File

@ -0,0 +1,303 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/un.h>
#include <sys/user.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "procstat.h"
static const char *
protocol_to_string(int domain, int type, int protocol)
{
switch (domain) {
case AF_INET:
case AF_INET6:
switch (protocol) {
case IPPROTO_TCP:
return ("TCP");
case IPPROTO_UDP:
return ("UDP");
case IPPROTO_ICMP:
return ("ICMP");
case IPPROTO_RAW:
return ("RAW");
case IPPROTO_SCTP:
return ("SCTP");
default:
return ("??");
}
case AF_LOCAL:
switch (type) {
case SOCK_STREAM:
return ("UDSS");
case SOCK_DGRAM:
return ("UDSD");
default:
return ("??");
}
default:
return ("??");
}
}
static void
addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
{
char buffer2[INET6_ADDRSTRLEN];
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
struct sockaddr_un *sun;
switch (ss->ss_family) {
case AF_LOCAL:
sun = (struct sockaddr_un *)ss;
if (strlen(sun->sun_path) == 0)
strlcpy(buffer, "-", buflen);
else
strlcpy(buffer, sun->sun_path, buflen);
break;
case AF_INET:
sin = (struct sockaddr_in *)ss;
snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr),
ntohs(sin->sin_port));
break;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)ss;
if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
sizeof(buffer2)) != NULL)
snprintf(buffer, buflen, "%s.%d", buffer2,
ntohs(sin6->sin6_port));
else
strlcpy(buffer, "-", sizeof(buffer));
break;
default:
strlcpy(buffer, "", buflen);
break;
}
}
static void
print_address(struct sockaddr_storage *ss)
{
char addr[PATH_MAX];
addr_to_string(ss, addr, sizeof(addr));
printf("%-19s", addr);
}
void
procstat_files(pid_t pid, struct kinfo_proc *kipp)
{
struct kinfo_file *freep, *kif;
int error, i, name[4];
const char *str;
size_t len;
if (!hflag)
printf("%5s %3s %1s %1s %-8s %3s %7s %-4s %-35s\n", "PID",
"FD", "T", "V", "FLAGS", "REF", "OFFSET", "PROT",
"NAME");
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_FILEDESC;
name[3] = pid;
error = sysctl(name, 4, NULL, &len, NULL, 0);
if (error < 0 && errno != ESRCH && errno != EPERM) {
warn("sysctl: kern.proc.filedesc: %d", pid);
return;
}
if (error < 0)
return;
freep = kif = malloc(len);
if (kif == NULL)
err(-1, "malloc");
if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
warn("sysctl: kern.proc.filedesc %d", pid);
free(freep);
return;
}
for (i = 0; i < len / sizeof(*kif); i++, kif++) {
if (kif->kf_structsize != sizeof(*kif))
errx(-1, "kinfo_file mismatch");
printf("%5d ", pid);
printf("%3d ", kif->kf_fd);
switch (kif->kf_type) {
case KF_TYPE_VNODE:
str = "v";
break;
case KF_TYPE_SOCKET:
str = "s";
break;
case KF_TYPE_PIPE:
str = "p";
break;
case KF_TYPE_FIFO:
str = "f";
break;
case KF_TYPE_KQUEUE:
str = "k";
break;
case KF_TYPE_CRYPTO:
str = "c";
break;
case KF_TYPE_MQUEUE:
str = "m";
break;
case KF_TYPE_NONE:
case KF_TYPE_UNKNOWN:
default:
str = "?";
break;
}
printf("%1s ", str);
str = "-";
if (kif->kf_type == KF_TYPE_VNODE) {
switch (kif->kf_vnode_type) {
case KF_VTYPE_VREG:
str = "r";
break;
case KF_VTYPE_VDIR:
str = "d";
break;
case KF_VTYPE_VBLK:
str = "b";
break;
case KF_VTYPE_VCHR:
str = "c";
break;
case KF_VTYPE_VLNK:
str = "l";
break;
case KF_VTYPE_VSOCK:
str = "s";
break;
case KF_VTYPE_VFIFO:
str = "f";
break;
case KF_VTYPE_VBAD:
str = "x";
break;
case KF_VTYPE_VNON:
case KF_VTYPE_UNKNOWN:
default:
str = "?";
break;
}
}
printf("%1s ", str);
printf("%s", kif->kf_flags & KF_FLAG_READ ? "r" : "-");
printf("%s", kif->kf_flags & KF_FLAG_WRITE ? "w" : "-");
printf("%s", kif->kf_flags & KF_FLAG_APPEND ? "a" : "-");
printf("%s", kif->kf_flags & KF_FLAG_ASYNC ? "s" : "-");
printf("%s", kif->kf_flags & KF_FLAG_FSYNC ? "f" : "-");
printf("%s", kif->kf_flags & KF_FLAG_NONBLOCK ? "n" : "-");
printf("%s", kif->kf_flags & KF_FLAG_DIRECT ? "d" : "-");
printf("%s ", kif->kf_flags & KF_FLAG_HASLOCK ? "l" : "-");
printf("%3d ", kif->kf_ref_count);
printf("%7jd ", (intmax_t)kif->kf_offset);
switch (kif->kf_type) {
case KF_TYPE_VNODE:
case KF_TYPE_FIFO:
printf("%-4s ", "-");
printf("%-35s", kif->kf_path);
break;
case KF_TYPE_SOCKET:
printf("%-4s ",
protocol_to_string(kif->kf_sock_domain,
kif->kf_sock_type, kif->kf_sock_protocol));
/*
* While generally we like to print two addresses,
* local and peer, for sockets, it turns out to be
* more useful to print the first non-nul address for
* local sockets, as typically they aren't bound and
* connected, and the path strings can get long.
*/
if (kif->kf_sock_domain == AF_LOCAL) {
struct sockaddr_un *sun =
(struct sockaddr_un *)&kif->kf_sa_local;
if (sun->sun_path[0] != 0)
print_address(&kif->kf_sa_local);
else
print_address(&kif->kf_sa_peer);
} else {
print_address(&kif->kf_sa_local);
printf(" ");
print_address(&kif->kf_sa_peer);
}
break;
default:
printf("%-4s ", "-");
printf("%-35s", "-");
}
printf("\n");
}
free(freep);
}

View File

@ -0,0 +1,198 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "procstat.h"
/*
* Walk the stack trace provided by the kernel and reduce it to what we
* actually want to print. This involves stripping true instruction pointers,
* frame numbers, and carriage returns as generated by stack(9). If -kk is
* specified, print the function and offset, otherwise just the function.
*/
enum trace_state { TS_FRAMENUM, TS_PC, TS_AT, TS_FUNC, TS_OFF };
static enum trace_state
kstack_nextstate(enum trace_state ts)
{
switch (ts) {
case TS_FRAMENUM:
return (TS_PC);
case TS_PC:
return (TS_AT);
case TS_AT:
return (TS_FUNC);
case TS_FUNC:
return (TS_OFF);
case TS_OFF:
return TS_FRAMENUM;
default:
errx(-1, "kstack_nextstate");
}
}
static void
kstack_cleanup(const char *old, char *new, int kflag)
{
enum trace_state old_ts, ts;
const char *cp_old;
char *cp_new;
ts = TS_FRAMENUM;
for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) {
switch (*cp_old) {
case ' ':
case '\n':
case '+':
old_ts = ts;
ts = kstack_nextstate(old_ts);
if (old_ts == TS_OFF) {
*cp_new = ' ';
cp_new++;
}
if (kflag > 1 && old_ts == TS_FUNC) {
*cp_new = '+';
cp_new++;
}
continue;
}
if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) {
*cp_new = *cp_old;
cp_new++;
}
}
*cp_new = '\0';
}
/*
* Sort threads by tid.
*/
static int
kinfo_kstack_compare(const void *a, const void *b)
{
return ((struct kinfo_kstack *)a)->kkst_tid -
((struct kinfo_kstack *)b)->kkst_tid;
}
static void
kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count)
{
qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare);
}
void
procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
{
struct kinfo_kstack *kkstp, *kkstp_free;
char trace[KKST_MAXLEN];
int error, i, name[4];
size_t len;
if (!hflag)
printf("%5s %6s %-20s %-45s\n", "PID", "TID", "COMM",
"KSTACK");
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_KSTACK;
name[3] = pid;
len = 0;
error = sysctl(name, 4, NULL, &len, NULL, 0);
if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
warn("sysctl: kern.proc.kstack: %d", pid);
return;
}
if (error < 0 && errno == ENOENT)
errx(-1, "kern.proc.kstack sysctl unavailable; options DDB "
"is required.");
if (error < 0)
return;
kkstp = kkstp_free = malloc(len);
if (kkstp == NULL)
err(-1, "malloc");
if (sysctl(name, 4, kkstp, &len, NULL, 0) < 0) {
warn("sysctl: kern.proc.pid: %d", pid);
free(kkstp);
return;
}
kinfo_kstack_sort(kkstp, len / sizeof(*kkstp));
for (i = 0; i < len / sizeof(*kkstp); i++) {
kkstp = &kkstp_free[i];
printf("%5d ", pid);
printf("%6d ", kkstp->kkst_tid);
printf("%-20s ", kipp->ki_comm);
switch (kkstp->kkst_state) {
case KKST_STATE_RUNNING:
printf("%-45s\n", "<running>");
continue;
case KKST_STATE_SWAPPED:
printf("%-45s\n", "<swapped>");
continue;
case KKST_STATE_STACKOK:
break;
default:
printf("%-45s\n", "<unknown>");
continue;
}
/*
* The kernel generates a trace with carriage returns between
* entries, but for a more compact view, we convert carriage
* returns to spaces.
*/
kstack_cleanup(kkstp->kkst_trace, trace, kflag);
printf("%-45s\n", trace);
}
free(kkstp_free);
}

View File

@ -0,0 +1,138 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "procstat.h"
void
procstat_threads(pid_t pid, struct kinfo_proc *kipp)
{
struct kinfo_proc *kip;
int error, i, name[4];
const char *str;
size_t len;
if (!hflag)
printf("%5s %6s %-20s %2s %4s %-7s %-9s\n", "PID", "TID",
"COMM", "CPU", "PRI", "STATE", "WCHAN");
/*
* We need to re-query for thread information, so don't use *kipp.
*/
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
name[3] = pid;
len = 0;
error = sysctl(name, 4, NULL, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
warn("sysctl: kern.proc.pid: %d", pid);
return;
}
if (error < 0)
return;
kip = malloc(len);
if (kip == NULL)
err(-1, "malloc");
if (sysctl(name, 4, kip, &len, NULL, 0) < 0) {
warn("sysctl: kern.proc.pid: %d", pid);
free(kip);
return;
}
kinfo_proc_sort(kip, len / sizeof(*kipp));
for (i = 0; i < len / sizeof(*kipp); i++) {
kipp = &kip[i];
printf("%5d ", pid);
printf("%6d ", kipp->ki_tid);
printf("%-20s ", strlen(kipp->ki_comm) ?
kipp->ki_comm : "-");
if (kipp->ki_oncpu != 255)
printf("%3d ", kipp->ki_oncpu);
else if (kipp->ki_lastcpu != 255)
printf("%3d ", kipp->ki_lastcpu);
else
printf("%3s ", "-");
printf("%4d ", kipp->ki_pri.pri_level);
switch (kipp->ki_stat) {
case SRUN:
str = "run";
break;
case SSTOP:
str = "stop";
break;
case SSLEEP:
str = "sleep";
break;
case SLOCK:
str = "lock";
break;
case SWAIT:
str = "wait";
break;
case SZOMB:
str = "zomb";
break;
case SIDL:
str = "idle";
break;
default:
str = "??";
break;
}
printf("%-7s ", str);
if (kipp->ki_kiflag & KI_LOCKBLOCK) {
printf("*%-8s ", strlen(kipp->ki_lockname) ?
kipp->ki_lockname : "-");
} else {
printf("%-9s ", strlen(kipp->ki_wmesg) ?
kipp->ki_wmesg : "-");
}
printf("\n");
}
free(kip);
}

View File

@ -0,0 +1,130 @@
/*-
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "procstat.h"
void
procstat_vm(pid_t pid, struct kinfo_proc *kipp)
{
struct kinfo_vmentry *freep, *kve;
int error, i, name[4], ptrwidth;
const char *str;
size_t len;
ptrwidth = 2*sizeof(void *) + 2;
if (!hflag)
printf("%5s %*s %*s %3s %4s %4s %3s %3s %2s %-2s %-s\n",
"PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
"PRES", "REF", "SHD", "FL", "TP", "PATH");
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_VMMAP;
name[3] = pid;
len = 0;
error = sysctl(name, 4, NULL, &len, NULL, 0);
if (error < 0 && errno != ESRCH && errno != EPERM) {
warn("sysctl: kern.proc.vmmap: %d", pid);
return;
}
if (error < 0)
return;
/*
* Especially if running procstat -sv, we may need room for more
* mappings when printing than were present when we queried, so pad
* out the allocation a bit.
*/
len += sizeof(*kve) * 3;
freep = kve = malloc(len);
if (kve == NULL)
err(-1, "malloc");
if (sysctl(name, 4, kve, &len, NULL, 0) < 0) {
warn("sysctl: kern.proc.vmmap: %d", pid);
free(freep);
return;
}
for (i = 0; i < (len / sizeof(*kve)); i++, kve++) {
if (kve->kve_structsize != sizeof(*kve))
errx(-1, "kinfo_vmentry structure mismatch");
printf("%5d ", pid);
printf("%*p ", ptrwidth, kve->kve_start);
printf("%*p ", ptrwidth, kve->kve_end);
printf("%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
printf("%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
printf("%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
printf("%4d ", kve->kve_resident);
printf("%4d ", kve->kve_private_resident);
printf("%3d ", kve->kve_ref_count);
printf("%3d ", kve->kve_shadow_count);
printf("%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
printf("%-1s ", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
"-");
switch (kve->kve_type) {
case KVME_TYPE_NONE:
str = "--";
break;
case KVME_TYPE_DEFAULT:
str = "df";
break;
case KVME_TYPE_VNODE:
str = "vn";
break;
case KVME_TYPE_SWAP:
str = "sw";
break;
case KVME_TYPE_DEVICE:
str = "dv";
break;
case KVME_TYPE_PHYS:
str = "ph";
break;
case KVME_TYPE_DEAD:
str = "dd";
break;
case KVME_TYPE_UNKNOWN:
default:
str = "??";
break;
}
printf("%-2s ", str);
printf("%-s\n", kve->kve_path);
}
free(freep);
}