summaryrefslogtreecommitdiffstats
path: root/usr.bin/procstat
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2007-12-02 23:31:45 +0000
committerrwatson <rwatson@FreeBSD.org>2007-12-02 23:31:45 +0000
commit88563131a07695a978d1ea8d582fcaef2bbcf495 (patch)
tree7dbb26f0de9b1cdfcb17b3932fafcf867ce71aa3 /usr.bin/procstat
parent2cfd49de5b26f76b5592e60721eee0cb4d5981e7 (diff)
downloadFreeBSD-src-88563131a07695a978d1ea8d582fcaef2bbcf495.zip
FreeBSD-src-88563131a07695a978d1ea8d582fcaef2bbcf495.tar.gz
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>
Diffstat (limited to 'usr.bin/procstat')
-rw-r--r--usr.bin/procstat/Makefile15
-rw-r--r--usr.bin/procstat/procstat.1114
-rw-r--r--usr.bin/procstat/procstat.c252
-rw-r--r--usr.bin/procstat/procstat.h46
-rw-r--r--usr.bin/procstat/procstat_args.c74
-rw-r--r--usr.bin/procstat/procstat_basic.c64
-rw-r--r--usr.bin/procstat/procstat_bin.c68
-rw-r--r--usr.bin/procstat/procstat_cred.c57
-rw-r--r--usr.bin/procstat/procstat_files.c303
-rw-r--r--usr.bin/procstat/procstat_kstack.c198
-rw-r--r--usr.bin/procstat/procstat_threads.c138
-rw-r--r--usr.bin/procstat/procstat_vm.c130
12 files changed, 1459 insertions, 0 deletions
diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile
new file mode 100644
index 0000000..e3c77e4
--- /dev/null
+++ b/usr.bin/procstat/Makefile
@@ -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>
diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1
new file mode 100644
index 0000000..98a78b0
--- /dev/null
+++ b/usr.bin/procstat/procstat.1
@@ -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.
diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c
new file mode 100644
index 0000000..d039831
--- /dev/null
+++ b/usr.bin/procstat/procstat.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h
new file mode 100644
index 0000000..8bacab7
--- /dev/null
+++ b/usr.bin/procstat/procstat.h
@@ -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 */
diff --git a/usr.bin/procstat/procstat_args.c b/usr.bin/procstat/procstat_args.c
new file mode 100644
index 0000000..f4a27a0
--- /dev/null
+++ b/usr.bin/procstat/procstat_args.c
@@ -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");
+}
diff --git a/usr.bin/procstat/procstat_basic.c b/usr.bin/procstat/procstat_basic.c
new file mode 100644
index 0000000..1fd3277
--- /dev/null
+++ b/usr.bin/procstat/procstat_basic.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat_bin.c b/usr.bin/procstat/procstat_bin.c
new file mode 100644
index 0000000..a6757eb
--- /dev/null
+++ b/usr.bin/procstat/procstat_bin.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat_cred.c b/usr.bin/procstat/procstat_cred.c
new file mode 100644
index 0000000..a1fc89b
--- /dev/null
+++ b/usr.bin/procstat/procstat_cred.c
@@ -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");
+}
diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c
new file mode 100644
index 0000000..e36fc01
--- /dev/null
+++ b/usr.bin/procstat/procstat_files.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat_kstack.c b/usr.bin/procstat/procstat_kstack.c
new file mode 100644
index 0000000..c36720a
--- /dev/null
+++ b/usr.bin/procstat/procstat_kstack.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat_threads.c b/usr.bin/procstat/procstat_threads.c
new file mode 100644
index 0000000..dbfde79
--- /dev/null
+++ b/usr.bin/procstat/procstat_threads.c
@@ -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);
+}
diff --git a/usr.bin/procstat/procstat_vm.c b/usr.bin/procstat/procstat_vm.c
new file mode 100644
index 0000000..5a00587
--- /dev/null
+++ b/usr.bin/procstat/procstat_vm.c
@@ -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);
+}
OpenPOWER on IntegriCloud