summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pstat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pstat')
-rw-r--r--usr.sbin/pstat/Makefile11
-rw-r--r--usr.sbin/pstat/Makefile.depend21
-rw-r--r--usr.sbin/pstat/pstat.8251
-rw-r--r--usr.sbin/pstat/pstat.c597
4 files changed, 880 insertions, 0 deletions
diff --git a/usr.sbin/pstat/Makefile b/usr.sbin/pstat/Makefile
new file mode 100644
index 0000000..e3b0533
--- /dev/null
+++ b/usr.sbin/pstat/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= pstat
+LINKS= ${BINDIR}/pstat ${BINDIR}/swapinfo
+MAN= pstat.8
+MLINKS= pstat.8 swapinfo.8
+
+LIBADD= kvm util
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pstat/Makefile.depend b/usr.sbin/pstat/Makefile.depend
new file mode 100644
index 0000000..7c356c9
--- /dev/null
+++ b/usr.sbin/pstat/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libelf \
+ lib/libkvm \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/pstat/pstat.8 b/usr.sbin/pstat/pstat.8
new file mode 100644
index 0000000..cd13994
--- /dev/null
+++ b/usr.sbin/pstat/pstat.8
@@ -0,0 +1,251 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software was developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)pstat.8 8.5 (Berkeley) 5/13/94
+.\" $FreeBSD$
+.\"
+.Dd October 11, 2014
+.Dt PSTAT 8
+.Os
+.Sh NAME
+.Nm pstat ,
+.Nm swapinfo
+.Nd display system data structures
+.Sh SYNOPSIS
+.Nm
+.Op Fl Tfghkmnst
+.Op Fl M Ar core Op Fl N Ar system
+.Nm swapinfo
+.Op Fl ghkm
+.Op Fl M Ar core Op Fl N Ar system
+.Sh DESCRIPTION
+The
+.Nm
+utility displays open file entry, swap space utilization,
+terminal state, and vnode data structures.
+.Pp
+If invoked as
+.Nm swapinfo
+the
+.Fl s
+option is implied, and only the
+.Fl k , m , g ,
+and
+.Fl h
+options are legal.
+.Pp
+If the
+.Fl M
+option is not specified, information is obtained from
+the currently running kernel via the
+.Xr sysctl 3
+interface.
+Otherwise, information is read from the specified core file,
+using the name list from the specified kernel image (or from
+the default image).
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl n
+Print devices out by major/minor instead of name.
+.It Fl h
+.Dq Human-readable
+output.
+Use unit suffixes when printing swap partition sizes:
+Byte, Kilobyte, Megabyte, Gigabyte, Terabyte and Petabyte.
+.It Fl k
+Print sizes in kilobytes, regardless of the setting of the
+.Ev BLOCKSIZE
+environment variable.
+.It Fl m
+Print sizes in megabytes, regardless of the setting of the
+.Ev BLOCKSIZE
+environment variable.
+.It Fl g
+Print sizes in gigabytes, regardless of the setting of the
+.Ev BLOCKSIZE
+environment variable.
+.It Fl T
+Print the number of used and free slots in several system tables.
+This is useful for checking to see how large system tables have become
+if the system is under heavy load.
+.It Fl f
+Print the open file table with these headings:
+.Bl -tag -width indent
+.It LOC
+The core location of this table entry.
+.It TYPE
+The type of object the file table entry points to.
+.It FLG
+Miscellaneous state variables encoded thus:
+.Pp
+.Bl -tag -width indent -compact
+.It R
+open for reading
+.It W
+open for writing
+.It A
+open for appending
+.It I
+signal pgrp when data ready
+.El
+.It CNT
+Number of processes that know this open file.
+.It MSG
+Number of messages outstanding for this file.
+.It DATA
+The location of the vnode table entry or socket structure for this file.
+.It OFFSET
+The file offset (see
+.Xr lseek 2 ) .
+.El
+.It Fl s
+Print information about swap space usage on all the
+swap areas compiled into the kernel.
+The first column is the device name of the partition.
+The next column is
+the total space available in the partition.
+The
+.Ar Used
+column indicates the total blocks used so far; the
+.Ar Available
+column indicates how much space is remaining on each partition.
+The
+.Ar Capacity
+reports the percentage of space used.
+.Pp
+If more than one partition is configured into the system, totals for all
+of the statistics will be reported in the final line of the report.
+.It Fl t
+Print table for terminals
+with these headings:
+.Bl -tag -width indent
+.It LINE
+Device name.
+.It INQ
+Number of characters that can be stored in the input queue.
+.It CAN
+Number of characters in the input queue which can be read.
+.It LIN
+Number of characters in the input queue which cannot be read yet.
+.It LOW
+Low water mark for input.
+.It OUTQ
+Number of characters that can be stored in the output queue.
+.It USE
+Number of bytes in the output queue.
+.It LOW
+Low water mark for output.
+.It COL
+Calculated column position of terminal.
+.It SESS
+Process ID of the session leader.
+.It PGID
+Process group for which this is the controlling terminal.
+.It STATE
+Miscellaneous state variables encoded thus:
+.Pp
+.Bl -tag -width indent -compact
+.It I
+init/lock-state device nodes present
+.It C
+callout device nodes present
+.It O
+opened
+.It c
+console in use
+.It G
+gone
+.It B
+busy in
+.Xr open 2
+.It Y
+send SIGIO for input events
+.It L
+next character is literal
+.It H
+high watermark reached
+.It X
+open for exclusive use
+.It S
+output stopped (ixon flow control)
+.It l
+block mode input routine in use
+.It Z
+connection lost
+.It s
+i/o being snooped
+.It b
+busy in
+.Xr read 2
+or
+.Xr write 2
+.El
+.Pp
+The
+.Ql i
+and
+.Ql o
+characters refer to the previous character, to differentiate between
+input and output.
+.El
+.It Fl M
+Extract values associated with the name list from the specified core.
+.It Fl N
+If
+.Fl M
+is also specified,
+extract the name list from the specified system instead of the default,
+which is the kernel image the system has booted from.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr systat 1 ,
+.Xr stat 2 ,
+.Xr fs 5 ,
+.Xr iostat 8 ,
+.Xr vmstat 8
+.Rs
+.%T UNIX Implementation
+.%A K. Thompson
+.Re
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.0 .
+.Sh BUGS
+Does not understand
+.Tn NFS
+swap servers.
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
new file mode 100644
index 0000000..2017841
--- /dev/null
+++ b/usr.sbin/pstat/pstat.c
@@ -0,0 +1,597 @@
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/stdint.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/blist.h>
+
+#include <sys/sysctl.h>
+#include <vm/vm_param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <libutil.h>
+#include <limits.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+enum {
+ NL_CONSTTY,
+ NL_MAXFILES,
+ NL_NFILES,
+ NL_TTY_LIST,
+ NL_MARKER
+};
+
+static struct {
+ int order;
+ const char *name;
+} namelist[] = {
+ { NL_CONSTTY, "_constty" },
+ { NL_MAXFILES, "_maxfiles" },
+ { NL_NFILES, "_openfiles" },
+ { NL_TTY_LIST, "_tty_list" },
+ { NL_MARKER, "" },
+};
+#define NNAMES (sizeof(namelist) / sizeof(*namelist))
+static struct nlist nl[NNAMES];
+
+static int humanflag;
+static int usenumflag;
+static int totalflag;
+static int swapflag;
+static char *nlistf;
+static char *memf;
+static kvm_t *kd;
+
+static const char *usagestr;
+
+static void filemode(void);
+static int getfiles(struct xfile **, size_t *);
+static void swapmode(void);
+static void ttymode(void);
+static void ttyprt(struct xtty *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, quit, ret;
+ int fileflag, ttyflag;
+ unsigned int i;
+ char buf[_POSIX2_LINE_MAX];
+ const char *opts;
+
+ fileflag = swapflag = ttyflag = 0;
+
+ /* We will behave like good old swapinfo if thus invoked */
+ opts = strrchr(argv[0], '/');
+ if (opts)
+ opts++;
+ else
+ opts = argv[0];
+ if (!strcmp(opts, "swapinfo")) {
+ swapflag = 1;
+ opts = "ghkmM:N:";
+ usagestr = "swapinfo [-ghkm] [-M core [-N system]]";
+ } else {
+ opts = "TM:N:fghkmnst";
+ usagestr = "pstat [-Tfghkmnst] [-M core [-N system]]";
+ }
+
+ while ((ch = getopt(argc, argv, opts)) != -1)
+ switch (ch) {
+ case 'f':
+ fileflag = 1;
+ break;
+ case 'g':
+ setenv("BLOCKSIZE", "1G", 1);
+ break;
+ case 'h':
+ humanflag = 1;
+ break;
+ case 'k':
+ setenv("BLOCKSIZE", "1K", 1);
+ break;
+ case 'm':
+ setenv("BLOCKSIZE", "1M", 1);
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'n':
+ usenumflag = 1;
+ break;
+ case 's':
+ ++swapflag;
+ break;
+ case 'T':
+ totalflag = 1;
+ break;
+ case 't':
+ ttyflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Initialize symbol names list.
+ */
+ for (i = 0; i < NNAMES; i++)
+ nl[namelist[i].order].n_name = strdup(namelist[i].name);
+
+ if (memf != NULL) {
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
+ if (kd == NULL)
+ errx(1, "kvm_openfiles: %s", buf);
+ if ((ret = kvm_nlist(kd, nl)) != 0) {
+ if (ret == -1)
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+ quit = 0;
+ for (i = 0; nl[i].n_name[0] != '\0'; ++i)
+ if (nl[i].n_value == 0) {
+ quit = 1;
+ warnx("undefined symbol: %s",
+ nl[i].n_name);
+ }
+ if (quit)
+ exit(1);
+ }
+ }
+ if (!(fileflag | ttyflag | swapflag | totalflag))
+ usage();
+ if (fileflag || totalflag)
+ filemode();
+ if (ttyflag)
+ ttymode();
+ if (swapflag || totalflag)
+ swapmode();
+ exit (0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s\n", usagestr);
+ exit (1);
+}
+
+static const char fhdr32[] =
+ " LOC TYPE FLG CNT MSG DATA OFFSET\n";
+/* c0000000 ------ RWAI 123 123 c0000000 1000000000000000 */
+
+static const char fhdr64[] =
+ " LOC TYPE FLG CNT MSG DATA OFFSET\n";
+/* c000000000000000 ------ RWAI 123 123 c000000000000000 1000000000000000 */
+
+static const char hdr[] =
+" LINE INQ CAN LIN LOW OUTQ USE LOW COL SESS PGID STATE\n";
+
+static void
+ttymode_kvm(void)
+{
+ TAILQ_HEAD(, tty) tl;
+ struct tty *tp, tty;
+ struct xtty xt;
+
+ (void)printf("%s", hdr);
+ bzero(&xt, sizeof xt);
+ xt.xt_size = sizeof xt;
+ if (kvm_read(kd, nl[NL_TTY_LIST].n_value, &tl, sizeof tl) != sizeof tl)
+ errx(1, "kvm_read(): %s", kvm_geterr(kd));
+ tp = TAILQ_FIRST(&tl);
+ while (tp != NULL) {
+ if (kvm_read(kd, (u_long)tp, &tty, sizeof tty) != sizeof tty)
+ errx(1, "kvm_read(): %s", kvm_geterr(kd));
+ xt.xt_insize = tty.t_inq.ti_nblocks * TTYINQ_DATASIZE;
+ xt.xt_incc = tty.t_inq.ti_linestart - tty.t_inq.ti_begin;
+ xt.xt_inlc = tty.t_inq.ti_end - tty.t_inq.ti_linestart;
+ xt.xt_inlow = tty.t_inlow;
+ xt.xt_outsize = tty.t_outq.to_nblocks * TTYOUTQ_DATASIZE;
+ xt.xt_outcc = tty.t_outq.to_end - tty.t_outq.to_begin;
+ xt.xt_outlow = tty.t_outlow;
+ xt.xt_column = tty.t_column;
+ /* xt.xt_pgid = ... */
+ /* xt.xt_sid = ... */
+ xt.xt_flags = tty.t_flags;
+ xt.xt_dev = NODEV;
+ ttyprt(&xt);
+ tp = TAILQ_NEXT(&tty, t_list);
+ }
+}
+
+static void
+ttymode_sysctl(void)
+{
+ struct xtty *xttys;
+ size_t len;
+ unsigned int i, n;
+
+ (void)printf("%s", hdr);
+ if ((xttys = malloc(len = sizeof(*xttys))) == NULL)
+ err(1, "malloc()");
+ while (sysctlbyname("kern.ttys", xttys, &len, 0, 0) == -1) {
+ if (errno != ENOMEM)
+ err(1, "sysctlbyname()");
+ len *= 2;
+ if ((xttys = realloc(xttys, len)) == NULL)
+ err(1, "realloc()");
+ }
+ n = len / sizeof(*xttys);
+ for (i = 0; i < n; i++)
+ ttyprt(&xttys[i]);
+}
+
+static void
+ttymode(void)
+{
+
+ if (kd != NULL)
+ ttymode_kvm();
+ else
+ ttymode_sysctl();
+}
+
+static struct {
+ int flag;
+ char val;
+} ttystates[] = {
+#if 0
+ { TF_NOPREFIX, 'N' },
+#endif
+ { TF_INITLOCK, 'I' },
+ { TF_CALLOUT, 'C' },
+
+ /* Keep these together -> 'Oi' and 'Oo'. */
+ { TF_OPENED, 'O' },
+ { TF_OPENED_IN, 'i' },
+ { TF_OPENED_OUT, 'o' },
+ { TF_OPENED_CONS, 'c' },
+
+ { TF_GONE, 'G' },
+ { TF_OPENCLOSE, 'B' },
+ { TF_ASYNC, 'Y' },
+ { TF_LITERAL, 'L' },
+
+ /* Keep these together -> 'Hi' and 'Ho'. */
+ { TF_HIWAT, 'H' },
+ { TF_HIWAT_IN, 'i' },
+ { TF_HIWAT_OUT, 'o' },
+
+ { TF_STOPPED, 'S' },
+ { TF_EXCLUDE, 'X' },
+ { TF_BYPASS, 'l' },
+ { TF_ZOMBIE, 'Z' },
+ { TF_HOOK, 's' },
+
+ /* Keep these together -> 'bi' and 'bo'. */
+ { TF_BUSY, 'b' },
+ { TF_BUSY_IN, 'i' },
+ { TF_BUSY_OUT, 'o' },
+
+ { 0, '\0'},
+};
+
+static void
+ttyprt(struct xtty *xt)
+{
+ int i, j;
+ char *name;
+
+ if (xt->xt_size != sizeof *xt)
+ errx(1, "struct xtty size mismatch");
+ if (usenumflag || xt->xt_dev == 0 ||
+ (name = devname(xt->xt_dev, S_IFCHR)) == NULL)
+ printf("%#10jx ", (uintmax_t)xt->xt_dev);
+ else
+ printf("%10s ", name);
+ printf("%5zu %4zu %4zu %4zu %5zu %4zu %4zu %5u %5d %5d ",
+ xt->xt_insize, xt->xt_incc, xt->xt_inlc,
+ (xt->xt_insize - xt->xt_inlow), xt->xt_outsize,
+ xt->xt_outcc, (xt->xt_outsize - xt->xt_outlow),
+ MIN(xt->xt_column, 99999), xt->xt_sid, xt->xt_pgid);
+ for (i = j = 0; ttystates[i].flag; i++)
+ if (xt->xt_flags & ttystates[i].flag) {
+ putchar(ttystates[i].val);
+ j++;
+ }
+ if (j == 0)
+ putchar('-');
+ putchar('\n');
+}
+
+static void
+filemode(void)
+{
+ struct xfile *fp, *buf;
+ char flagbuf[16], *fbp;
+ int maxf, openf;
+ size_t len;
+ static char const * const dtypes[] = { "???", "inode", "socket",
+ "pipe", "fifo", "kqueue", "crypto" };
+ int i;
+ int wid;
+
+ if (kd != NULL) {
+ if (kvm_read(kd, nl[NL_MAXFILES].n_value,
+ &maxf, sizeof maxf) != sizeof maxf ||
+ kvm_read(kd, nl[NL_NFILES].n_value,
+ &openf, sizeof openf) != sizeof openf)
+ errx(1, "kvm_read(): %s", kvm_geterr(kd));
+ } else {
+ len = sizeof(int);
+ if (sysctlbyname("kern.maxfiles", &maxf, &len, 0, 0) == -1 ||
+ sysctlbyname("kern.openfiles", &openf, &len, 0, 0) == -1)
+ err(1, "sysctlbyname()");
+ }
+
+ if (totalflag) {
+ (void)printf("%3d/%3d files\n", openf, maxf);
+ return;
+ }
+ if (getfiles(&buf, &len) == -1)
+ return;
+ openf = len / sizeof *fp;
+
+ (void)printf("%d/%d open files\n", openf, maxf);
+ printf(sizeof(uintptr_t) == 4 ? fhdr32 : fhdr64);
+ wid = (int)sizeof(uintptr_t) * 2;
+ for (fp = (struct xfile *)buf, i = 0; i < openf; ++fp, ++i) {
+ if ((size_t)fp->xf_type >= sizeof(dtypes) / sizeof(dtypes[0]))
+ continue;
+ (void)printf("%*jx", wid, (uintmax_t)(uintptr_t)fp->xf_file);
+ (void)printf(" %-6.6s", dtypes[fp->xf_type]);
+ fbp = flagbuf;
+ if (fp->xf_flag & FREAD)
+ *fbp++ = 'R';
+ if (fp->xf_flag & FWRITE)
+ *fbp++ = 'W';
+ if (fp->xf_flag & FAPPEND)
+ *fbp++ = 'A';
+ if (fp->xf_flag & FASYNC)
+ *fbp++ = 'I';
+ *fbp = '\0';
+ (void)printf(" %4s %3d", flagbuf, fp->xf_count);
+ (void)printf(" %3d", fp->xf_msgcount);
+ (void)printf(" %*jx", wid, (uintmax_t)(uintptr_t)fp->xf_data);
+ (void)printf(" %*jx\n", (int)sizeof(fp->xf_offset) * 2,
+ (uintmax_t)fp->xf_offset);
+ }
+ free(buf);
+}
+
+static int
+getfiles(struct xfile **abuf, size_t *alen)
+{
+ struct xfile *buf;
+ size_t len;
+ int mib[2];
+
+ /*
+ * XXX
+ * Add emulation of KINFO_FILE here.
+ */
+ if (kd != NULL)
+ errx(1, "files on dead kernel, not implemented");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_FILE;
+ if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
+ warn("sysctl: KERN_FILE");
+ return (-1);
+ }
+ if ((buf = malloc(len)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
+ warn("sysctl: KERN_FILE");
+ return (-1);
+ }
+ *abuf = buf;
+ *alen = len;
+ return (0);
+}
+
+/*
+ * swapmode is based on a program called swapinfo written
+ * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+
+#define CONVERT(v) ((int64_t)(v) * pagesize / blocksize)
+#define CONVERT_BLOCKS(v) ((int64_t)(v) * pagesize)
+static struct kvm_swap swtot;
+static int nswdev;
+
+static void
+print_swap_header(void)
+{
+ int hlen;
+ long blocksize;
+ const char *header;
+
+ header = getbsize(&hlen, &blocksize);
+ if (totalflag == 0)
+ (void)printf("%-15s %*s %8s %8s %8s\n",
+ "Device", hlen, header,
+ "Used", "Avail", "Capacity");
+}
+
+static void
+print_swap_line(const char *swdevname, intmax_t nblks, intmax_t bused,
+ intmax_t bavail, float bpercent)
+{
+ char usedbuf[5];
+ char availbuf[5];
+ int hlen, pagesize;
+ long blocksize;
+
+ pagesize = getpagesize();
+ getbsize(&hlen, &blocksize);
+
+ printf("%-15s %*jd ", swdevname, hlen, CONVERT(nblks));
+ if (humanflag) {
+ humanize_number(usedbuf, sizeof(usedbuf),
+ CONVERT_BLOCKS(bused), "",
+ HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+ humanize_number(availbuf, sizeof(availbuf),
+ CONVERT_BLOCKS(bavail), "",
+ HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+ printf("%8s %8s %5.0f%%\n", usedbuf, availbuf, bpercent);
+ } else {
+ printf("%8jd %8jd %5.0f%%\n", (intmax_t)CONVERT(bused),
+ (intmax_t)CONVERT(bavail), bpercent);
+ }
+}
+
+static void
+print_swap(struct kvm_swap *ksw)
+{
+
+ swtot.ksw_total += ksw->ksw_total;
+ swtot.ksw_used += ksw->ksw_used;
+ ++nswdev;
+ if (totalflag == 0)
+ print_swap_line(ksw->ksw_devname, ksw->ksw_total,
+ ksw->ksw_used, ksw->ksw_total - ksw->ksw_used,
+ (ksw->ksw_used * 100.0) / ksw->ksw_total);
+}
+
+static void
+print_swap_total(void)
+{
+ int hlen, pagesize;
+ long blocksize;
+
+ pagesize = getpagesize();
+ getbsize(&hlen, &blocksize);
+ if (totalflag) {
+ blocksize = 1024 * 1024;
+ (void)printf("%jdM/%jdM swap space\n",
+ CONVERT(swtot.ksw_used), CONVERT(swtot.ksw_total));
+ } else if (nswdev > 1) {
+ print_swap_line("Total", swtot.ksw_total, swtot.ksw_used,
+ swtot.ksw_total - swtot.ksw_used,
+ (swtot.ksw_used * 100.0) / swtot.ksw_total);
+ }
+}
+
+static void
+swapmode_kvm(void)
+{
+ struct kvm_swap kswap[16];
+ int i, n;
+
+ n = kvm_getswapinfo(kd, kswap, sizeof kswap / sizeof kswap[0],
+ SWIF_DEV_PREFIX);
+
+ print_swap_header();
+ for (i = 0; i < n; ++i)
+ print_swap(&kswap[i]);
+ print_swap_total();
+}
+
+static void
+swapmode_sysctl(void)
+{
+ struct kvm_swap ksw;
+ struct xswdev xsw;
+ size_t mibsize, size;
+ int mib[16], n;
+
+ print_swap_header();
+ mibsize = sizeof mib / sizeof mib[0];
+ if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
+ err(1, "sysctlnametomib()");
+ for (n = 0; ; ++n) {
+ mib[mibsize] = n;
+ size = sizeof xsw;
+ if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
+ break;
+ if (xsw.xsw_version != XSWDEV_VERSION)
+ errx(1, "xswdev version mismatch");
+ if (xsw.xsw_dev == NODEV)
+ snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
+ "<NFSfile>");
+ else
+ snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
+ "/dev/%s", devname(xsw.xsw_dev, S_IFCHR));
+ ksw.ksw_used = xsw.xsw_used;
+ ksw.ksw_total = xsw.xsw_nblks;
+ ksw.ksw_flags = xsw.xsw_flags;
+ print_swap(&ksw);
+ }
+ if (errno != ENOENT)
+ err(1, "sysctl()");
+ print_swap_total();
+}
+
+static void
+swapmode(void)
+{
+ if (kd != NULL)
+ swapmode_kvm();
+ else
+ swapmode_sysctl();
+}
OpenPOWER on IntegriCloud