diff options
author | rwatson <rwatson@FreeBSD.org> | 2007-12-02 23:31:45 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2007-12-02 23:31:45 +0000 |
commit | 88563131a07695a978d1ea8d582fcaef2bbcf495 (patch) | |
tree | 7dbb26f0de9b1cdfcb17b3932fafcf867ce71aa3 /usr.bin/procstat | |
parent | 2cfd49de5b26f76b5592e60721eee0cb4d5981e7 (diff) | |
download | FreeBSD-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/Makefile | 15 | ||||
-rw-r--r-- | usr.bin/procstat/procstat.1 | 114 | ||||
-rw-r--r-- | usr.bin/procstat/procstat.c | 252 | ||||
-rw-r--r-- | usr.bin/procstat/procstat.h | 46 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_args.c | 74 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_basic.c | 64 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_bin.c | 68 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_cred.c | 57 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_files.c | 303 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_kstack.c | 198 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_threads.c | 138 | ||||
-rw-r--r-- | usr.bin/procstat/procstat_vm.c | 130 |
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); +} |