aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/systat
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2004-10-16 08:43:07 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2004-10-16 08:43:07 +0000
commit5c5cd6c8e7b9cc9c39e56d04459ff9f4b2408bc1 (patch)
tree27f32fc9bf3cb037289399e845a7c48aada4daa9 /usr.bin/systat
parente06b1220a2565309de654c909ca0c876cab9f0bc (diff)
parent9f37b70b3f9b9fadaa66885f9c9fb7f1e8b637e3 (diff)
Notes
Diffstat (limited to 'usr.bin/systat')
-rw-r--r--usr.bin/systat/Makefile13
-rw-r--r--usr.bin/systat/cmds.c200
-rw-r--r--usr.bin/systat/cmdtab.c87
-rw-r--r--usr.bin/systat/convtbl.c98
-rw-r--r--usr.bin/systat/convtbl.h132
-rw-r--r--usr.bin/systat/devs.c325
-rw-r--r--usr.bin/systat/devs.h30
-rw-r--r--usr.bin/systat/extern.h174
-rw-r--r--usr.bin/systat/fetch.c149
-rw-r--r--usr.bin/systat/icmp.c285
-rw-r--r--usr.bin/systat/icmp6.c283
-rw-r--r--usr.bin/systat/ifcmds.c96
-rw-r--r--usr.bin/systat/ifstat.c412
-rw-r--r--usr.bin/systat/iostat.c411
-rw-r--r--usr.bin/systat/ip.c345
-rw-r--r--usr.bin/systat/ip6.c303
-rw-r--r--usr.bin/systat/keyboard.c123
-rw-r--r--usr.bin/systat/main.c298
-rw-r--r--usr.bin/systat/mbufs.c200
-rw-r--r--usr.bin/systat/mode.c99
-rw-r--r--usr.bin/systat/mode.h44
-rw-r--r--usr.bin/systat/netcmds.c323
-rw-r--r--usr.bin/systat/netstat.c586
-rw-r--r--usr.bin/systat/pigs.c247
-rw-r--r--usr.bin/systat/swap.c198
-rw-r--r--usr.bin/systat/systat.1624
-rw-r--r--usr.bin/systat/systat.h69
-rw-r--r--usr.bin/systat/tcp.c329
-rw-r--r--usr.bin/systat/vmstat.c877
29 files changed, 7360 insertions, 0 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
new file mode 100644
index 000000000000..3cd09f4b50a4
--- /dev/null
+++ b/usr.bin/systat/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= systat
+SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \
+ mbufs.c netcmds.c netstat.c pigs.c swap.c icmp.c icmp6.c \
+ mode.c ip.c ip6.c tcp.c \
+ vmstat.c convtbl.c ifcmds.c ifstat.c
+CFLAGS+=-DINET6
+DPADD= ${LIBCURSES} ${LIBM} ${LIBDEVSTAT} ${LIBKVM}
+LDADD= -lcurses -lm -ldevstat -lkvm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/systat/cmds.c b/usr.bin/systat/cmds.c
new file mode 100644
index 000000000000..b15286b580c5
--- /dev/null
+++ b/usr.bin/systat/cmds.c
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/29/95";
+#endif
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "systat.h"
+#include "extern.h"
+
+void
+command(cmd)
+ const char *cmd;
+{
+ struct cmdtab *p;
+ char *cp, *tmpstr, *tmpstr1;
+ int interval, omask;
+
+ tmpstr = tmpstr1 = strdup(cmd);
+ omask = sigblock(sigmask(SIGALRM));
+ for (cp = tmpstr1; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (*tmpstr1 == '\0')
+ return;
+ for (; *cp && isspace(*cp); cp++)
+ ;
+ if (strcmp(tmpstr1, "quit") == 0 || strcmp(tmpstr1, "q") == 0)
+ die(0);
+ if (strcmp(tmpstr1, "load") == 0) {
+ load();
+ goto done;
+ }
+ if (strcmp(tmpstr1, "stop") == 0) {
+ alarm(0);
+ mvaddstr(CMDLINE, 0, "Refresh disabled.");
+ clrtoeol();
+ goto done;
+ }
+ if (strcmp(tmpstr1, "help") == 0) {
+ int _col, _len;
+
+ move(CMDLINE, _col = 0);
+ for (p = cmdtab; p->c_name; p++) {
+ _len = strlen(p->c_name);
+ if (_col + _len > COLS)
+ break;
+ addstr(p->c_name); _col += _len;
+ if (_col + 1 < COLS)
+ addch(' ');
+ }
+ clrtoeol();
+ goto done;
+ }
+ interval = atoi(tmpstr1);
+ if (interval <= 0 &&
+ (strcmp(tmpstr1, "start") == 0 || strcmp(tmpstr1, "interval") == 0)) {
+ interval = *cp ? atoi(cp) : naptime;
+ if (interval <= 0) {
+ error("%d: bad interval.", interval);
+ goto done;
+ }
+ }
+ if (interval > 0) {
+ alarm(0);
+ naptime = interval;
+ display(0);
+ status();
+ goto done;
+ }
+ p = lookup(tmpstr1);
+ if (p == (struct cmdtab *)-1) {
+ error("%s: Ambiguous command.", tmpstr1);
+ goto done;
+ }
+ if (p) {
+ if (curcmd == p)
+ goto done;
+ alarm(0);
+ (*curcmd->c_close)(wnd);
+ curcmd->c_flags &= ~CF_INIT;
+ wnd = (*p->c_open)();
+ if (wnd == 0) {
+ error("Couldn't open new display");
+ wnd = (*curcmd->c_open)();
+ if (wnd == 0) {
+ error("Couldn't change back to previous cmd");
+ exit(1);
+ }
+ p = curcmd;
+ }
+ if ((p->c_flags & CF_INIT) == 0) {
+ if ((*p->c_init)())
+ p->c_flags |= CF_INIT;
+ else
+ goto done;
+ }
+ curcmd = p;
+ labels();
+ display(0);
+ status();
+ goto done;
+ }
+ if (curcmd->c_cmd == 0 || !(*curcmd->c_cmd)(tmpstr1, cp))
+ error("%s: Unknown command.", tmpstr1);
+done:
+ sigsetmask(omask);
+ free(tmpstr);
+}
+
+struct cmdtab *
+lookup(name)
+ const char *name;
+{
+ const char *p, *q;
+ struct cmdtab *ct, *found;
+ int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = (struct cmdtab *) 0;
+ for (ct = cmdtab; (p = ct->c_name); ct++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return (ct);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = ct;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return ((struct cmdtab *)-1);
+ return (found);
+}
+
+void
+status()
+{
+
+ error("Showing %s, refresh every %d seconds.",
+ curcmd->c_name, naptime);
+}
+
+int
+prefix(s1, s2)
+ const char *s1, *s2;
+{
+
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ return (1);
+ s1++, s2++;
+ }
+ return (*s1 == '\0');
+}
diff --git a/usr.bin/systat/cmdtab.c b/usr.bin/systat/cmdtab.c
new file mode 100644
index 000000000000..6b4f77ee7cf1
--- /dev/null
+++ b/usr.bin/systat/cmdtab.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+struct cmdtab cmdtab[] = {
+ { "pigs", showpigs, fetchpigs, labelpigs,
+ initpigs, openpigs, closepigs, 0,
+ 0, CF_LOADAV },
+ { "swap", showswap, fetchswap, labelswap,
+ initswap, openswap, closeswap, 0,
+ 0, CF_LOADAV },
+ { "mbufs", showmbufs, fetchmbufs, labelmbufs,
+ initmbufs, openmbufs, closembufs, 0,
+ 0, CF_LOADAV },
+ { "iostat", showiostat, fetchiostat, labeliostat,
+ initiostat, openiostat, closeiostat, cmdiostat,
+ 0, CF_LOADAV },
+ { "vmstat", showkre, fetchkre, labelkre,
+ initkre, openkre, closekre, cmdkre,
+ 0, 0 },
+ { "netstat", shownetstat, fetchnetstat, labelnetstat,
+ initnetstat, opennetstat, closenetstat, cmdnetstat,
+ 0, CF_LOADAV },
+ { "icmp", showicmp, fetchicmp, labelicmp,
+ initicmp, openicmp, closeicmp, cmdmode,
+ reseticmp, CF_LOADAV },
+ { "ip", showip, fetchip, labelip,
+ initip, openip, closeip, cmdmode,
+ resetip, CF_LOADAV },
+#ifdef INET6
+ { "icmp6", showicmp6, fetchicmp6, labelicmp6,
+ initicmp6, openicmp6, closeicmp6, cmdmode,
+ reseticmp6, CF_LOADAV },
+ { "ip6", showip6, fetchip6, labelip6,
+ initip6, openip6, closeip6, cmdmode,
+ resetip6, CF_LOADAV },
+#endif
+ { "tcp", showtcp, fetchtcp, labeltcp,
+ inittcp, opentcp, closetcp, cmdmode,
+ resettcp, 0 },
+ { "ifstat", showifstat, fetchifstat, labelifstat,
+ initifstat, openifstat, closeifstat, cmdifstat,
+ 0, CF_LOADAV },
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0 }
+};
+struct cmdtab *curcmd = &cmdtab[0];
diff --git a/usr.bin/systat/convtbl.c b/usr.bin/systat/convtbl.c
new file mode 100644
index 000000000000..56436132fbe4
--- /dev/null
+++ b/usr.bin/systat/convtbl.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 <unistd.h>
+#include "convtbl.h"
+
+struct convtbl convtbl[] = {
+ /* mul, scale, str */
+ { BYTE, BYTES, "bytes" }, /* SC_BYTE (0) */
+ { BYTE, KILO, "KB" }, /* SC_KILOBYTE (1) */
+ { BYTE, MEGA, "MB" }, /* SC_MEGABYTE (2) */
+ { BYTE, GIGA, "GB" }, /* SC_GIGABYTE (3) */
+
+ { BIT, BITS, "b" }, /* SC_BITS (4) */
+ { BIT, KILO, "Kb" }, /* SC_KILOBITS (5) */
+ { BIT, MEGA, "Mb" }, /* SC_MEGABITS (6) */
+ { BIT, GIGA, "Gb" }, /* SC_GIGABITS (7) */
+
+ { 0, 0, "" } /* SC_AUTO (8) */
+
+};
+
+
+static __inline
+struct convtbl *
+get_tbl_ptr(const u_long size, const u_int scale)
+{
+ struct convtbl *tbl_ptr = NULL;
+ u_long tmp = 0;
+ u_int idx = scale;
+
+ /* If our index is out of range, default to auto-scaling. */
+ if (idx > SC_AUTO)
+ idx = SC_AUTO;
+
+ if (idx == SC_AUTO)
+ /*
+ * Simple but elegant algorithm. Count how many times
+ * we can shift our size value right by a factor of ten,
+ * incrementing an index each time. We then use the
+ * index as the array index into the conversion table.
+ */
+ for (tmp = size, idx = SC_KILOBYTE;
+ tmp >= MEGA && idx <= SC_GIGABYTE;
+ tmp >>= 10, idx++);
+
+ tbl_ptr = &convtbl[idx];
+ return tbl_ptr;
+}
+
+double
+convert(const u_long size, const u_int scale)
+{
+ struct convtbl *tp = NULL;
+
+ tp = get_tbl_ptr(size, scale);
+
+ return ((double)size * tp->mul / tp->scale);
+
+}
+
+const char *
+get_string(const u_long size, const u_int scale)
+{
+ struct convtbl *tp = NULL;
+
+ tp = get_tbl_ptr(size, scale);
+
+ return tp->str;
+}
diff --git a/usr.bin/systat/convtbl.h b/usr.bin/systat/convtbl.h
new file mode 100644
index 000000000000..8d5ffeeef260
--- /dev/null
+++ b/usr.bin/systat/convtbl.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 _CONVTBL_H_
+#define _CONVTBL_H_
+
+#include <sys/types.h>
+
+#define BITS (1)
+#define BYTES (1)
+#define KILO (1024)
+#define MEGA (KILO * 1024)
+#define GIGA (MEGA * 1024)
+
+#define SC_BYTE (0)
+#define SC_KILOBYTE (1)
+#define SC_MEGABYTE (2)
+#define SC_GIGABYTE (3)
+#define SC_BIT (4)
+#define SC_KILOBIT (5)
+#define SC_MEGABIT (6)
+#define SC_GIGABIT (7)
+#define SC_AUTO (8)
+
+#define BIT (8)
+#define BYTE (1)
+
+struct convtbl {
+ u_int mul;
+ u_int scale;
+ const char *str;
+};
+
+extern struct convtbl convtbl[];
+
+extern double convert(const u_long, const u_int);
+extern const char *get_string(const u_long, const u_int);
+
+#endif /* ! _CONVTBL_H_ */
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifndef _CONVTBL_H_
+#define _CONVTBL_H_
+
+#include <sys/types.h>
+
+#define BITS (1)
+#define BYTES (1)
+#define KILO (1024)
+#define MEGA (KILO * 1024)
+#define GIGA (MEGA * 1024)
+
+#define SC_BYTE (0)
+#define SC_KILOBYTE (1)
+#define SC_MEGABYTE (2)
+#define SC_GIGABYTE (3)
+#define SC_BIT (4)
+#define SC_KILOBIT (5)
+#define SC_MEGABIT (6)
+#define SC_GIGABIT (7)
+#define SC_AUTO (8)
+
+#define BIT (8)
+#define BYTE (1)
+
+struct convtbl {
+ u_int mul;
+ u_int scale;
+ char *str;
+};
+
+extern struct convtbl convtbl[];
+
+extern double convert(const u_long, const u_int);
+extern char *get_string(const u_long, const u_int);
+
+#endif /* ! _CONVTBL_H_ */
diff --git a/usr.bin/systat/devs.c b/usr.bin/systat/devs.c
new file mode 100644
index 000000000000..d37cf2d5ad98
--- /dev/null
+++ b/usr.bin/systat/devs.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1998 Kenneth D. Merry.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/devicestat.h>
+#include <sys/resource.h>
+
+#include <ctype.h>
+#include <devstat.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "devs.h"
+
+typedef enum {
+ DS_MATCHTYPE_NONE,
+ DS_MATCHTYPE_SPEC,
+ DS_MATCHTYPE_PATTERN
+} last_match_type;
+
+last_match_type last_type;
+struct device_selection *dev_select;
+long generation;
+int num_devices, num_selected;
+int num_selections;
+long select_generation;
+struct devstat_match *matches = NULL;
+int num_matches = 0;
+char **specified_devices;
+int num_devices_specified = 0;
+
+static int dsmatchselect(const char *args, devstat_select_mode select_mode,
+ int maxshowdevs, struct statinfo *s1);
+static int dsselect(const char *args, devstat_select_mode select_mode,
+ int maxshowdevs, struct statinfo *s1);
+
+int
+dsinit(int maxshowdevs, struct statinfo *s1, struct statinfo *s2 __unused,
+ struct statinfo *s3 __unused)
+{
+
+ /*
+ * Make sure that the userland devstat version matches the kernel
+ * devstat version. If not, exit and print a message informing
+ * the user of his mistake.
+ */
+ if (devstat_checkversion(NULL) < 0)
+ errx(1, "%s", devstat_errbuf);
+
+ generation = 0;
+ num_devices = 0;
+ num_selected = 0;
+ num_selections = 0;
+ select_generation = 0;
+ last_type = DS_MATCHTYPE_NONE;
+
+ if (devstat_getdevs(NULL, s1) == -1)
+ errx(1, "%s", devstat_errbuf);
+
+ num_devices = s1->dinfo->numdevs;
+ generation = s1->dinfo->generation;
+
+ dev_select = NULL;
+
+ /*
+ * At this point, selectdevs will almost surely indicate that the
+ * device list has changed, so we don't look for return values of 0
+ * or 1. If we get back -1, though, there is an error.
+ */
+ if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
+ &select_generation, generation, s1->dinfo->devices, num_devices,
+ NULL, 0, NULL, 0, DS_SELECT_ADD, maxshowdevs, 0) == -1)
+ errx(1, "%d %s", __LINE__, devstat_errbuf);
+
+ return(1);
+}
+
+int
+dscmd(const char *cmd, const char *args, int maxshowdevs, struct statinfo *s1)
+{
+ int retval;
+
+ if (prefix(cmd, "display") || prefix(cmd, "add"))
+ return(dsselect(args, DS_SELECT_ADDONLY, maxshowdevs, s1));
+ if (prefix(cmd, "ignore") || prefix(cmd, "delete"))
+ return(dsselect(args, DS_SELECT_REMOVE, maxshowdevs, s1));
+ if (prefix(cmd, "show") || prefix(cmd, "only"))
+ return(dsselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
+ if (prefix(cmd, "type") || prefix(cmd, "match"))
+ return(dsmatchselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
+ if (prefix(cmd, "refresh")) {
+ retval = devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections, &select_generation, generation,
+ s1->dinfo->devices, num_devices,
+ (last_type ==DS_MATCHTYPE_PATTERN) ? matches : NULL,
+ (last_type ==DS_MATCHTYPE_PATTERN) ? num_matches : 0,
+ (last_type == DS_MATCHTYPE_SPEC) ?specified_devices : NULL,
+ (last_type == DS_MATCHTYPE_SPEC) ?num_devices_specified : 0,
+ (last_type == DS_MATCHTYPE_NONE) ? DS_SELECT_ADD :
+ DS_SELECT_ADDONLY, maxshowdevs, 0);
+ if (retval == -1) {
+ warnx("%s", devstat_errbuf);
+ return(0);
+ } else if (retval == 1)
+ return(2);
+ }
+ if (prefix(cmd, "drives")) {
+ register int i;
+ move(CMDLINE, 0);
+ clrtoeol();
+ for (i = 0; i < num_devices; i++) {
+ printw("%s%d ", s1->dinfo->devices[i].device_name,
+ s1->dinfo->devices[i].unit_number);
+ }
+ return(1);
+ }
+ return(0);
+}
+
+static int
+dsmatchselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
+ struct statinfo *s1)
+{
+ char **tempstr, *tmpstr, *tmpstr1;
+ char *tstr[100];
+ int num_args = 0;
+ int i;
+ int retval = 0;
+
+ /*
+ * Break the (pipe delimited) input string out into separate
+ * strings.
+ */
+ tmpstr = tmpstr1 = strdup(args);
+ for (tempstr = tstr, num_args = 0;
+ (*tempstr = strsep(&tmpstr1, "|")) != NULL && (num_args < 100);
+ num_args++)
+ if (**tempstr != '\0')
+ if (++tempstr >= &tstr[100])
+ break;
+ free(tmpstr);
+
+ if (num_args > 99) {
+ warnx("dsmatchselect: too many match arguments");
+ return(0);
+ }
+
+ /*
+ * If we've gone through the matching code before, clean out
+ * previously used memory.
+ */
+ if (num_matches > 0) {
+ free(matches);
+ matches = NULL;
+ num_matches = 0;
+ }
+
+ for (i = 0; i < num_args; i++) {
+ if (devstat_buildmatch(tstr[i], &matches, &num_matches) != 0) {
+ warnx("%s", devstat_errbuf);
+ return(0);
+ }
+ }
+ if (num_args > 0) {
+
+ last_type = DS_MATCHTYPE_PATTERN;
+
+ retval = devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections, &select_generation, generation,
+ s1->dinfo->devices, num_devices, matches, num_matches,
+ NULL, 0, select_mode, maxshowdevs, 0);
+ if (retval == -1)
+ err(1, "device selection error");
+ else if (retval == 1)
+ return(2);
+ }
+ return(1);
+}
+
+static int
+dsselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
+ struct statinfo *s1)
+{
+ char *cp, *tmpstr, *tmpstr1, *buffer;
+ int i;
+ int retval = 0;
+
+ /*
+ * If we've gone through this code before, free previously
+ * allocated resources.
+ */
+ if (num_devices_specified > 0) {
+ for (i = 0; i < num_devices_specified; i++)
+ free(specified_devices[i]);
+ free(specified_devices);
+ specified_devices = NULL;
+ num_devices_specified = 0;
+ }
+
+ /* do an initial malloc */
+ specified_devices = (char **)malloc(sizeof(char *));
+
+ tmpstr = tmpstr1 = strdup(args);
+ cp = index(tmpstr1, '\n');
+ if (cp)
+ *cp = '\0';
+ for (;;) {
+ for (cp = tmpstr1; *cp && isspace(*cp); cp++)
+ ;
+ tmpstr1 = cp;
+ for (; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (cp - args == 0)
+ break;
+ for (i = 0; i < num_devices; i++) {
+ asprintf(&buffer, "%s%d", dev_select[i].device_name,
+ dev_select[i].unit_number);
+ if (strcmp(buffer, tmpstr1) == 0) {
+
+ num_devices_specified++;
+
+ specified_devices =(char **)realloc(
+ specified_devices,
+ sizeof(char *) *
+ num_devices_specified);
+ specified_devices[num_devices_specified -1]=
+ strdup(tmpstr1);
+ free(buffer);
+
+ break;
+ }
+ else
+ free(buffer);
+ }
+ if (i >= num_devices)
+ error("%s: unknown drive", args);
+ args = cp;
+ }
+ free(tmpstr);
+
+ if (num_devices_specified > 0) {
+ last_type = DS_MATCHTYPE_SPEC;
+
+ retval = devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections, &select_generation, generation,
+ s1->dinfo->devices, num_devices, NULL, 0,
+ specified_devices, num_devices_specified,
+ select_mode, maxshowdevs, 0);
+ if (retval == -1)
+ err(1, "%s", devstat_errbuf);
+ else if (retval == 1)
+ return(2);
+ }
+ return(1);
+}
diff --git a/usr.bin/systat/devs.h b/usr.bin/systat/devs.h
new file mode 100644
index 000000000000..921700846b23
--- /dev/null
+++ b/usr.bin/systat/devs.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 1998 David E. O'Brien
+ * 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$
+ */
+
+int dsinit(int, struct statinfo *, struct statinfo *, struct statinfo *);
+int dscmd(const char *, const char *, int, struct statinfo *);
diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h
new file mode 100644
index 000000000000..84af89ca55f0
--- /dev/null
+++ b/usr.bin/systat/extern.h
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <fcntl.h>
+#include <kvm.h>
+
+extern struct cmdtab *curcmd;
+extern struct cmdtab cmdtab[];
+extern struct text *xtext;
+extern WINDOW *wnd;
+extern char **dr_name;
+extern char c, *namp, hostname[];
+extern double avenrun[3];
+extern float *dk_mspw;
+extern kvm_t *kd;
+extern long ntext, textp;
+extern int *dk_select;
+extern int CMDLINE;
+extern int dk_ndrive;
+extern int hz, stathz;
+extern double hertz; /* sampling frequency for cp_time and dk_time */
+extern int naptime, col;
+extern int nhosts;
+extern int nports;
+extern int protos;
+extern int verbose;
+
+struct inpcb;
+
+extern struct device_selection *dev_select;
+extern long generation;
+extern int num_devices;
+extern int num_selected;
+extern int num_selections;
+extern long select_generation;
+
+extern struct nlist namelist[];
+
+int checkhost(struct inpcb *);
+int checkport(struct inpcb *);
+void closeicmp(WINDOW *);
+void closeicmp6(WINDOW *);
+void closeifstat(WINDOW *);
+void closeiostat(WINDOW *);
+void closeip(WINDOW *);
+void closeip6(WINDOW *);
+void closekre(WINDOW *);
+void closembufs(WINDOW *);
+void closenetstat(WINDOW *);
+void closepigs(WINDOW *);
+void closeswap(WINDOW *);
+void closetcp(WINDOW *);
+int cmdifstat(const char *, const char *);
+int cmdiostat(const char *, const char *);
+int cmdkre(const char *, const char *);
+int cmdnetstat(const char *, const char *);
+struct cmdtab *lookup(const char *);
+void command(const char *);
+void die(int);
+void display(int);
+int dkinit(void);
+int dkcmd(char *, char *);
+void error(const char *fmt, ...) __printflike(1, 2);
+void fetchicmp(void);
+void fetchicmp6(void);
+void fetchifstat(void);
+void fetchip(void);
+void fetchip6(void);
+void fetchiostat(void);
+void fetchkre(void);
+void fetchmbufs(void);
+void fetchnetstat(void);
+void fetchpigs(void);
+void fetchswap(void);
+void fetchtcp(void);
+void getsysctl(const char *, void *, size_t);
+int ifcmd(const char *cmd, const char *args);
+int initicmp(void);
+int initicmp6(void);
+int initifstat(void);
+int initip(void);
+int initip6(void);
+int initiostat(void);
+int initkre(void);
+int initmbufs(void);
+int initnetstat(void);
+int initpigs(void);
+int initswap(void);
+int inittcp(void);
+int keyboard(void);
+int kvm_ckread(void *, void *, int);
+void labelicmp(void);
+void labelicmp6(void);
+void labelifstat(void);
+void labelip(void);
+void labelip6(void);
+void labeliostat(void);
+void labelkre(void);
+void labelmbufs(void);
+void labelnetstat(void);
+void labelpigs(void);
+void labels(void);
+void labelswap(void);
+void labeltcp(void);
+void load(void);
+int netcmd(const char *, const char *);
+void nlisterr(struct nlist []);
+WINDOW *openicmp(void);
+WINDOW *openicmp6(void);
+WINDOW *openifstat(void);
+WINDOW *openip(void);
+WINDOW *openip6(void);
+WINDOW *openiostat(void);
+WINDOW *openkre(void);
+WINDOW *openmbufs(void);
+WINDOW *opennetstat(void);
+WINDOW *openpigs(void);
+WINDOW *openswap(void);
+WINDOW *opentcp(void);
+int prefix(const char *, const char *);
+void reseticmp(void);
+void reseticmp6(void);
+void resetip(void);
+void resetip6(void);
+void resettcp(void);
+void showicmp(void);
+void showicmp6(void);
+void showifstat(void);
+void showip(void);
+void showip6(void);
+void showiostat(void);
+void showkre(void);
+void showmbufs(void);
+void shownetstat(void);
+void showpigs(void);
+void showswap(void);
+void showtcp(void);
+void status(void);
+void suspend(int);
+char *sysctl_dynread(const char *, size_t *);
diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c
new file mode 100644
index 000000000000..1a22bbeb171f
--- /dev/null
+++ b/usr.bin/systat/fetch.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)fetch.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+
+int
+kvm_ckread(a, b, l)
+ void *a, *b;
+ int l;
+{
+ if (kvm_read(kd, (u_long)a, b, l) != l) {
+ if (verbose)
+ error("error reading kmem at %p", a);
+ return (0);
+ }
+ else
+ return (1);
+}
+
+void getsysctl(name, ptr, len)
+ const char *name;
+ void *ptr;
+ size_t len;
+{
+ size_t nlen = len;
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) != 0) {
+ error("sysctl(%s...) failed: %s", name,
+ strerror(errno));
+ }
+ if (nlen != len) {
+ error("sysctl(%s...) expected %lu, got %lu", name,
+ (unsigned long)len, (unsigned long)nlen);
+ }
+}
+
+/*
+ * Read sysctl data with variable size. Try some times (with increasing
+ * buffers), fail if still too small.
+ * This is needed sysctls with possibly raplidly increasing data sizes,
+ * but imposes little overhead in the case of constant sizes.
+ * Returns NULL on error, or a pointer to freshly malloc()'ed memory that holds
+ * the requested data.
+ * If szp is not NULL, the size of the returned data will be written into *szp.
+ */
+
+/* Some defines: Number of tries. */
+#define SD_NTRIES 10
+/* Percent of over-allocation (initial) */
+#define SD_MARGIN 10
+/*
+ * Factor for over-allocation in percent (the margin is increased by this on
+ * any failed try).
+ */
+#define SD_FACTOR 50
+/* Maximum supported MIB depth */
+#define SD_MAXMIB 16
+
+char *
+sysctl_dynread(n, szp)
+ const char *n;
+ size_t *szp;
+{
+ char *rv = NULL;
+ int mib[SD_MAXMIB];
+ size_t mibsz = SD_MAXMIB;
+ size_t mrg = SD_MARGIN;
+ size_t sz;
+ int i;
+
+ /* cache the MIB */
+ if (sysctlnametomib(n, mib, &mibsz) == -1) {
+ if (errno == ENOMEM) {
+ error("XXX: SD_MAXMIB too small, please bump!");
+ }
+ return NULL;
+ }
+ for (i = 0; i < SD_NTRIES; i++) {
+ /* get needed buffer size */
+ if (sysctl(mib, mibsz, NULL, &sz, NULL, 0) == -1)
+ break;
+ sz += sz * mrg / 100;
+ if ((rv = (char *)malloc(sz)) == NULL) {
+ error("Out of memory!");
+ return NULL;
+ }
+ if (sysctl(mib, mibsz, rv, &sz, NULL, 0) == -1) {
+ free(rv);
+ rv = NULL;
+ if (errno == ENOMEM) {
+ mrg += mrg * SD_FACTOR / 100;
+ } else
+ break;
+ } else {
+ /* success */
+ if (szp != NULL)
+ *szp = sz;
+ break;
+ }
+ }
+
+ return rv;
+}
diff --git a/usr.bin/systat/icmp.c b/usr.bin/systat/icmp.c
new file mode 100644
index 000000000000..487a3ba40f7d
--- /dev/null
+++ b/usr.bin/systat/icmp.c
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* From:
+ "Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp"
+*/
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+static struct icmpstat icmpstat, initstat, oldstat;
+
+/*-
+--0 1 2 3 4 5 6 7
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+01 ICMP Input ICMP Output
+02999999999 total messages 999999999 total messages
+03999999999 with bad code 999999999 errors generated
+04999999999 with bad length 999999999 suppressed - original too short
+05999999999 with bad checksum 999999999 suppressed - original was ICMP
+06999999999 with insufficient data 999999999 responses sent
+07 999999999 suppressed - multicast echo
+08 999999999 suppressed - multicast tstamp
+09
+10 Input Histogram Output Histogram
+11999999999 echo response 999999999 echo response
+12999999999 echo request 999999999 echo request
+13999999999 destination unreachable 999999999 destination unreachable
+14999999999 redirect 999999999 redirect
+15999999999 time-to-live exceeded 999999999 time-to-line exceeded
+16999999999 parameter problem 999999999 parameter problem
+17999999999 router advertisement 999999999 router solicitation
+18
+19
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+--0 1 2 3 4 5 6 7
+*/
+
+WINDOW *
+openicmp(void)
+{
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+void
+closeicmp(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+labelicmp(void)
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+#define L(row, str) mvwprintw(wnd, row, 10, str)
+#define R(row, str) mvwprintw(wnd, row, 45, str);
+ L(1, "ICMP Input"); R(1, "ICMP Output");
+ L(2, "total messages"); R(2, "total messages");
+ L(3, "with bad code"); R(3, "errors generated");
+ L(4, "with bad length"); R(4, "suppressed - original too short");
+ L(5, "with bad checksum"); R(5, "suppressed - original was ICMP");
+ L(6, "with insufficient data"); R(6, "responses sent");
+ ; R(7, "suppressed - multicast echo");
+ ; R(8, "suppressed - multicast tstamp");
+ L(10, "Input Histogram"); R(10, "Output Histogram");
+#define B(row, str) L(row, str); R(row, str)
+ B(11, "echo response");
+ B(12, "echo request");
+ B(13, "destination unreachable");
+ B(14, "redirect");
+ B(15, "time-to-live exceeded");
+ B(16, "parameter problem");
+ L(17, "router advertisement"); R(17, "router solicitation");
+#undef L
+#undef R
+#undef B
+}
+
+static void
+domode(struct icmpstat *ret)
+{
+ const struct icmpstat *sub;
+ int i, divisor = 1;
+
+ switch(currentmode) {
+ case display_RATE:
+ sub = &oldstat;
+ divisor = naptime;
+ break;
+ case display_DELTA:
+ sub = &oldstat;
+ break;
+ case display_SINCE:
+ sub = &initstat;
+ break;
+ default:
+ *ret = icmpstat;
+ return;
+ }
+#define DO(stat) ret->stat = (icmpstat.stat - sub->stat) / divisor
+ DO(icps_error);
+ DO(icps_oldshort);
+ DO(icps_oldicmp);
+ for (i = 0; i <= ICMP_MAXTYPE; i++) {
+ DO(icps_outhist[i]);
+ }
+ DO(icps_badcode);
+ DO(icps_tooshort);
+ DO(icps_checksum);
+ DO(icps_badlen);
+ DO(icps_reflect);
+ for (i = 0; i <= ICMP_MAXTYPE; i++) {
+ DO(icps_inhist[i]);
+ }
+ DO(icps_bmcastecho);
+ DO(icps_bmcasttstamp);
+#undef DO
+}
+
+void
+showicmp(void)
+{
+ struct icmpstat stats;
+ u_long totalin, totalout;
+ int i;
+
+ memset(&stats, 0, sizeof stats);
+ domode(&stats);
+ for (i = totalin = totalout = 0; i <= ICMP_MAXTYPE; i++) {
+ totalin += stats.icps_inhist[i];
+ totalout += stats.icps_outhist[i];
+ }
+ totalin += stats.icps_badcode + stats.icps_badlen +
+ stats.icps_checksum + stats.icps_tooshort;
+ mvwprintw(wnd, 2, 0, "%9lu", totalin);
+ mvwprintw(wnd, 2, 35, "%9lu", totalout);
+
+#define DO(stat, row, col) \
+ mvwprintw(wnd, row, col, "%9lu", stats.stat)
+
+ DO(icps_badcode, 3, 0);
+ DO(icps_badlen, 4, 0);
+ DO(icps_checksum, 5, 0);
+ DO(icps_tooshort, 6, 0);
+ DO(icps_error, 3, 35);
+ DO(icps_oldshort, 4, 35);
+ DO(icps_oldicmp, 5, 35);
+ DO(icps_reflect, 6, 35);
+ DO(icps_bmcastecho, 7, 35);
+ DO(icps_bmcasttstamp, 8, 35);
+#define DO2(type, row) DO(icps_inhist[type], row, 0); DO(icps_outhist[type], \
+ row, 35)
+ DO2(ICMP_ECHOREPLY, 11);
+ DO2(ICMP_ECHO, 12);
+ DO2(ICMP_UNREACH, 13);
+ DO2(ICMP_REDIRECT, 14);
+ DO2(ICMP_TIMXCEED, 15);
+ DO2(ICMP_PARAMPROB, 16);
+ DO(icps_inhist[ICMP_ROUTERADVERT], 17, 0);
+ DO(icps_outhist[ICMP_ROUTERSOLICIT], 17, 35);
+#undef DO
+#undef DO2
+}
+
+int
+initicmp(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_ICMP;
+ name[3] = ICMPCTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting icmpstat size failed");
+ return 0;
+ }
+ if (len > sizeof icmpstat) {
+ error("icmpstat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting icmpstat size failed");
+ return 0;
+ }
+ oldstat = initstat;
+ return 1;
+}
+
+void
+reseticmp(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_ICMP;
+ name[3] = ICMPCTL_STATS;
+
+ len = sizeof initstat;
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting icmpstat size failed");
+ }
+ oldstat = initstat;
+}
+
+void
+fetchicmp(void)
+{
+ int name[4];
+ size_t len;
+
+ oldstat = icmpstat;
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_ICMP;
+ name[3] = ICMPCTL_STATS;
+ len = sizeof icmpstat;
+
+ if (sysctl(name, 4, &icmpstat, &len, 0, 0) < 0)
+ return;
+}
+
diff --git a/usr.bin/systat/icmp6.c b/usr.bin/systat/icmp6.c
new file mode 100644
index 000000000000..c02819ffdd6d
--- /dev/null
+++ b/usr.bin/systat/icmp6.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* From:
+ "Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp"
+*/
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+static struct icmp6stat icmp6stat, initstat, oldstat;
+
+/*-
+--0 1 2 3 4 5 6 7
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+01 ICMPv6 Input ICMPv6 Output
+02999999999 total messages 999999999 total messages
+03999999999 with bad code 999999999 errors generated
+04999999999 with bad length 999999999 suppressed - original too short
+05999999999 with bad checksum 999999999 suppressed - original was ICMP
+06999999999 with insufficient data 999999999 responses sent
+07
+08 Input Histogram Output Histogram
+09999999999 echo response 999999999 echo response
+10999999999 echo request 999999999 echo request
+11999999999 destination unreachable 999999999 destination unreachable
+12999999999 redirect 999999999 redirect
+13999999999 time-to-live exceeded 999999999 time-to-line exceeded
+14999999999 parameter problem 999999999 parameter problem
+15999999999 neighbor solicitation 999999999 neighbor solicitation
+16999999999 neighbor advertisment 999999999 neighbor advertisment
+17999999999 router advertisement 999999999 router solicitation
+18
+19
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+--0 1 2 3 4 5 6 7
+*/
+
+WINDOW *
+openicmp6(void)
+{
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+void
+closeicmp6(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+labelicmp6(void)
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+#define L(row, str) mvwprintw(wnd, row, 10, str)
+#define R(row, str) mvwprintw(wnd, row, 45, str);
+ L(1, "ICMPv6 Input"); R(1, "ICMPv6 Output");
+ L(2, "total messages"); R(2, "total messages");
+ L(3, "with bad code"); R(3, "errors generated");
+ L(4, "with bad length"); R(4, "suppressed - original too short");
+ L(5, "with bad checksum"); R(5, "suppressed - original was ICMP");
+ L(6, "with insufficient data"); R(6, "responses sent");
+
+ L(8, "Input Histogram"); R(8, "Output Histogram");
+#define B(row, str) L(row, str); R(row, str)
+ B(9, "echo response");
+ B(10, "echo request");
+ B(11, "destination unreachable");
+ B(12, "redirect");
+ B(13, "time-to-live exceeded");
+ B(14, "parameter problem");
+ B(15, "neighbor solicitation");
+ B(16, "neighbor advertisment");
+ L(17, "router advertisement"); R(17, "router solicitation");
+#undef L
+#undef R
+#undef B
+}
+
+static void
+domode(struct icmp6stat *ret)
+{
+ const struct icmp6stat *sub;
+ int i, divisor = 1;
+
+ switch(currentmode) {
+ case display_RATE:
+ sub = &oldstat;
+ divisor = naptime;
+ break;
+ case display_DELTA:
+ sub = &oldstat;
+ break;
+ case display_SINCE:
+ sub = &initstat;
+ break;
+ default:
+ *ret = icmp6stat;
+ return;
+ }
+#define DO(stat) ret->stat = (icmp6stat.stat - sub->stat) / divisor
+ DO(icp6s_error);
+ DO(icp6s_tooshort);
+ DO(icp6s_canterror);
+ for (i = 0; i <= ICMP6_MAXTYPE; i++) {
+ DO(icp6s_outhist[i]);
+ }
+ DO(icp6s_badcode);
+ DO(icp6s_tooshort);
+ DO(icp6s_checksum);
+ DO(icp6s_badlen);
+ DO(icp6s_reflect);
+ for (i = 0; i <= ICMP6_MAXTYPE; i++) {
+ DO(icp6s_inhist[i]);
+ }
+#undef DO
+}
+
+void
+showicmp6(void)
+{
+ struct icmp6stat stats;
+ u_long totalin, totalout;
+ int i;
+
+ memset(&stats, 0, sizeof stats);
+ domode(&stats);
+ for (i = totalin = totalout = 0; i <= ICMP6_MAXTYPE; i++) {
+ totalin += stats.icp6s_inhist[i];
+ totalout += stats.icp6s_outhist[i];
+ }
+ totalin += stats.icp6s_badcode + stats.icp6s_badlen +
+ stats.icp6s_checksum + stats.icp6s_tooshort;
+ mvwprintw(wnd, 2, 0, "%9lu", totalin);
+ mvwprintw(wnd, 2, 35, "%9lu", totalout);
+
+#define DO(stat, row, col) \
+ mvwprintw(wnd, row, col, "%9lu", stats.stat)
+
+ DO(icp6s_badcode, 3, 0);
+ DO(icp6s_badlen, 4, 0);
+ DO(icp6s_checksum, 5, 0);
+ DO(icp6s_tooshort, 6, 0);
+ DO(icp6s_error, 3, 35);
+ DO(icp6s_tooshort, 4, 35);
+ DO(icp6s_canterror, 5, 35);
+ DO(icp6s_reflect, 6, 35);
+#define DO2(type, row) DO(icp6s_inhist[type], row, 0); DO(icp6s_outhist[type], \
+ row, 35)
+ DO2(ICMP6_ECHO_REPLY, 9);
+ DO2(ICMP6_ECHO_REQUEST, 10);
+ DO2(ICMP6_DST_UNREACH, 11);
+ DO2(ND_REDIRECT, 12);
+ DO2(ICMP6_TIME_EXCEEDED, 13);
+ DO2(ICMP6_PARAM_PROB, 14);
+ DO2(ND_NEIGHBOR_SOLICIT, 15);
+ DO2(ND_NEIGHBOR_ADVERT, 16);
+ DO(icp6s_inhist[ND_ROUTER_SOLICIT], 17, 0);
+ DO(icp6s_outhist[ND_ROUTER_ADVERT], 17, 35);
+#undef DO
+#undef DO2
+}
+
+int
+initicmp6(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_ICMPV6;
+ name[3] = ICMPV6CTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting icmp6stat size failed");
+ return 0;
+ }
+ if (len > sizeof icmp6stat) {
+ error("icmp6stat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting icmp6stat size failed");
+ return 0;
+ }
+ oldstat = initstat;
+ return 1;
+}
+
+void
+reseticmp6(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_ICMPV6;
+ name[3] = ICMPV6CTL_STATS;
+
+ len = sizeof initstat;
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting icmp6stat size failed");
+ }
+ oldstat = initstat;
+}
+
+void
+fetchicmp6(void)
+{
+ int name[4];
+ size_t len;
+
+ oldstat = icmp6stat;
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_ICMPV6;
+ name[3] = ICMPV6CTL_STATS;
+ len = sizeof icmp6stat;
+
+ if (sysctl(name, 4, &icmp6stat, &len, 0, 0) < 0)
+ return;
+}
+
+#endif
diff --git a/usr.bin/systat/ifcmds.c b/usr.bin/systat/ifcmds.c
new file mode 100644
index 000000000000..68c377e476ad
--- /dev/null
+++ b/usr.bin/systat/ifcmds.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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/time.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h> /* For IFT_ETHER */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <float.h>
+#include <err.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+#include "convtbl.h"
+
+int curscale = SC_AUTO;
+
+static int selectscale(const char *);
+
+int
+ifcmd(const char *cmd, const char *args)
+{
+ if (prefix(cmd, "scale")) {
+ if (*args != '\0' && selectscale(args) != -1)
+ ;
+ else {
+ move(CMDLINE, 0);
+ clrtoeol();
+ addstr("what scale? kbit, kbyte, mbit, mbyte, " \
+ "gbit, gbyte, auto");
+ }
+ }
+ return 1;
+}
+
+static int
+selectscale(const char *args)
+{
+ int retval = 0;
+
+#define streq(a,b) (strcmp(a,b) == 0)
+ if (streq(args, "default") || streq(args, "auto"))
+ curscale = SC_AUTO;
+ else if (streq(args, "kbit"))
+ curscale = SC_KILOBIT;
+ else if (streq(args, "kbyte"))
+ curscale = SC_KILOBYTE;
+ else if (streq(args, "mbit"))
+ curscale = SC_MEGABIT;
+ else if (streq(args, "mbyte"))
+ curscale = SC_MEGABYTE;
+ else if (streq(args, "gbit"))
+ curscale = SC_GIGABIT;
+ else if (streq(args, "gbyte"))
+ curscale = SC_GIGABYTE;
+ else
+ retval = -1;
+
+ return retval;
+}
diff --git a/usr.bin/systat/ifstat.c b/usr.bin/systat/ifstat.c
new file mode 100644
index 000000000000..26c81ce1413a
--- /dev/null
+++ b/usr.bin/systat/ifstat.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 INTIFSTAT_ERRUPTION)
+ * 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/time.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h> /* For IFT_ETHER */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <float.h>
+#include <err.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+#include "convtbl.h"
+
+ /* Column numbers */
+
+#define C1 0 /* 0-19 */
+#define C2 20 /* 20-39 */
+#define C3 40 /* 40-59 */
+#define C4 60 /* 60-80 */
+#define C5 80 /* Used for label positioning. */
+
+static const int col0 = 0;
+static const int col1 = C1;
+static const int col2 = C2;
+static const int col3 = C3;
+static const int col4 = C4;
+static const int col5 = C5;
+
+
+SLIST_HEAD(, if_stat) curlist;
+SLIST_HEAD(, if_stat_disp) displist;
+
+struct if_stat {
+ SLIST_ENTRY(if_stat) link;
+ char if_name[IF_NAMESIZE];
+ struct ifmibdata if_mib;
+ struct timeval tv;
+ struct timeval tv_lastchanged;
+ u_long if_in_curtraffic;
+ u_long if_out_curtraffic;
+ u_long if_in_traffic_peak;
+ u_long if_out_traffic_peak;
+ u_int if_row; /* Index into ifmib sysctl */
+ u_int if_ypos; /* 0 if not being displayed */
+ u_int display;
+};
+
+extern u_int curscale;
+
+static void right_align_string(const struct if_stat *);
+static void getifmibdata(const int, struct ifmibdata *);
+static void sort_interface_list(void);
+static u_int getifnum(void);
+
+#define IFSTAT_ERR(n, s) do { \
+ putchar(' '); \
+ closeifstat(wnd); \
+ err((n), (s)); \
+} while (0)
+
+#define STARTING_ROW (8)
+#define ROW_SPACING (3)
+
+#define TOPLINE 5
+#define TOPLABEL \
+" Interface Traffic Peak Total"
+
+#define CLEAR_LINE(y, x) do { \
+ wmove(wnd, y, x); \
+ wclrtoeol(wnd); \
+} while (0)
+
+#define IN_col2 (ifp->if_in_curtraffic)
+#define OUT_col2 (ifp->if_out_curtraffic)
+#define IN_col3 (ifp->if_in_traffic_peak)
+#define OUT_col3 (ifp->if_out_traffic_peak)
+#define IN_col4 (ifp->if_mib.ifmd_data.ifi_ibytes)
+#define OUT_col4 (ifp->if_mib.ifmd_data.ifi_obytes)
+
+#define EMPTY_COLUMN " "
+#define CLEAR_COLUMN(y, x) mvprintw((y), (x), "%20s", EMPTY_COLUMN);
+
+#define DOPUTRATE(c, r, d) do { \
+ CLEAR_COLUMN(r, c); \
+ mvprintw(r, (c), "%10.3f %s%s ", \
+ convert(d##_##c, curscale), \
+ get_string(d##_##c, curscale), \
+ "/s"); \
+} while (0)
+
+#define DOPUTTOTAL(c, r, d) do { \
+ CLEAR_COLUMN((r), (c)); \
+ mvprintw((r), (c), "%12.3f %s ", \
+ convert(d##_##c, SC_AUTO), \
+ get_string(d##_##c, SC_AUTO)); \
+} while (0)
+
+#define PUTRATE(c, r) do { \
+ DOPUTRATE(c, (r), IN); \
+ DOPUTRATE(c, (r)+1, OUT); \
+} while (0)
+
+#define PUTTOTAL(c, r) do { \
+ DOPUTTOTAL(c, (r), IN); \
+ DOPUTTOTAL(c, (r)+1, OUT); \
+} while (0)
+
+#define PUTNAME(p) do { \
+ mvprintw(p->if_ypos, 0, "%s", p->if_name); \
+ mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in"); \
+ mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out"); \
+} while (0)
+
+
+WINDOW *
+openifstat(void)
+{
+ return (subwin(stdscr, LINES-1-5, 0, 5, 0));
+}
+
+void
+closeifstat(WINDOW *w)
+{
+ struct if_stat *node = NULL;
+
+ while (!SLIST_EMPTY(&curlist)) {
+ node = SLIST_FIRST(&curlist);
+ SLIST_REMOVE_HEAD(&curlist, link);
+ free(node);
+ }
+
+ if (w != NULL) {
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+ }
+
+ return;
+}
+
+
+void
+labelifstat(void)
+{
+
+ wmove(wnd, TOPLINE, 0);
+ wclrtoeol(wnd);
+ mvprintw(TOPLINE, 0, "%s", TOPLABEL);
+
+ return;
+}
+
+void
+showifstat(void)
+{
+ struct if_stat *ifp = NULL;
+ SLIST_FOREACH(ifp, &curlist, link) {
+ if (ifp->display == 0)
+ continue;
+ PUTNAME(ifp);
+ PUTRATE(col2, ifp->if_ypos);
+ PUTRATE(col3, ifp->if_ypos);
+ PUTTOTAL(col4, ifp->if_ypos);
+ }
+
+ return;
+}
+
+int
+initifstat(void)
+{
+ struct if_stat *p = NULL;
+ u_int n = 0, i = 0;
+
+ n = getifnum();
+ if (n <= 0)
+ return -1;
+
+ SLIST_INIT(&curlist);
+
+ for (i = 0; i < n; i++) {
+ p = (struct if_stat *)malloc(sizeof(struct if_stat));
+ if (p == NULL)
+ IFSTAT_ERR(1, "out of memory");
+ memset((void *)p, 0, sizeof(struct if_stat));
+ SLIST_INSERT_HEAD(&curlist, p, link);
+ p->if_row = i+1;
+ getifmibdata(p->if_row, &p->if_mib);
+ right_align_string(p);
+
+ /*
+ * Initially, we only display interfaces that have
+ * received some traffic.
+ */
+ if (p->if_mib.ifmd_data.ifi_ibytes != 0)
+ p->display = 1;
+ }
+
+ sort_interface_list();
+
+ return 1;
+}
+
+void
+fetchifstat(void)
+{
+ struct if_stat *ifp = NULL;
+ struct timeval tv, new_tv, old_tv;
+ double elapsed = 0.0;
+ u_int new_inb, new_outb, old_inb, old_outb = 0;
+ u_int we_need_to_sort_interface_list = 0;
+
+ SLIST_FOREACH(ifp, &curlist, link) {
+ /*
+ * Grab a copy of the old input/output values before we
+ * call getifmibdata().
+ */
+ old_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
+ old_outb = ifp->if_mib.ifmd_data.ifi_obytes;
+ ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange;
+
+ if (gettimeofday(&new_tv, (struct timezone *)0) != 0)
+ IFSTAT_ERR(2, "error getting time of day");
+ (void)getifmibdata(ifp->if_row, &ifp->if_mib);
+
+
+ new_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
+ new_outb = ifp->if_mib.ifmd_data.ifi_obytes;
+
+ /* Display interface if it's received some traffic. */
+ if (new_inb > 0 && old_inb == 0) {
+ ifp->display = 1;
+ we_need_to_sort_interface_list++;
+ }
+
+ /*
+ * The rest is pretty trivial. Calculate the new values
+ * for our current traffic rates, and while we're there,
+ * see if we have new peak rates.
+ */
+ old_tv = ifp->tv;
+ timersub(&new_tv, &old_tv, &tv);
+ elapsed = tv.tv_sec + (tv.tv_usec * 1e-6);
+
+ ifp->if_in_curtraffic = new_inb - old_inb;
+ ifp->if_out_curtraffic = new_outb - old_outb;
+
+ /*
+ * Rather than divide by the time specified on the comm-
+ * and line, we divide by ``elapsed'' as this is likely
+ * to be more accurate.
+ */
+ ifp->if_in_curtraffic /= elapsed;
+ ifp->if_out_curtraffic /= elapsed;
+
+ if (ifp->if_in_curtraffic > ifp->if_in_traffic_peak)
+ ifp->if_in_traffic_peak = ifp->if_in_curtraffic;
+
+ if (ifp->if_out_curtraffic > ifp->if_out_traffic_peak)
+ ifp->if_out_traffic_peak = ifp->if_out_curtraffic;
+
+ ifp->tv.tv_sec = new_tv.tv_sec;
+ ifp->tv.tv_usec = new_tv.tv_usec;
+
+ }
+
+ if (we_need_to_sort_interface_list)
+ sort_interface_list();
+
+ return;
+}
+
+/*
+ * We want to right justify our interface names against the first column
+ * (first sixteen or so characters), so we need to do some alignment.
+ */
+static void
+right_align_string(const struct if_stat *ifp)
+{
+ int str_len = 0, pad_len = 0;
+ char *newstr = NULL, *ptr = NULL;
+
+ if (ifp == NULL || ifp->if_mib.ifmd_name == NULL)
+ return;
+ else {
+ /* string length + '\0' */
+ str_len = strlen(ifp->if_mib.ifmd_name)+1;
+ pad_len = IF_NAMESIZE-(str_len);
+
+ newstr = (char *)ifp->if_name;
+ ptr = newstr + pad_len;
+ (void)memset((void *)newstr, (int)' ', IF_NAMESIZE);
+ (void)strncpy(ptr, (const char *)&ifp->if_mib.ifmd_name,
+ str_len);
+ }
+
+ return;
+}
+
+/*
+ * This function iterates through our list of interfaces, identifying
+ * those that are to be displayed (ifp->display = 1). For each interf-
+ * rface that we're displaying, we generate an appropriate position for
+ * it on the screen (ifp->if_ypos).
+ *
+ * This function is called any time a change is made to an interface's
+ * ``display'' state.
+ */
+void
+sort_interface_list(void)
+{
+ struct if_stat *ifp = NULL;
+ u_int y = 0;
+
+ y = STARTING_ROW;
+ SLIST_FOREACH(ifp, &curlist, link) {
+ if (ifp->display) {
+ ifp->if_ypos = y;
+ y += ROW_SPACING;
+ }
+ }
+}
+
+static
+unsigned int
+getifnum(void)
+{
+ u_int data = 0;
+ size_t datalen = 0;
+ static int name[] = { CTL_NET,
+ PF_LINK,
+ NETLINK_GENERIC,
+ IFMIB_SYSTEM,
+ IFMIB_IFCOUNT };
+
+ datalen = sizeof(data);
+ if (sysctl(name, 5, (void *)&data, (size_t *)&datalen, (void *)NULL,
+ (size_t)0) != 0)
+ IFSTAT_ERR(1, "sysctl error");
+ return data;
+}
+
+static void
+getifmibdata(int row, struct ifmibdata *data)
+{
+ size_t datalen = 0;
+ static int name[] = { CTL_NET,
+ PF_LINK,
+ NETLINK_GENERIC,
+ IFMIB_IFDATA,
+ 0,
+ IFDATA_GENERAL };
+ datalen = sizeof(*data);
+ name[4] = row;
+
+ if (sysctl(name, 6, (void *)data, (size_t *)&datalen, (void *)NULL,
+ (size_t)0) != 0)
+ IFSTAT_ERR(2, "sysctl error getting interface data");
+}
+
+int
+cmdifstat(const char *cmd, const char *args)
+{
+ int retval = 0;
+
+ retval = ifcmd(cmd, args);
+ /* ifcmd() returns 1 on success */
+ if (retval == 1) {
+ showifstat();
+ refresh();
+ }
+
+ return retval;
+}
diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c
new file mode 100644
index 000000000000..0702ea140b50
--- /dev/null
+++ b/usr.bin/systat/iostat.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 1998 Kenneth D. Merry.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+
+#include <devstat.h>
+#include <err.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "devs.h"
+
+struct statinfo cur, last;
+
+static int linesperregion;
+static double etime;
+static int numbers = 0; /* default display bar graphs */
+static int kbpt = 0; /* default ms/seek shown */
+
+static int barlabels(int);
+static void histogram(long double, int, double);
+static int numlabels(int);
+static int devstats(int, int, int);
+static void stat1(int, int);
+
+WINDOW *
+openiostat()
+{
+ return (subwin(stdscr, LINES-1-5, 0, 5, 0));
+}
+
+void
+closeiostat(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+int
+initiostat()
+{
+ if ((num_devices = devstat_getnumdevs(NULL)) < 0)
+ return(0);
+
+ cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ bzero(cur.dinfo, sizeof(struct devinfo));
+ bzero(last.dinfo, sizeof(struct devinfo));
+
+ /*
+ * This value for maxshowdevs (100) is bogus. I'm not sure exactly
+ * how to calculate it, though.
+ */
+ if (dsinit(100, &cur, &last, NULL) != 1)
+ return(0);
+
+ return(1);
+}
+
+void
+fetchiostat()
+{
+ struct devinfo *tmp_dinfo;
+ size_t len;
+
+ len = sizeof(cur.cp_time);
+ if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0)
+ || len != sizeof(cur.cp_time)) {
+ perror("kern.cp_time");
+ exit (1);
+ }
+ tmp_dinfo = last.dinfo;
+ last.dinfo = cur.dinfo;
+ cur.dinfo = tmp_dinfo;
+
+ last.snap_time = cur.snap_time;
+
+ /*
+ * Here what we want to do is refresh our device stats.
+ * getdevs() returns 1 when the device list has changed.
+ * If the device list has changed, we want to go through
+ * the selection process again, in case a device that we
+ * were previously displaying has gone away.
+ */
+ switch (devstat_getdevs(NULL, &cur)) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1:
+ cmdiostat("refresh", NULL);
+ break;
+ default:
+ break;
+ }
+ num_devices = cur.dinfo->numdevs;
+ generation = cur.dinfo->generation;
+
+}
+
+#define INSET 10
+
+void
+labeliostat()
+{
+ int row;
+
+ row = 0;
+ wmove(wnd, row, 0); wclrtobot(wnd);
+ mvwaddstr(wnd, row++, INSET,
+ "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
+ mvwaddstr(wnd, row++, 0, "cpu user|");
+ mvwaddstr(wnd, row++, 0, " nice|");
+ mvwaddstr(wnd, row++, 0, " system|");
+ mvwaddstr(wnd, row++, 0, "interrupt|");
+ mvwaddstr(wnd, row++, 0, " idle|");
+ if (numbers)
+ row = numlabels(row + 1);
+ else
+ row = barlabels(row + 1);
+}
+
+static int
+numlabels(row)
+ int row;
+{
+ int i, _col, regions, ndrives;
+ char tmpstr[10];
+
+#define COLWIDTH 17
+#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH)
+ for (ndrives = 0, i = 0; i < num_devices; i++)
+ if (dev_select[i].selected)
+ ndrives++;
+ regions = howmany(ndrives, DRIVESPERLINE);
+ /*
+ * Deduct -regions for blank line after each scrolling region.
+ */
+ linesperregion = (wnd->_maxy - row - regions) / regions;
+ /*
+ * Minimum region contains space for two
+ * label lines and one line of statistics.
+ */
+ if (linesperregion < 3)
+ linesperregion = 3;
+ _col = INSET;
+ for (i = 0; i < num_devices; i++)
+ if (dev_select[i].selected) {
+ if (_col + COLWIDTH >= wnd->_maxx - INSET) {
+ _col = INSET, row += linesperregion + 1;
+ if (row > wnd->_maxy - (linesperregion + 1))
+ break;
+ }
+ sprintf(tmpstr, "%s%d", dev_select[i].device_name,
+ dev_select[i].unit_number);
+ mvwaddstr(wnd, row, _col + 4, tmpstr);
+ mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s ");
+ _col += COLWIDTH;
+ }
+ if (_col)
+ row += linesperregion + 1;
+ return (row);
+}
+
+static int
+barlabels(row)
+ int row;
+{
+ int i;
+ char tmpstr[10];
+
+ mvwaddstr(wnd, row++, INSET,
+ "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
+ linesperregion = 2 + kbpt;
+ for (i = 0; i < num_devices; i++)
+ if (dev_select[i].selected) {
+ if (row > wnd->_maxy - linesperregion)
+ break;
+ sprintf(tmpstr, "%s%d", dev_select[i].device_name,
+ dev_select[i].unit_number);
+ mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
+ tmpstr);
+ mvwaddstr(wnd, row++, 0, " tps|");
+ if (kbpt)
+ mvwaddstr(wnd, row++, 0, " KB/t|");
+ }
+ return (row);
+}
+
+
+void
+showiostat()
+{
+ long t;
+ int i, row, _col;
+
+#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
+ etime = 0;
+ for(i = 0; i < CPUSTATES; i++) {
+ X(cp_time);
+ etime += cur.cp_time[i];
+ }
+ if (etime == 0.0)
+ etime = 1.0;
+ etime /= hertz;
+ row = 1;
+ for (i = 0; i < CPUSTATES; i++)
+ stat1(row++, i);
+ if (!numbers) {
+ row += 2;
+ for (i = 0; i < num_devices; i++)
+ if (dev_select[i].selected) {
+ if (row > wnd->_maxy - linesperregion)
+ break;
+ row = devstats(row, INSET, i);
+ }
+ return;
+ }
+ _col = INSET;
+ wmove(wnd, row + linesperregion, 0);
+ wdeleteln(wnd);
+ wmove(wnd, row + 3, 0);
+ winsertln(wnd);
+ for (i = 0; i < num_devices; i++)
+ if (dev_select[i].selected) {
+ if (_col + COLWIDTH >= wnd->_maxx - INSET) {
+ _col = INSET, row += linesperregion + 1;
+ if (row > wnd->_maxy - (linesperregion + 1))
+ break;
+ wmove(wnd, row + linesperregion, 0);
+ wdeleteln(wnd);
+ wmove(wnd, row + 3, 0);
+ winsertln(wnd);
+ }
+ (void) devstats(row + 3, _col, i);
+ _col += COLWIDTH;
+ }
+}
+
+static int
+devstats(row, _col, dn)
+ int row, _col, dn;
+{
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ long double busy_seconds;
+ int di;
+
+ di = dev_select[dn].position;
+
+ busy_seconds = cur.snap_time - last.snap_time;
+
+ if (devstat_compute_statistics(&cur.dinfo->devices[di],
+ &last.dinfo->devices[di], busy_seconds,
+ DSM_KB_PER_TRANSFER, &kb_per_transfer,
+ DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
+ DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0)
+ errx(1, "%s", devstat_errbuf);
+
+ if (numbers) {
+ mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ",
+ kb_per_transfer, transfers_per_second,
+ mb_per_second);
+ return(row);
+ }
+ wmove(wnd, row++, _col);
+ histogram(mb_per_second, 50, .5);
+ wmove(wnd, row++, _col);
+ histogram(transfers_per_second, 50, .5);
+ if (kbpt) {
+ wmove(wnd, row++, _col);
+ histogram(kb_per_transfer, 50, .5);
+ }
+
+ return(row);
+
+}
+
+static void
+stat1(row, o)
+ int row, o;
+{
+ int i;
+ double dtime;
+
+ dtime = 0.0;
+ for (i = 0; i < CPUSTATES; i++)
+ dtime += cur.cp_time[i];
+ if (dtime == 0.0)
+ dtime = 1.0;
+ wmove(wnd, row, INSET);
+#define CPUSCALE 0.5
+ histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE);
+}
+
+static void
+histogram(val, colwidth, scale)
+ long double val;
+ int colwidth;
+ double scale;
+{
+ char buf[10];
+ int k;
+ int v = (int)(val * scale) + 0.5;
+
+ k = MIN(v, colwidth);
+ if (v > colwidth) {
+ snprintf(buf, sizeof(buf), "%5.2Lf", val);
+ k -= strlen(buf);
+ while (k--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ return;
+ }
+ while (k--)
+ waddch(wnd, 'X');
+ wclrtoeol(wnd);
+}
+
+int
+cmdiostat(cmd, args)
+ const char *cmd, *args;
+{
+
+ if (prefix(cmd, "kbpt"))
+ kbpt = !kbpt;
+ else if (prefix(cmd, "numbers"))
+ numbers = 1;
+ else if (prefix(cmd, "bars"))
+ numbers = 0;
+ else if (!dscmd(cmd, args, 100, &cur))
+ return (0);
+ wclear(wnd);
+ labeliostat();
+ refresh();
+ return (1);
+}
diff --git a/usr.bin/systat/ip.c b/usr.bin/systat/ip.c
new file mode 100644
index 000000000000..1462ab102147
--- /dev/null
+++ b/usr.bin/systat/ip.c
@@ -0,0 +1,345 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* From:
+ "Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp"
+*/
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+struct stat {
+ struct ipstat i;
+ struct udpstat u;
+};
+
+static struct stat curstat, initstat, oldstat;
+
+/*-
+--0 1 2 3 4 5 6 7
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+01 IP Input IP Output
+02999999999 total packets received 999999999 total packets sent
+03999999999 - with bad checksums 999999999 - generated locally
+04999999999 - too short for header 999999999 - output drops
+05999999999 - too short for data 999999999 output fragments generated
+06999999999 - with invalid hlen 999999999 - fragmentation failed
+07999999999 - with invalid length 999999999 destinations unreachable
+08999999999 - with invalid version 999999999 packets output via raw IP
+09999999999 - jumbograms
+10999999999 total fragments received UDP Statistics
+11999999999 - fragments dropped 999999999 total input packets
+12999999999 - fragments timed out 999999999 - too short for header
+13999999999 - packets reassembled ok 999999999 - invalid checksum
+14999999999 packets forwarded 999999999 - no checksum
+15999999999 - unreachable dests 999999999 - invalid length
+16999999999 - redirects generated 999999999 - no socket for dest port
+17999999999 option errors 999999999 - no socket for broadcast
+18999999999 unwanted multicasts 999999999 - socket buffer full
+19999999999 delivered to upper layer 999999999 total output packets
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+--0 1 2 3 4 5 6 7
+*/
+
+WINDOW *
+openip(void)
+{
+ return (subwin(stdscr, LINES-4-1, 0, 4, 0));
+}
+
+void
+closeip(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+labelip(void)
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+#define L(row, str) mvwprintw(wnd, row, 10, str)
+#define R(row, str) mvwprintw(wnd, row, 45, str);
+ L(1, "IP Input"); R(1, "IP Output");
+ L(2, "total packets received"); R(2, "total packets sent");
+ L(3, "- with bad checksums"); R(3, "- generated locally");
+ L(4, "- too short for header"); R(4, "- output drops");
+ L(5, "- too short for data"); R(5, "output fragments generated");
+ L(6, "- with invalid hlen"); R(6, "- fragmentation failed");
+ L(7, "- with invalid length"); R(7, "destinations unreachable");
+ L(8, "- with invalid version"); R(8, "packets output via raw IP");
+ L(9, "- jumbograms");
+ L(10, "total fragments received"); R(10, "UDP Statistics");
+ L(11, "- fragments dropped"); R(11, "total input packets");
+ L(12, "- fragments timed out"); R(12, "- too short for header");
+ L(13, "- packets reassembled ok"); R(13, "- invalid checksum");
+ L(14, "packets forwarded"); R(14, "- no checksum");
+ L(15, "- unreachable dests"); R(15, "- invalid length");
+ L(16, "- redirects generated"); R(16, "- no socket for dest port");
+ L(17, "option errors"); R(17, "- no socket for broadcast");
+ L(18, "unwanted multicasts"); R(18, "- socket buffer full");
+ L(19, "delivered to upper layer"); R(19, "total output packets");
+#undef L
+#undef R
+}
+
+static void
+domode(struct stat *ret)
+{
+ const struct stat *sub;
+ int divisor = 1;
+
+ switch(currentmode) {
+ case display_RATE:
+ sub = &oldstat;
+ divisor = naptime;
+ break;
+ case display_DELTA:
+ sub = &oldstat;
+ break;
+ case display_SINCE:
+ sub = &initstat;
+ break;
+ default:
+ *ret = curstat;
+ return;
+ }
+#define DO(stat) ret->stat = (curstat.stat - sub->stat) / divisor
+ DO(i.ips_total);
+ DO(i.ips_badsum);
+ DO(i.ips_tooshort);
+ DO(i.ips_toosmall);
+ DO(i.ips_badhlen);
+ DO(i.ips_badlen);
+ DO(i.ips_fragments);
+ DO(i.ips_fragdropped);
+ DO(i.ips_fragtimeout);
+ DO(i.ips_forward);
+ DO(i.ips_cantforward);
+ DO(i.ips_redirectsent);
+ DO(i.ips_noproto);
+ DO(i.ips_delivered);
+ DO(i.ips_localout);
+ DO(i.ips_odropped);
+ DO(i.ips_reassembled);
+ DO(i.ips_fragmented);
+ DO(i.ips_ofragments);
+ DO(i.ips_cantfrag);
+ DO(i.ips_badoptions);
+ DO(i.ips_noroute);
+ DO(i.ips_badvers);
+ DO(i.ips_rawout);
+ DO(i.ips_toolong);
+ DO(i.ips_notmember);
+ DO(u.udps_ipackets);
+ DO(u.udps_hdrops);
+ DO(u.udps_badsum);
+ DO(u.udps_nosum);
+ DO(u.udps_badlen);
+ DO(u.udps_noport);
+ DO(u.udps_noportbcast);
+ DO(u.udps_fullsock);
+ DO(u.udps_opackets);
+#undef DO
+}
+
+void
+showip(void)
+{
+ struct stat stats;
+ u_long totalout;
+
+ domode(&stats);
+ totalout = stats.i.ips_forward + stats.i.ips_localout;
+
+#define DO(stat, row, col) \
+ mvwprintw(wnd, row, col, "%9lu", stats.stat)
+
+ DO(i.ips_total, 2, 0);
+ mvwprintw(wnd, 2, 35, "%9lu", totalout);
+ DO(i.ips_badsum, 3, 0);
+ DO(i.ips_localout, 3, 35);
+ DO(i.ips_tooshort, 4, 0);
+ DO(i.ips_odropped, 4, 35);
+ DO(i.ips_toosmall, 5, 0);
+ DO(i.ips_ofragments, 5, 35);
+ DO(i.ips_badhlen, 6, 0);
+ DO(i.ips_cantfrag, 6, 35);
+ DO(i.ips_badlen, 7, 0);
+ DO(i.ips_noroute, 7, 35);
+ DO(i.ips_badvers, 8, 0);
+ DO(i.ips_rawout, 8, 35);
+ DO(i.ips_toolong, 9, 0);
+ DO(i.ips_fragments, 10, 0);
+ DO(i.ips_fragdropped, 11, 0);
+ DO(u.udps_ipackets, 11, 35);
+ DO(i.ips_fragtimeout, 12, 0);
+ DO(u.udps_hdrops, 12, 35);
+ DO(i.ips_reassembled, 13, 0);
+ DO(u.udps_badsum, 13, 35);
+ DO(i.ips_forward, 14, 0);
+ DO(u.udps_nosum, 14, 35);
+ DO(i.ips_cantforward, 15, 0);
+ DO(u.udps_badlen, 15, 35);
+ DO(i.ips_redirectsent, 16, 0);
+ DO(u.udps_noport, 16, 35);
+ DO(i.ips_badoptions, 17, 0);
+ DO(u.udps_noportbcast, 17, 35);
+ DO(i.ips_notmember, 18, 0);
+ DO(u.udps_fullsock, 18, 35);
+ DO(i.ips_delivered, 19, 0);
+ DO(u.udps_opackets, 19, 35);
+#undef DO
+}
+
+int
+initip(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_IP;
+ name[3] = IPCTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting ipstat size failed");
+ return 0;
+ }
+ if (len > sizeof curstat.i) {
+ error("ipstat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat.i, &len, 0, 0) < 0) {
+ error("sysctl getting ipstat failed");
+ return 0;
+ }
+ name[2] = IPPROTO_UDP;
+ name[3] = UDPCTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting udpstat size failed");
+ return 0;
+ }
+ if (len > sizeof curstat.u) {
+ error("ipstat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat.u, &len, 0, 0) < 0) {
+ error("sysctl getting udpstat failed");
+ return 0;
+ }
+ oldstat = initstat;
+ return 1;
+}
+
+void
+resetip(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_IP;
+ name[3] = IPCTL_STATS;
+
+ len = sizeof initstat.i;
+ if (sysctl(name, 4, &initstat.i, &len, 0, 0) < 0) {
+ error("sysctl getting ipstat failed");
+ }
+ name[2] = IPPROTO_UDP;
+ name[3] = UDPCTL_STATS;
+
+ len = sizeof initstat.u;
+ if (sysctl(name, 4, &initstat.u, &len, 0, 0) < 0) {
+ error("sysctl getting udpstat failed");
+ }
+ oldstat = initstat;
+}
+
+void
+fetchip(void)
+{
+ int name[4];
+ size_t len;
+
+ oldstat = curstat;
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_IP;
+ name[3] = IPCTL_STATS;
+ len = sizeof curstat.i;
+
+ if (sysctl(name, 4, &curstat.i, &len, 0, 0) < 0)
+ return;
+ name[2] = IPPROTO_UDP;
+ name[3] = UDPCTL_STATS;
+ len = sizeof curstat.u;
+
+ if (sysctl(name, 4, &curstat.u, &len, 0, 0) < 0)
+ return;
+}
+
diff --git a/usr.bin/systat/ip6.c b/usr.bin/systat/ip6.c
new file mode 100644
index 000000000000..a88c5b48c2e6
--- /dev/null
+++ b/usr.bin/systat/ip6.c
@@ -0,0 +1,303 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* From:
+ "Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp"
+*/
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet6/ip6_var.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+static struct ip6stat curstat, initstat, oldstat;
+
+/*-
+--0 1 2 3 4 5 6 7
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+01 IPv6 Input IPv6 Output
+029999999 total packets received 999999999 total packets sent
+039999999 - too short for header 999999999 - generated locally
+049999999 - too short for data 999999999 - output drops
+059999999 - with invalid version 999999999 output fragments generated
+069999999 total fragments received 999999999 - fragmentation failed
+079999999 - fragments dropped 999999999 destinations unreachable
+089999999 - fragments timed out 999999999 packets output via raw IP
+099999999 - fragments overflown Input next-header histogram
+109999999 - packets reassembled ok 999999999 - destination options
+119999999 packets forwarded 999999999 - hop-by-hop options
+129999999 - unreachable dests 999999999 - IPv4
+139999999 - redirects generated 999999999 - TCP
+149999999 option errors 999999999 - UDP
+159999999 unwanted multicasts 999999999 - IPv6
+169999999 delivered to upper layer 999999999 - routing header
+17 999999999 - fragmentation header
+189999999 bad scope packets 999999999 - ICMP6
+199999999 address selection failed 999999999 - none
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+--0 1 2 3 4 5 6 7
+*/
+
+WINDOW *
+openip6(void)
+{
+ return (subwin(stdscr, LINES-4-1, 0, 4, 0));
+}
+
+void
+closeip6(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+labelip6(void)
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+#define L(row, str) mvwprintw(wnd, row, 10, str)
+#define R(row, str) mvwprintw(wnd, row, 45, str);
+ L(1, "IPv6 Input"); R(1, "IPv6 Output");
+ L(2, "total packets received"); R(2, "total packets sent");
+ L(3, "- too short for header"); R(3, "- generated locally");
+ L(4, "- too short for data"); R(4, "- output drops");
+ L(5, "- with invalid version"); R(5, "output fragments generated");
+ L(6, "total fragments received"); R(6, "- fragmentation failed");
+ L(7, "- fragments dropped"); R(7, "destinations unreachable");
+ L(8, "- fragments timed out"); R(8, "packets output via raw IP");
+ L(9, "- fragments overflown"); R(9, "Input next-header histogram");
+ L(10, "- packets reassembled ok"); R(10, " - destination options");
+ L(11, "packets forwarded"); R(11, " - hop-by-hop options");
+ L(12, "- unreachable dests"); R(12, " - IPv4");
+ L(13, "- redirects generated"); R(13, " - TCP");
+ L(14, "option errors"); R(14, " - UDP");
+ L(15, "unwanted multicasts"); R(15, " - IPv6");
+ L(16, "delivered to upper layer"); R(16, " - routing header");
+ R(17, " - fragmentation header");
+ L(18, "bad scope packets"); R(18, " - ICMP6");
+ L(19, "address selection failed"); R(19, " - none");
+#undef L
+#undef R
+}
+
+static void
+domode(struct ip6stat *ret)
+{
+ const struct ip6stat *sub;
+ int divisor = 1, i;
+
+ switch(currentmode) {
+ case display_RATE:
+ sub = &oldstat;
+ divisor = naptime;
+ break;
+ case display_DELTA:
+ sub = &oldstat;
+ break;
+ case display_SINCE:
+ sub = &initstat;
+ break;
+ default:
+ *ret = curstat;
+ return;
+ }
+#define DO(stat) ret->stat = (curstat.stat - sub->stat) / divisor
+ DO(ip6s_total);
+ DO(ip6s_tooshort);
+ DO(ip6s_toosmall);
+ DO(ip6s_fragments);
+ DO(ip6s_fragdropped);
+ DO(ip6s_fragtimeout);
+ DO(ip6s_fragoverflow);
+ DO(ip6s_forward);
+ DO(ip6s_cantforward);
+ DO(ip6s_redirectsent);
+ DO(ip6s_delivered);
+ DO(ip6s_localout);
+ DO(ip6s_odropped);
+ DO(ip6s_reassembled);
+ DO(ip6s_fragmented);
+ DO(ip6s_ofragments);
+ DO(ip6s_cantfrag);
+ DO(ip6s_badoptions);
+ DO(ip6s_noroute);
+ DO(ip6s_badvers);
+ DO(ip6s_rawout);
+ DO(ip6s_notmember);
+ for (i = 0; i < 256; i++)
+ DO(ip6s_nxthist[i]);
+ DO(ip6s_badscope);
+ DO(ip6s_sources_none);
+#undef DO
+}
+
+void
+showip6(void)
+{
+ struct ip6stat stats;
+ u_long totalout;
+
+ domode(&stats);
+ totalout = stats.ip6s_forward + stats.ip6s_localout;
+
+#define DO(stat, row, col) \
+ mvwprintw(wnd, row, col, "%9lu", stats.stat)
+
+ DO(ip6s_total, 2, 0);
+ mvwprintw(wnd, 2, 35, "%9lu", totalout);
+ DO(ip6s_localout, 3, 35);
+ DO(ip6s_tooshort, 3, 0);
+ DO(ip6s_odropped, 4, 35);
+ DO(ip6s_toosmall, 4, 0);
+ DO(ip6s_ofragments, 5, 35);
+ DO(ip6s_badvers, 5, 0);
+ DO(ip6s_cantfrag, 6, 35);
+ DO(ip6s_fragments, 6, 0);
+ DO(ip6s_noroute, 7, 35);
+ DO(ip6s_fragdropped, 7, 0);
+ DO(ip6s_rawout, 8, 35);
+ DO(ip6s_fragtimeout, 8, 0);
+ DO(ip6s_fragoverflow, 9, 0);
+ DO(ip6s_nxthist[IPPROTO_DSTOPTS], 10, 35);
+ DO(ip6s_reassembled, 10, 0);
+ DO(ip6s_nxthist[IPPROTO_HOPOPTS], 11, 35);
+ DO(ip6s_forward, 11, 0);
+ DO(ip6s_nxthist[IPPROTO_IPV4], 12, 35);
+ DO(ip6s_cantforward, 12, 0);
+ DO(ip6s_nxthist[IPPROTO_TCP], 13, 35);
+ DO(ip6s_redirectsent, 13, 0);
+ DO(ip6s_nxthist[IPPROTO_UDP], 14, 35);
+ DO(ip6s_badoptions, 14, 0);
+ DO(ip6s_nxthist[IPPROTO_IPV6], 15, 35);
+ DO(ip6s_notmember, 15, 0);
+ DO(ip6s_nxthist[IPPROTO_ROUTING], 16, 35);
+ DO(ip6s_delivered, 16, 0);
+ DO(ip6s_nxthist[IPPROTO_FRAGMENT], 17, 35);
+ DO(ip6s_nxthist[IPPROTO_ICMPV6], 18, 35);
+ DO(ip6s_badscope, 18, 0);
+ DO(ip6s_nxthist[IPPROTO_NONE], 19, 35);
+ DO(ip6s_sources_none, 19, 0);
+#undef DO
+}
+
+int
+initip6(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_IPV6;
+ name[3] = IPV6CTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting ip6stat size failed");
+ return 0;
+ }
+ if (len > sizeof curstat) {
+ error("ip6stat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting ip6stat failed");
+ return 0;
+ }
+ oldstat = initstat;
+ return 1;
+}
+
+void
+resetip6(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_IPV6;
+ name[3] = IPV6CTL_STATS;
+
+ len = sizeof initstat;
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting ipstat failed");
+ }
+
+ oldstat = initstat;
+}
+
+void
+fetchip6(void)
+{
+ int name[4];
+ size_t len;
+
+ oldstat = curstat;
+ name[0] = CTL_NET;
+ name[1] = PF_INET6;
+ name[2] = IPPROTO_IPV6;
+ name[3] = IPV6CTL_STATS;
+ len = sizeof curstat;
+
+ if (sysctl(name, 4, &curstat, &len, 0, 0) < 0)
+ return;
+}
+
+#endif
diff --git a/usr.bin/systat/keyboard.c b/usr.bin/systat/keyboard.c
new file mode 100644
index 000000000000..b563266be97f
--- /dev/null
+++ b/usr.bin/systat/keyboard.c
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)keyboard.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <ctype.h>
+#include <signal.h>
+#include <termios.h>
+
+#include "systat.h"
+#include "extern.h"
+
+int
+keyboard()
+{
+ char ch, line[80];
+ int oldmask;
+
+ for (;;) {
+ col = 0;
+ move(CMDLINE, 0);
+ do {
+ refresh();
+ ch = getch() & 0177;
+ if (ch == 0177 && ferror(stdin)) {
+ clearerr(stdin);
+ continue;
+ }
+ if (ch >= 'A' && ch <= 'Z')
+ ch += 'a' - 'A';
+ if (col == 0) {
+#define mask(s) (1 << ((s) - 1))
+ if (ch == CTRL('l')) {
+ oldmask = sigblock(mask(SIGALRM));
+ wrefresh(curscr);
+ sigsetmask(oldmask);
+ continue;
+ }
+ if (ch == CTRL('g')) {
+ oldmask = sigblock(mask(SIGALRM));
+ status();
+ sigsetmask(oldmask);
+ continue;
+ }
+ if (ch != ':')
+ continue;
+ move(CMDLINE, 0);
+ clrtoeol();
+ }
+ if (ch == erasechar() && col > 0) {
+ if (col == 1 && line[0] == ':')
+ continue;
+ col--;
+ goto doerase;
+ }
+ if (ch == CTRL('w') && col > 0) {
+ while (--col >= 0 && isspace(line[col]))
+ ;
+ col++;
+ while (--col >= 0 && !isspace(line[col]))
+ if (col == 0 && line[0] == ':')
+ break;
+ col++;
+ goto doerase;
+ }
+ if (ch == killchar() && col > 0) {
+ col = 0;
+ if (line[0] == ':')
+ col++;
+ doerase:
+ move(CMDLINE, col);
+ clrtoeol();
+ continue;
+ }
+ if (isprint(ch) || ch == ' ') {
+ line[col] = ch;
+ mvaddch(CMDLINE, col, ch);
+ col++;
+ }
+ } while (col == 0 || (ch != '\r' && ch != '\n'));
+ line[col] = '\0';
+ oldmask = sigblock(mask(SIGALRM));
+ command(line + 1);
+ sigsetmask(oldmask);
+ }
+ /*NOTREACHED*/
+}
diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c
new file mode 100644
index 000000000000..833a1884889f
--- /dev/null
+++ b/usr.bin/systat/main.c
@@ -0,0 +1,298 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <nlist.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "systat.h"
+#include "extern.h"
+
+static int dellave;
+
+kvm_t *kd;
+sig_t sigtstpdfl;
+double avenrun[3];
+int col;
+int naptime = 5;
+int verbose = 1; /* to report kvm read errs */
+struct clockinfo clkinfo;
+double hertz;
+char c;
+char *namp;
+char hostname[MAXHOSTNAMELEN];
+WINDOW *wnd;
+int CMDLINE;
+int use_kvm = 1;
+
+static WINDOW *wload; /* one line window for load average */
+
+int
+main(int argc, char **argv)
+{
+ char errbuf[_POSIX2_LINE_MAX], dummy;
+ size_t size;
+
+ (void) setlocale(LC_TIME, "");
+
+ argc--, argv++;
+ while (argc > 0) {
+ if (argv[0][0] == '-') {
+ struct cmdtab *p;
+
+ p = lookup(&argv[0][1]);
+ if (p == (struct cmdtab *)-1)
+ errx(1, "%s: ambiguous request", &argv[0][1]);
+ if (p == (struct cmdtab *)0)
+ errx(1, "%s: unknown request", &argv[0][1]);
+ curcmd = p;
+ } else {
+ naptime = atoi(argv[0]);
+ if (naptime <= 0)
+ naptime = 5;
+ }
+ argc--, argv++;
+ }
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd != NULL) {
+ /*
+ * Try to actually read something, we may be in a jail, and
+ * have /dev/null opened as /dev/mem.
+ */
+ if (kvm_nlist(kd, namelist) != 0 || namelist[0].n_value == 0 ||
+ kvm_read(kd, namelist[0].n_value, &dummy, sizeof(dummy)) !=
+ sizeof(dummy)) {
+ kvm_close(kd);
+ kd = NULL;
+ }
+ }
+ if (kd == NULL) {
+ /*
+ * Maybe we are lacking permissions? Retry, this time with bogus
+ * devices. We can now use sysctl only.
+ */
+ use_kvm = 0;
+ kd = kvm_openfiles("/dev/null", "/dev/null", "/dev/null",
+ O_RDONLY, errbuf);
+ if (kd == NULL) {
+ error("%s", errbuf);
+ exit(1);
+ }
+ }
+ signal(SIGINT, die);
+ signal(SIGQUIT, die);
+ signal(SIGTERM, die);
+
+ /*
+ * Initialize display. Load average appears in a one line
+ * window of its own. Current command's display appears in
+ * an overlapping sub-window of stdscr configured by the display
+ * routines to minimize update work by curses.
+ */
+ initscr();
+ CMDLINE = LINES - 1;
+ wnd = (*curcmd->c_open)();
+ if (wnd == NULL) {
+ warnx("couldn't initialize display");
+ die(0);
+ }
+ wload = newwin(1, 0, 3, 20);
+ if (wload == NULL) {
+ warnx("couldn't set up load average window");
+ die(0);
+ }
+ gethostname(hostname, sizeof (hostname));
+ size = sizeof(clkinfo);
+ if (sysctlbyname("kern.clockrate", &clkinfo, &size, NULL, 0)
+ || size != sizeof(clkinfo)) {
+ error("kern.clockrate");
+ die(0);
+ }
+ hertz = clkinfo.stathz;
+ (*curcmd->c_init)();
+ curcmd->c_flags |= CF_INIT;
+ labels();
+
+ dellave = 0.0;
+
+ signal(SIGALRM, display);
+ display(0);
+ noecho();
+ crmode();
+ keyboard();
+ /*NOTREACHED*/
+
+ return EXIT_SUCCESS;
+}
+
+void
+labels()
+{
+ if (curcmd->c_flags & CF_LOADAV) {
+ mvaddstr(2, 20,
+ "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10");
+ mvaddstr(3, 5, "Load Average");
+ }
+ (*curcmd->c_label)();
+#ifdef notdef
+ mvprintw(21, 25, "CPU usage on %s", hostname);
+#endif
+ refresh();
+}
+
+void
+display(signo)
+ int signo __unused;
+{
+ int i, j;
+
+ /* Get the load average over the last minute. */
+ (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
+ (*curcmd->c_fetch)();
+ if (curcmd->c_flags & CF_LOADAV) {
+ j = 5.0*avenrun[0] + 0.5;
+ dellave -= avenrun[0];
+ if (dellave >= 0.0)
+ c = '<';
+ else {
+ c = '>';
+ dellave = -dellave;
+ }
+ if (dellave < 0.1)
+ c = '|';
+ dellave = avenrun[0];
+ wmove(wload, 0, 0); wclrtoeol(wload);
+ for (i = (j > 50) ? 50 : j; i > 0; i--)
+ waddch(wload, c);
+ if (j > 50)
+ wprintw(wload, " %4.1f", avenrun[0]);
+ }
+ (*curcmd->c_refresh)();
+ if (curcmd->c_flags & CF_LOADAV)
+ wrefresh(wload);
+ wrefresh(wnd);
+ move(CMDLINE, col);
+ refresh();
+ alarm(naptime);
+}
+
+void
+load()
+{
+
+ (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
+ mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f",
+ avenrun[0], avenrun[1], avenrun[2]);
+ clrtoeol();
+}
+
+void
+die(signo)
+ int signo __unused;
+{
+ move(CMDLINE, 0);
+ clrtoeol();
+ refresh();
+ endwin();
+ exit(0);
+}
+
+#include <stdarg.h>
+
+void
+error(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[255];
+ int oy, ox;
+
+ va_start(ap, fmt);
+ if (wnd) {
+ getyx(stdscr, oy, ox);
+ (void) vsnprintf(buf, sizeof(buf), fmt, ap);
+ clrtoeol();
+ standout();
+ mvaddstr(CMDLINE, 0, buf);
+ standend();
+ move(oy, ox);
+ refresh();
+ } else {
+ (void) vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+ va_end(ap);
+}
+
+void
+nlisterr(n_list)
+ struct nlist n_list[];
+{
+ int i, n;
+
+ n = 0;
+ clear();
+ mvprintw(2, 10, "systat: nlist: can't find following symbols:");
+ for (i = 0;
+ n_list[i].n_name != NULL && *n_list[i].n_name != '\0'; i++)
+ if (n_list[i].n_value == 0)
+ mvprintw(2 + ++n, 10, "%s", n_list[i].n_name);
+ move(CMDLINE, 0);
+ clrtoeol();
+ refresh();
+ endwin();
+ exit(1);
+}
diff --git a/usr.bin/systat/mbufs.c b/usr.bin/systat/mbufs.c
new file mode 100644
index 000000000000..1193a3ea77fb
--- /dev/null
+++ b/usr.bin/systat/mbufs.c
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "systat.h"
+#include "extern.h"
+
+static struct mbstat *mbstat;
+static long *m_mbtypes;
+static short nmbtypes;
+
+static struct mtnames {
+ short mt_type;
+ const char *mt_name;
+} mtnames[] = {
+ { MT_DATA, "data"},
+ { MT_HEADER, "headers"},
+ { MT_SONAME, "socknames"},
+ { MT_FTABLE, "frags"},
+ { MT_CONTROL, "control"},
+ { MT_OOBDATA, "oobdata"}
+};
+#define NNAMES (sizeof (mtnames) / sizeof (mtnames[0]))
+
+WINDOW *
+openmbufs()
+{
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+void
+closembufs(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+labelmbufs()
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+ mvwaddstr(wnd, 0, 10,
+ "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50 /55 /60");
+}
+
+void
+showmbufs()
+{
+ int i, j, max, idx;
+ u_long totmbufs;
+ char buf[10];
+ const char *mtname;
+
+ totmbufs = mbstat->m_mbufs;
+
+ /*
+ * Print totals for different mbuf types.
+ */
+ for (j = 0; j < wnd->_maxy; j++) {
+ max = 0, idx = -1;
+ for (i = 0; i < wnd->_maxy; i++) {
+ if (i == MT_NOTMBUF)
+ continue;
+ if (i >= nmbtypes)
+ break;
+ if (m_mbtypes[i] > max) {
+ max = m_mbtypes[i];
+ idx = i;
+ }
+ }
+ if (max == 0)
+ break;
+
+ mtname = NULL;
+ for (i = 0; i < (int)NNAMES; i++)
+ if (mtnames[i].mt_type == idx)
+ mtname = mtnames[i].mt_name;
+ if (mtname == NULL)
+ mvwprintw(wnd, 1+j, 0, "%10d", idx);
+ else
+ mvwprintw(wnd, 1+j, 0, "%-10.10s", mtname);
+ wmove(wnd, 1 + j, 10);
+ if (max > 60) {
+ snprintf(buf, sizeof(buf), " %d", max);
+ max = 60;
+ while (max--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ } else
+ while (max--)
+ waddch(wnd, 'X');
+ wclrtoeol(wnd);
+ m_mbtypes[idx] = 0;
+ }
+
+ /*
+ * Print total number of free mbufs.
+ */
+ if (totmbufs > 0) {
+ mvwprintw(wnd, 1+j, 0, "%-10.10s", "Mbufs");
+ if (totmbufs > 60) {
+ snprintf(buf, sizeof(buf), " %lu", totmbufs);
+ totmbufs = 60;
+ while(totmbufs--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ } else {
+ while(totmbufs--)
+ waddch(wnd, 'X');
+ }
+ wclrtoeol(wnd);
+ j++;
+ }
+ wmove(wnd, 1+j, 0); wclrtobot(wnd);
+}
+
+int
+initmbufs()
+{
+ int i;
+ size_t len;
+
+ len = sizeof *mbstat;
+ if ((mbstat = malloc(len)) == NULL) {
+ error("malloc mbstat failed");
+ return 0;
+ }
+ if (sysctlbyname("kern.ipc.mbstat", mbstat, &len, NULL, 0) < 0) {
+ error("sysctl retrieving mbstat");
+ return 0;
+ }
+ nmbtypes = mbstat->m_numtypes;
+ if ((m_mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) {
+ error("calloc m_mbtypes failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+fetchmbufs()
+{
+ size_t len;
+
+ len = sizeof *mbstat;
+ if (sysctlbyname("kern.ipc.mbstat", mbstat, &len, NULL, 0) < 0)
+ printw("sysctl: mbstat: %s", strerror(errno));
+}
diff --git a/usr.bin/systat/mode.c b/usr.bin/systat/mode.c
new file mode 100644
index 000000000000..5f64e3ec237f
--- /dev/null
+++ b/usr.bin/systat/mode.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ */
+
+/*
+ * mode.c - mechanisms for dealing with SGI-style modal displays.
+ *
+ * There are four generally-understood useful modes for status displays
+ * of the sort exemplified by the IRIX ``netstat -C'' and ``osview''
+ * programs. We try to follow their example, although the user interface
+ * and terminology slightly differ.
+ *
+ * RATE - the default mode - displays the precise rate of change in
+ * each statistic in units per second, regardless of the actual display
+ * update interval.
+ *
+ * DELTA - displays the change in each statistic over the entire
+ * display update interval (i.e., RATE * interval).
+ *
+ * SINCE - displays the total change in each statistic since the module
+ * was last initialized or reset.
+ *
+ * ABSOLUTE - displays the current value of each statistic.
+ *
+ * In the SGI programs, these modes are selected by the single-character
+ * commands D, W, N, and A. In systat, they are the slightly-harder-to-type
+ * ``mode delta'', etc. The initial value for SINCE mode is initialized
+ * when the module is first started and can be reset using the ``reset''
+ * command (as opposed to the SGI way where changing modes implicitly
+ * resets). A ``mode'' command with no arguments displays the current
+ * mode in the command line.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+enum mode currentmode = display_RATE;
+
+static const char *const modes[] = { "rate", "delta", "since", "absolute" };
+
+int
+cmdmode(const char *cmd, const char *args)
+{
+ if (prefix(cmd, "mode")) {
+ if (args[0] == '\0') {
+ move(CMDLINE, 0);
+ clrtoeol();
+ printw("%s", modes[currentmode]);
+ } else if (prefix(args, "rate")) {
+ currentmode = display_RATE;
+ } else if (prefix(args, "delta")) {
+ currentmode = display_DELTA;
+ } else if (prefix(args, "since")) {
+ currentmode = display_SINCE;
+ } else if (prefix(args, "absolute")) {
+ currentmode = display_ABS;
+ } else {
+ printw("unknown mode `%s'", args);
+ }
+ return 1;
+ }
+ if(prefix(cmd, "reset")) {
+ curcmd->c_reset();
+ return 1;
+ }
+ return 0;
+}
diff --git a/usr.bin/systat/mode.h b/usr.bin/systat/mode.h
new file mode 100644
index 000000000000..9fc0feae96d5
--- /dev/null
+++ b/usr.bin/systat/mode.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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$
+ */
+
+/*
+ * mode.h - mechanisms for dealing with SGI-style modal displays.
+ */
+
+#ifndef MODE_H
+#define MODE_H 1
+
+enum mode { display_RATE, display_DELTA, display_SINCE, display_ABS };
+
+extern int cmdmode(const char *cmd, const char *args);
+extern enum mode currentmode;
+
+#endif /* MODE_H */
diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c
new file mode 100644
index 000000000000..c78f6feac7d7
--- /dev/null
+++ b/usr.bin/systat/netcmds.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/*
+ * Common network command support routines.
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+
+#define streq(a,b) (strcmp(a,b)==0)
+
+static struct hitem {
+ struct in_addr addr;
+ int onoff;
+} *hosts;
+
+int nports, nhosts, protos;
+
+static void changeitems(const char *, int);
+static int selectproto(const char *);
+static void showprotos(void);
+static int selectport(long, int);
+static void showports(void);
+static int selecthost(struct in_addr *, int);
+static void showhosts(void);
+
+int
+netcmd(cmd, args)
+ const char *cmd, *args;
+{
+
+ if (prefix(cmd, "proto")) {
+ if (*args == '\0') {
+ move(CMDLINE, 0);
+ clrtoeol();
+ addstr("which proto?");
+ } else if (!selectproto(args)) {
+ error("%s: Unknown protocol.", args);
+ }
+ return (1);
+ }
+ if (prefix(cmd, "ignore") || prefix(cmd, "display")) {
+ changeitems(args, prefix(cmd, "display"));
+ return (1);
+ }
+ if (prefix(cmd, "reset")) {
+ selectproto(0);
+ selecthost(0, 0);
+ selectport(-1, 0);
+ return (1);
+ }
+ if (prefix(cmd, "show")) {
+ move(CMDLINE, 0); clrtoeol();
+ if (*args == '\0') {
+ showprotos();
+ showhosts();
+ showports();
+ return (1);
+ }
+ if (prefix(args, "protos"))
+ showprotos();
+ else if (prefix(args, "hosts"))
+ showhosts();
+ else if (prefix(args, "ports"))
+ showports();
+ else
+ addstr("show what?");
+ return (1);
+ }
+ return (0);
+}
+
+
+static void
+changeitems(args, onoff)
+ const char *args;
+ int onoff;
+{
+ char *cp, *tmpstr, *tmpstr1;
+ struct servent *sp;
+ struct hostent *hp;
+ struct in_addr in;
+
+ tmpstr = tmpstr1 = strdup(args);
+ cp = index(tmpstr1, '\n');
+ if (cp)
+ *cp = '\0';
+ for (;;tmpstr1 = cp) {
+ for (cp = tmpstr1; *cp && isspace(*cp); cp++)
+ ;
+ tmpstr1 = cp;
+ for (; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (cp - tmpstr1 == 0)
+ break;
+ sp = getservbyname(tmpstr1,
+ protos == TCP ? "tcp" : protos == UDP ? "udp" : 0);
+ if (sp) {
+ selectport(sp->s_port, onoff);
+ continue;
+ }
+ hp = gethostbyname(tmpstr1);
+ if (hp == 0) {
+ in.s_addr = inet_addr(tmpstr1);
+ if ((int)in.s_addr == -1) {
+ error("%s: unknown host or port", tmpstr1);
+ continue;
+ }
+ } else
+ in = *(struct in_addr *)hp->h_addr;
+ selecthost(&in, onoff);
+ }
+ free(tmpstr);
+}
+
+static int
+selectproto(proto)
+ const char *proto;
+{
+
+ if (proto == 0 || streq(proto, "all"))
+ protos = TCP | UDP;
+ else if (streq(proto, "tcp"))
+ protos = TCP;
+ else if (streq(proto, "udp"))
+ protos = UDP;
+ else
+ return (0);
+
+ return (protos);
+}
+
+static void
+showprotos()
+{
+
+ if ((protos&TCP) == 0)
+ addch('!');
+ addstr("tcp ");
+ if ((protos&UDP) == 0)
+ addch('!');
+ addstr("udp ");
+}
+
+static struct pitem {
+ long port;
+ int onoff;
+} *ports;
+
+static int
+selectport(port, onoff)
+ long port;
+ int onoff;
+{
+ register struct pitem *p;
+
+ if (port == -1) {
+ if (ports == 0)
+ return (0);
+ free((char *)ports), ports = 0;
+ nports = 0;
+ return (1);
+ }
+ for (p = ports; p < ports+nports; p++)
+ if (p->port == port) {
+ p->onoff = onoff;
+ return (0);
+ }
+ if (nports == 0)
+ ports = (struct pitem *)malloc(sizeof (*p));
+ else
+ ports = (struct pitem *)realloc(ports, (nports+1)*sizeof (*p));
+ p = &ports[nports++];
+ p->port = port;
+ p->onoff = onoff;
+ return (1);
+}
+
+int
+checkport(inp)
+ register struct inpcb *inp;
+{
+ register struct pitem *p;
+
+ if (ports)
+ for (p = ports; p < ports+nports; p++)
+ if (p->port == inp->inp_lport || p->port == inp->inp_fport)
+ return (p->onoff);
+ return (1);
+}
+
+static void
+showports()
+{
+ register struct pitem *p;
+ struct servent *sp;
+
+ for (p = ports; p < ports+nports; p++) {
+ sp = getservbyport(p->port,
+ protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp");
+ if (!p->onoff)
+ addch('!');
+ if (sp)
+ printw("%s ", sp->s_name);
+ else
+ printw("%d ", p->port);
+ }
+}
+
+static int
+selecthost(in, onoff)
+ struct in_addr *in;
+ int onoff;
+{
+ register struct hitem *p;
+
+ if (in == 0) {
+ if (hosts == 0)
+ return (0);
+ free((char *)hosts), hosts = 0;
+ nhosts = 0;
+ return (1);
+ }
+ for (p = hosts; p < hosts+nhosts; p++)
+ if (p->addr.s_addr == in->s_addr) {
+ p->onoff = onoff;
+ return (0);
+ }
+ if (nhosts == 0)
+ hosts = (struct hitem *)malloc(sizeof (*p));
+ else
+ hosts = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p));
+ p = &hosts[nhosts++];
+ p->addr = *in;
+ p->onoff = onoff;
+ return (1);
+}
+
+int
+checkhost(inp)
+ register struct inpcb *inp;
+{
+ register struct hitem *p;
+
+ if (hosts)
+ for (p = hosts; p < hosts+nhosts; p++)
+ if (p->addr.s_addr == inp->inp_laddr.s_addr ||
+ p->addr.s_addr == inp->inp_faddr.s_addr)
+ return (p->onoff);
+ return (1);
+}
+
+static void
+showhosts()
+{
+ register struct hitem *p;
+ struct hostent *hp;
+
+ for (p = hosts; p < hosts+nhosts; p++) {
+ hp = gethostbyaddr((char *)&p->addr, sizeof (p->addr), AF_INET);
+ if (!p->onoff)
+ addch('!');
+ printw("%s ", hp ? hp->h_name : (char *)inet_ntoa(p->addr));
+ }
+}
diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c
new file mode 100644
index 000000000000..f802219d71fa
--- /dev/null
+++ b/usr.bin/systat/netstat.c
@@ -0,0 +1,586 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/*
+ * netstat
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/in_pcb.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_var.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_debug.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+
+static struct netinfo *enter(struct inpcb *, int, const char *);
+static void enter_kvm(struct inpcb *, struct socket *, int, const char *);
+static void enter_sysctl(struct inpcb *, struct xsocket *, int, const char *);
+static void fetchnetstat_kvm(void);
+static void fetchnetstat_sysctl(void);
+static char *inetname(struct in_addr);
+static void inetprint(struct in_addr *, int, const char *);
+
+#define streq(a,b) (strcmp(a,b)==0)
+#define YMAX(w) ((w)->_maxy-1)
+
+WINDOW *
+opennetstat()
+{
+ sethostent(1);
+ setnetent(1);
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+struct netinfo {
+ TAILQ_ENTRY(netinfo) chain;
+ short ni_line; /* line on screen */
+ short ni_seen; /* 0 when not present in list */
+ short ni_flags;
+#define NIF_LACHG 0x1 /* local address changed */
+#define NIF_FACHG 0x2 /* foreign address changed */
+ short ni_state; /* tcp state */
+ const char *ni_proto; /* protocol */
+ struct in_addr ni_laddr; /* local address */
+ long ni_lport; /* local port */
+ struct in_addr ni_faddr; /* foreign address */
+ long ni_fport; /* foreign port */
+ u_int ni_rcvcc; /* rcv buffer character count */
+ u_int ni_sndcc; /* snd buffer character count */
+};
+
+TAILQ_HEAD(netinfohead, netinfo) netcb = TAILQ_HEAD_INITIALIZER(netcb);
+
+static int aflag = 0;
+static int nflag = 0;
+static int lastrow = 1;
+
+void
+closenetstat(w)
+ WINDOW *w;
+{
+ struct netinfo *p;
+
+ endhostent();
+ endnetent();
+ TAILQ_FOREACH(p, &netcb, chain) {
+ if (p->ni_line != -1)
+ lastrow--;
+ p->ni_line = -1;
+ }
+ if (w != NULL) {
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+ }
+}
+
+static const char *miblist[] = {
+ "net.inet.tcp.pcblist",
+ "net.inet.udp.pcblist"
+};
+
+struct nlist namelist[] = {
+#define X_TCB 0
+ { "tcb" },
+#define X_UDB 1
+ { "udb" },
+ { "" },
+};
+
+int
+initnetstat()
+{
+ protos = TCP|UDP;
+ return(1);
+}
+
+void
+fetchnetstat()
+{
+ if (use_kvm)
+ fetchnetstat_kvm();
+ else
+ fetchnetstat_sysctl();
+}
+
+static void
+fetchnetstat_kvm()
+{
+ struct inpcb *next;
+ struct netinfo *p;
+ struct inpcbhead head;
+ struct inpcb inpcb;
+ struct socket sockb;
+ struct tcpcb tcpcb;
+ void *off;
+ int istcp;
+
+ if (namelist[X_TCB].n_value == 0)
+ return;
+ TAILQ_FOREACH(p, &netcb, chain)
+ p->ni_seen = 0;
+ if (protos&TCP) {
+ off = NPTR(X_TCB);
+ istcp = 1;
+ }
+ else if (protos&UDP) {
+ off = NPTR(X_UDB);
+ istcp = 0;
+ }
+ else {
+ error("No protocols to display");
+ return;
+ }
+again:
+ KREAD(off, &head, sizeof (struct inpcbhead));
+ LIST_FOREACH(next, &head, inp_list) {
+ KREAD(next, &inpcb, sizeof (inpcb));
+ next = &inpcb;
+ if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
+ continue;
+ if (nhosts && !checkhost(&inpcb))
+ continue;
+ if (nports && !checkport(&inpcb))
+ continue;
+ if (istcp) {
+ if (inpcb.inp_vflag & INP_TIMEWAIT) {
+ bzero(&sockb, sizeof(sockb));
+ enter_kvm(&inpcb, &sockb, TCPS_TIME_WAIT,
+ "tcp");
+ } else {
+ KREAD(inpcb.inp_socket, &sockb,
+ sizeof (sockb));
+ KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
+ enter_kvm(&inpcb, &sockb, tcpcb.t_state,
+ "tcp");
+ }
+ } else
+ enter_kvm(&inpcb, &sockb, 0, "udp");
+ }
+ if (istcp && (protos&UDP)) {
+ istcp = 0;
+ off = NPTR(X_UDB);
+ goto again;
+ }
+}
+
+static void
+fetchnetstat_sysctl()
+{
+ struct netinfo *p;
+ int idx;
+ struct xinpgen *inpg;
+ char *cur, *end;
+ struct inpcb *inpcb;
+ struct xinpcb *xip;
+ struct xtcpcb *xtp;
+ int plen;
+ size_t lsz;
+
+ TAILQ_FOREACH(p, &netcb, chain)
+ p->ni_seen = 0;
+ if (protos&TCP) {
+ idx = 0;
+ } else if (protos&UDP) {
+ idx = 1;
+ } else {
+ error("No protocols to display");
+ return;
+ }
+
+ for (;idx < 2; idx++) {
+ if (idx == 1 && !(protos&UDP))
+ break;
+ inpg = (struct xinpgen *)sysctl_dynread(miblist[idx], &lsz);
+ if (inpg == NULL) {
+ error("sysctl(%s...) failed", miblist[idx]);
+ continue;
+ }
+ /*
+ * We currently do no require a consistent pcb list.
+ * Try to be robust in case of struct size changes
+ */
+ cur = ((char *)inpg) + inpg->xig_len;
+ /* There is also a trailing struct xinpgen */
+ end = ((char *)inpg) + lsz - inpg->xig_len;
+ if (end <= cur) {
+ free(inpg);
+ continue;
+ }
+ if (idx == 0) { /* TCP */
+ xtp = (struct xtcpcb *)cur;
+ plen = xtp->xt_len;
+ } else {
+ xip = (struct xinpcb *)cur;
+ plen = xip->xi_len;
+ }
+ while (cur + plen <= end) {
+ if (idx == 0) { /* TCP */
+ xtp = (struct xtcpcb *)cur;
+ inpcb = &xtp->xt_inp;
+ } else {
+ xip = (struct xinpcb *)cur;
+ inpcb = &xip->xi_inp;
+ }
+ cur += plen;
+
+ if (!aflag && inet_lnaof(inpcb->inp_laddr) ==
+ INADDR_ANY)
+ continue;
+ if (nhosts && !checkhost(inpcb))
+ continue;
+ if (nports && !checkport(inpcb))
+ continue;
+ if (idx == 0) /* TCP */
+ enter_sysctl(inpcb, &xtp->xt_socket,
+ xtp->xt_tp.t_state, "tcp");
+ else /* UDP */
+ enter_sysctl(inpcb, &xip->xi_socket, 0, "udp");
+ }
+ free(inpg);
+ }
+}
+
+static void
+enter_kvm(inp, so, state, proto)
+ struct inpcb *inp;
+ struct socket *so;
+ int state;
+ const char *proto;
+{
+ struct netinfo *p;
+
+ if ((p = enter(inp, state, proto)) != NULL) {
+ p->ni_rcvcc = so->so_rcv.sb_cc;
+ p->ni_sndcc = so->so_snd.sb_cc;
+ }
+}
+
+static void
+enter_sysctl(inp, so, state, proto)
+ struct inpcb *inp;
+ struct xsocket *so;
+ int state;
+ const char *proto;
+{
+ struct netinfo *p;
+
+ if ((p = enter(inp, state, proto)) != NULL) {
+ p->ni_rcvcc = so->so_rcv.sb_cc;
+ p->ni_sndcc = so->so_snd.sb_cc;
+ }
+}
+
+
+static struct netinfo *
+enter(inp, state, proto)
+ struct inpcb *inp;
+ int state;
+ const char *proto;
+{
+ struct netinfo *p;
+
+ /*
+ * Only take exact matches, any sockets with
+ * previously unbound addresses will be deleted
+ * below in the display routine because they
+ * will appear as ``not seen'' in the kernel
+ * data structures.
+ */
+ TAILQ_FOREACH(p, &netcb, chain) {
+ if (!streq(proto, p->ni_proto))
+ continue;
+ if (p->ni_lport != inp->inp_lport ||
+ p->ni_laddr.s_addr != inp->inp_laddr.s_addr)
+ continue;
+ if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr &&
+ p->ni_fport == inp->inp_fport)
+ break;
+ }
+ if (p == NULL) {
+ if ((p = malloc(sizeof(*p))) == NULL) {
+ error("Out of memory");
+ return NULL;
+ }
+ TAILQ_INSERT_HEAD(&netcb, p, chain);
+ p->ni_line = -1;
+ p->ni_laddr = inp->inp_laddr;
+ p->ni_lport = inp->inp_lport;
+ p->ni_faddr = inp->inp_faddr;
+ p->ni_fport = inp->inp_fport;
+ p->ni_proto = strdup(proto);
+ p->ni_flags = NIF_LACHG|NIF_FACHG;
+ }
+ p->ni_state = state;
+ p->ni_seen = 1;
+ return p;
+}
+
+/* column locations */
+#define LADDR 0
+#define FADDR LADDR+23
+#define PROTO FADDR+23
+#define RCVCC PROTO+6
+#define SNDCC RCVCC+7
+#define STATE SNDCC+7
+
+
+void
+labelnetstat()
+{
+ if (use_kvm && namelist[X_TCB].n_type == 0)
+ return;
+ wmove(wnd, 0, 0); wclrtobot(wnd);
+ mvwaddstr(wnd, 0, LADDR, "Local Address");
+ mvwaddstr(wnd, 0, FADDR, "Foreign Address");
+ mvwaddstr(wnd, 0, PROTO, "Proto");
+ mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
+ mvwaddstr(wnd, 0, SNDCC, "Send-Q");
+ mvwaddstr(wnd, 0, STATE, "(state)");
+}
+
+void
+shownetstat()
+{
+ struct netinfo *p, *q;
+
+ /*
+ * First, delete any connections that have gone
+ * away and adjust the position of connections
+ * below to reflect the deleted line.
+ */
+ p = TAILQ_FIRST(&netcb);
+ while (p != NULL) {
+ if (p->ni_line == -1 || p->ni_seen) {
+ p = TAILQ_NEXT(p, chain);
+ continue;
+ }
+ wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
+ TAILQ_FOREACH(q, &netcb, chain)
+ if (q != p && q->ni_line > p->ni_line) {
+ q->ni_line--;
+ /* this shouldn't be necessary */
+ q->ni_flags |= NIF_LACHG|NIF_FACHG;
+ }
+ lastrow--;
+ q = TAILQ_NEXT(p, chain);
+ TAILQ_REMOVE(&netcb, p, chain);
+ free(p);
+ p = q;
+ }
+ /*
+ * Update existing connections and add new ones.
+ */
+ TAILQ_FOREACH(p, &netcb, chain) {
+ if (p->ni_line == -1) {
+ /*
+ * Add a new entry if possible.
+ */
+ if (lastrow > YMAX(wnd))
+ continue;
+ p->ni_line = lastrow++;
+ p->ni_flags |= NIF_LACHG|NIF_FACHG;
+ }
+ if (p->ni_flags & NIF_LACHG) {
+ wmove(wnd, p->ni_line, LADDR);
+ inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto);
+ p->ni_flags &= ~NIF_LACHG;
+ }
+ if (p->ni_flags & NIF_FACHG) {
+ wmove(wnd, p->ni_line, FADDR);
+ inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto);
+ p->ni_flags &= ~NIF_FACHG;
+ }
+ mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto);
+ mvwprintw(wnd, p->ni_line, RCVCC, "%6u", p->ni_rcvcc);
+ mvwprintw(wnd, p->ni_line, SNDCC, "%6u", p->ni_sndcc);
+ if (streq(p->ni_proto, "tcp")) {
+ if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
+ mvwprintw(wnd, p->ni_line, STATE, "%d",
+ p->ni_state);
+ else
+ mvwaddstr(wnd, p->ni_line, STATE,
+ tcpstates[p->ni_state]);
+ }
+ wclrtoeol(wnd);
+ }
+ if (lastrow < YMAX(wnd)) {
+ wmove(wnd, lastrow, 0); wclrtobot(wnd);
+ wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd); /* XXX */
+ }
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+static void
+inetprint(in, port, proto)
+ struct in_addr *in;
+ int port;
+ const char *proto;
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+
+ snprintf(line, sizeof(line), "%.*s.", 16, inetname(*in));
+ cp = index(line, '\0');
+ if (!nflag && port)
+ sp = getservbyport(port, proto);
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.8s",
+ sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d",
+ ntohs((u_short)port));
+ /* pad to full column to clear any garbage */
+ cp = index(line, '\0');
+ while (cp - line < 22)
+ *cp++ = ' ';
+ line[22] = '\0';
+ waddstr(wnd, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+static char *
+inetname(in)
+ struct in_addr in;
+{
+ char *cp = 0;
+ static char line[50];
+ struct hostent *hp;
+ struct netent *np;
+
+ if (!nflag && in.s_addr != INADDR_ANY) {
+ int net = inet_netof(in);
+ int lna = inet_lnaof(in);
+
+ if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp == 0) {
+ hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
+ if (hp)
+ cp = hp->h_name;
+ }
+ }
+ if (in.s_addr == INADDR_ANY)
+ strcpy(line, "*");
+ else if (cp)
+ snprintf(line, sizeof(line), "%s", cp);
+ else {
+ in.s_addr = ntohl(in.s_addr);
+#define C(x) ((x) & 0xff)
+ snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ return (line);
+}
+
+int
+cmdnetstat(cmd, args)
+ const char *cmd, *args;
+{
+ if (prefix(cmd, "all")) {
+ aflag = !aflag;
+ goto fixup;
+ }
+ if (prefix(cmd, "numbers") || prefix(cmd, "names")) {
+ struct netinfo *p;
+ int new;
+
+ new = prefix(cmd, "numbers");
+ if (new == nflag)
+ return (1);
+ TAILQ_FOREACH(p, &netcb, chain) {
+ if (p->ni_line == -1)
+ continue;
+ p->ni_flags |= NIF_LACHG|NIF_FACHG;
+ }
+ nflag = new;
+ goto redisplay;
+ }
+ if (!netcmd(cmd, args))
+ return (0);
+fixup:
+ fetchnetstat();
+redisplay:
+ shownetstat();
+ refresh();
+ return (1);
+}
diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c
new file mode 100644
index 000000000000..4b504ed8a993
--- /dev/null
+++ b/usr.bin/systat/pigs.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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 char sccsid[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Pigs display from Bill Reeves at Lucasfilm
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/user.h>
+
+#include <curses.h>
+#include <math.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+#include "extern.h"
+
+int compar(const void *, const void *);
+
+static int nproc;
+static struct p_times {
+ float pt_pctcpu;
+ struct kinfo_proc *pt_kp;
+} *pt;
+
+static long stime[CPUSTATES];
+static int fscale;
+static double lccpu;
+
+WINDOW *
+openpigs()
+{
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+void
+closepigs(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+
+void
+showpigs()
+{
+ register int i, j, y, k;
+ float total;
+ int factor;
+ const char *uname, *pname;
+ char pidname[30];
+
+ if (pt == NULL)
+ return;
+ /* Accumulate the percent of cpu per user. */
+ total = 0.0;
+ for (i = 0; i <= nproc; i++) {
+ /* Accumulate the percentage. */
+ total += pt[i].pt_pctcpu;
+ }
+
+ if (total < 1.0)
+ total = 1.0;
+ factor = 50.0/total;
+
+ qsort(pt, nproc + 1, sizeof (struct p_times), compar);
+ y = 1;
+ i = nproc + 1;
+ if (i > wnd->_maxy-1)
+ i = wnd->_maxy-1;
+ for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) {
+ if (pt[k].pt_kp == NULL) {
+ uname = "";
+ pname = "<idle>";
+ }
+ else {
+ uname = user_from_uid(pt[k].pt_kp->ki_uid, 0);
+ pname = pt[k].pt_kp->ki_comm;
+ }
+ wmove(wnd, y, 0);
+ wclrtoeol(wnd);
+ mvwaddstr(wnd, y, 0, uname);
+ snprintf(pidname, sizeof(pidname), "%10.10s", pname);
+ mvwaddstr(wnd, y, 9, pidname);
+ wmove(wnd, y, 20);
+ for (j = pt[k].pt_pctcpu*factor + 0.5; j > 0; j--)
+ waddch(wnd, 'X');
+ }
+ wmove(wnd, y, 0); wclrtobot(wnd);
+}
+
+int
+initpigs()
+{
+ fixpt_t ccpu;
+ size_t len;
+ int err;
+
+ len = sizeof(stime);
+ err = sysctlbyname("kern.cp_time", &stime, &len, NULL, 0);
+ if (err || len != sizeof(stime)) {
+ perror("kern.cp_time");
+ return (0);
+ }
+
+ len = sizeof(ccpu);
+ err = sysctlbyname("kern.ccpu", &ccpu, &len, NULL, 0);
+ if (err || len != sizeof(ccpu)) {
+ perror("kern.ccpu");
+ return (0);
+ }
+
+ len = sizeof(fscale);
+ err = sysctlbyname("kern.fscale", &fscale, &len, NULL, 0);
+ if (err || len != sizeof(fscale)) {
+ perror("kern.fscale");
+ return (0);
+ }
+
+ lccpu = log((double) ccpu / fscale);
+
+ return(1);
+}
+
+void
+fetchpigs()
+{
+ int i;
+ float ftime;
+ float *pctp;
+ struct kinfo_proc *kpp;
+ long c_time[CPUSTATES];
+ double t;
+ static int lastnproc = 0;
+ size_t len;
+ int err;
+
+ if ((kpp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)) == NULL) {
+ error("%s", kvm_geterr(kd));
+ if (pt)
+ free(pt);
+ return;
+ }
+ if (nproc > lastnproc) {
+ free(pt);
+ if ((pt =
+ malloc((nproc + 1) * sizeof(struct p_times))) == NULL) {
+ error("Out of memory");
+ die(0);
+ }
+ }
+ lastnproc = nproc;
+ /*
+ * calculate %cpu for each proc
+ */
+ for (i = 0; i < nproc; i++) {
+ pt[i].pt_kp = &kpp[i];
+ pctp = &pt[i].pt_pctcpu;
+ ftime = kpp[i].ki_swtime;
+ if (ftime == 0 || (kpp[i].ki_sflag & PS_INMEM) == 0)
+ *pctp = 0;
+ else
+ *pctp = ((double) kpp[i].ki_pctcpu /
+ fscale) / (1.0 - exp(ftime * lccpu));
+ }
+ /*
+ * and for the imaginary "idle" process
+ */
+ len = sizeof(c_time);
+ err = sysctlbyname("kern.cp_time", &c_time, &len, NULL, 0);
+ if (err || len != sizeof(c_time)) {
+ perror("kern.cp_time");
+ return;
+ }
+ t = 0;
+ for (i = 0; i < CPUSTATES; i++)
+ t += c_time[i] - stime[i];
+ if (t == 0.0)
+ t = 1.0;
+ pt[nproc].pt_kp = NULL;
+ pt[nproc].pt_pctcpu = (c_time[CP_IDLE] - stime[CP_IDLE]) / t;
+ for (i = 0; i < CPUSTATES; i++)
+ stime[i] = c_time[i];
+}
+
+void
+labelpigs()
+{
+ wmove(wnd, 0, 0);
+ wclrtoeol(wnd);
+ mvwaddstr(wnd, 0, 20,
+ "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
+}
+
+int
+compar(a, b)
+ const void *a, *b;
+{
+ return (((const struct p_times *) a)->pt_pctcpu >
+ ((const struct p_times *) b)->pt_pctcpu)? -1: 1;
+}
diff --git a/usr.bin/systat/swap.c b/usr.bin/systat/swap.c
new file mode 100644
index 000000000000..eca672654ea9
--- /dev/null
+++ b/usr.bin/systat/swap.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95";
+#endif
+
+/*
+ * swapinfo - based on a program of the same name by Kevin Lahey
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <kvm.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+
+#include "systat.h"
+#include "extern.h"
+
+kvm_t *kd;
+
+static long blocksize;
+static int hlen;
+
+WINDOW *
+openswap()
+{
+ return (subwin(stdscr, LINES-5-1, 0, 5, 0));
+}
+
+void
+closeswap(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+/*
+ * The meat of all the swap stuff is stolen from pstat(8)'s
+ * swapmode(), which is based on a program called swapinfo written by
+ * Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+
+int
+initswap()
+{
+ char msgbuf[BUFSIZ];
+ static int once = 0;
+ struct kvm_swap dummy;
+
+ if (once)
+ return (1);
+
+ if (kvm_getswapinfo(kd, &dummy, 1, 0) < 0) {
+ snprintf(msgbuf, sizeof(msgbuf), "systat: kvm_getswapinfo failed");
+ error("%s", msgbuf);
+ return (0);
+ }
+
+ once = 1;
+ return (1);
+}
+
+static struct kvm_swap kvmsw[16];
+static int kvnsw;
+
+void
+fetchswap()
+{
+ kvnsw = kvm_getswapinfo(kd, kvmsw, 16, 0);
+}
+
+void
+labelswap()
+{
+ char *header;
+ int row, i;
+
+ fetchswap();
+
+ row = 0;
+ wmove(wnd, row, 0); wclrtobot(wnd);
+ header = getbsize(&hlen, &blocksize);
+ mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s",
+ "Disk", hlen, header, "Used",
+ "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100");
+
+ for (i = 0; i < kvnsw; ++i) {
+ mvwprintw(wnd, i + 1, 0, "%-5s", kvmsw[i].ksw_devname);
+ }
+}
+
+void
+showswap()
+{
+ int i;
+ int pagesize = getpagesize();
+
+#define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize))
+
+ for (i = 0; i <= kvnsw; ++i) {
+ int lcol = 5;
+ int count;
+
+ if (i == kvnsw) {
+ if (kvnsw == 1)
+ break;
+ mvwprintw(
+ wnd,
+ i + 1,
+ lcol,
+ "%-5s",
+ "Total"
+ );
+ lcol += 5;
+ }
+ if (kvmsw[i].ksw_total == 0) {
+ mvwprintw(
+ wnd,
+ i + 1,
+ lcol + 5,
+ "(swap not configured)"
+ );
+ continue;
+ }
+
+ mvwprintw(
+ wnd,
+ i + 1,
+ lcol,
+ "%*d",
+ hlen,
+ CONVERT(kvmsw[i].ksw_total)
+ );
+ lcol += hlen;
+
+ mvwprintw(
+ wnd,
+ i + 1,
+ lcol,
+ "%9d ",
+ CONVERT(kvmsw[i].ksw_used)
+ );
+
+ count = (int)((double)kvmsw[i].ksw_used * 49.999 /
+ (double)kvmsw[i].ksw_total);
+
+ while (count >= 0) {
+ waddch(wnd, 'X');
+ --count;
+ }
+ }
+}
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
new file mode 100644
index 000000000000..23add08a66d2
--- /dev/null
+++ b/usr.bin/systat/systat.1
@@ -0,0 +1,624 @@
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 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.
+.\"
+.\" @(#)systat.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD$
+.\"
+.Dd September 9, 1997
+.Dt SYSTAT 1
+.Os
+.Sh NAME
+.Nm systat
+.Nd display system statistics on a crt
+.Sh SYNOPSIS
+.Nm
+.Op Fl display
+.Op Ar refresh-interval
+.Sh DESCRIPTION
+The
+.Nm
+utility displays various system statistics in a screen oriented fashion
+using the curses screen display library,
+.Xr ncurses 3 .
+.Pp
+While
+.Nm
+is running the screen is usually divided into two windows (an exception
+is the vmstat display which uses the entire screen).
+The
+upper window depicts the current system load average.
+The
+information displayed in the lower window may vary, depending on
+user commands.
+The last line on the screen is reserved for user
+input and error messages.
+.Pp
+By default
+.Nm
+displays the processes getting the largest percentage of the processor
+in the lower window.
+Other displays show swap space usage, disk
+.Tn I/O
+statistics (a la
+.Xr iostat 8 ) ,
+virtual memory statistics (a la
+.Xr vmstat 8 ) ,
+network ``mbuf'' utilization,
+.Tn TCP/IP
+statistics,
+and network connections (a la
+.Xr netstat 1 ) .
+.Pp
+Input is interpreted at two different levels.
+A ``global'' command interpreter processes all keyboard input.
+If this command interpreter fails to recognize a command, the
+input line is passed to a per-display command interpreter.
+This
+allows each display to have certain display-specific commands.
+.Pp
+Command line options:
+.Bl -tag -width "refresh_interval"
+.It Fl Ns Ar display
+The
+.Fl
+flag expects
+.Ar display
+to be one of:
+.Ic icmp ,
+.Ic icmp6 ,
+.Ic ifstat ,
+.Ic iostat ,
+.Ic ip ,
+.Ic ip6 ,
+.Ic mbufs ,
+.Ic netstat ,
+.Ic pigs ,
+.Ic swap ,
+.Ic tcp ,
+or
+.Ic vmstat .
+These displays can also be requested interactively (without the
+.Dq Fl )
+and are described in
+full detail below.
+.It Ar refresh-interval
+The
+.Ar refresh-value
+specifies the screen refresh time interval in seconds.
+.El
+.Pp
+Certain characters cause immediate action by
+.Nm .
+These are
+.Bl -tag -width Fl
+.It Ic \&^L
+Refresh the screen.
+.It Ic \&^G
+Print the name of the current ``display'' being shown in
+the lower window and the refresh interval.
+.It Ic \&:
+Move the cursor to the command line and interpret the input
+line typed as a command.
+While entering a command the
+current character erase, word erase, and line kill characters
+may be used.
+.El
+.Pp
+The following commands are interpreted by the ``global''
+command interpreter.
+.Bl -tag -width Fl
+.It Ic help
+Print the names of the available displays on the command line.
+.It Ic load
+Print the load average over the past 1, 5, and 15 minutes
+on the command line.
+.It Ic stop
+Stop refreshing the screen.
+.It Xo
+.Op Ic start
+.Op Ar number
+.Xc
+Start (continue) refreshing the screen.
+If a second, numeric,
+argument is provided it is interpreted as a refresh interval
+(in seconds).
+Supplying only a number will set the refresh interval to this
+value.
+.It Ic quit
+Exit
+.Nm .
+(This may be abbreviated to
+.Ic q . )
+.El
+.Pp
+The available displays are:
+.Bl -tag -width Ic
+.It Ic pigs
+Display, in the lower window, those processes resident in main
+memory and getting the
+largest portion of the processor (the default display).
+When less than 100% of the
+processor is scheduled to user processes, the remaining time
+is accounted to the ``idle'' process.
+.It Ic icmp
+Display, in the lower window, statistics about messages received and
+transmitted by the Internet Control Message Protocol
+.Pq Dq Tn ICMP .
+The left half of the screen displays information about received
+packets, and the right half displays information regarding transmitted
+packets.
+.Pp
+The
+.Ic icmp
+display understands two commands:
+.Ic mode
+and
+.Ic reset .
+The
+.Ic mode
+command is used to select one of four display modes, given as its argument:
+.Bl -tag -width absoluteXX -compact
+.It Ic rate :
+show the rate of change of each value in packets (the default)
+per second
+.It Ic delta :
+show the rate of change of each value in packets per refresh interval
+.It Ic since :
+show the total change of each value since the display was last reset
+.It Ic absolute :
+show the absolute value of each statistic
+.El
+.Pp
+The
+.Ic reset
+command resets the baseline for
+.Ic since
+mode.
+The
+.Ic mode
+command with no argument will display the current mode in the command
+line.
+.It Ic icmp6
+This display is like the
+.Ic icmp
+display,
+but displays statistics for IPv6 ICMP.
+.It Ic ip
+Otherwise identical to the
+.Ic icmp
+display, except that it displays
+.Tn IP
+and
+.Tn UDP
+statistics.
+.It Ic ip6
+Like the
+.Ic ip
+display,
+except that it displays
+.Tn IPv6
+statics.
+It does not display
+.Tn UDP statistics.
+.It Ic tcp
+Like
+.Ic icmp ,
+but with
+.Tn TCP
+statistics.
+.It Ic iostat
+Display, in the lower window, statistics about processor use
+and disk throughput.
+Statistics on processor use appear as
+bar graphs of the amount of time executing in user mode (``user''),
+in user mode running low priority processes (``nice''), in
+system mode (``system''), in interrupt mode (``interrupt''),
+and idle (``idle'').
+Statistics
+on disk throughput show, for each drive, megabytes per second,
+average number of disk transactions per second, and
+average kilobytes of data per transaction.
+This information may be
+displayed as bar graphs or as rows of numbers which scroll downward.
+Bar
+graphs are shown by default.
+.Pp
+The following commands are specific to the
+.Ic iostat
+display; the minimum unambiguous prefix may be supplied.
+.Pp
+.Bl -tag -width Fl -compact
+.It Cm numbers
+Show the disk
+.Tn I/O
+statistics in numeric form.
+Values are
+displayed in numeric columns which scroll downward.
+.It Cm bars
+Show the disk
+.Tn I/O
+statistics in bar graph form (default).
+.It Cm kbpt
+Toggle the display of kilobytes per transaction.
+(the default is to
+not display kilobytes per transaction).
+.El
+.It Ic swap
+Show 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 graph shows the percentage of space in use on each partition.
+If there are more than one swap partition in use,
+a total line is also shown.
+Areas known to the kernel, but not in use are shown as not available.
+.It Ic mbufs
+Display, in the lower window, the number of mbufs allocated
+for particular uses, i.e., data, socket structures, etc.
+.It Ic vmstat
+Take over the entire display and show a (rather crowded) compendium
+of statistics related to virtual memory usage, process scheduling,
+device interrupts, system name translation cacheing, disk
+.Tn I/O
+etc.
+.Pp
+The upper left quadrant of the screen shows the number
+of users logged in and the load average over the last one, five,
+and fifteen minute intervals.
+Below this line are statistics on memory utilization.
+The first row of the table reports memory usage only among
+active processes, that is processes that have run in the previous
+twenty seconds.
+The second row reports on memory usage of all processes.
+The first column reports on the number of physical pages
+claimed by processes.
+The second column reports the number of physical pages that
+are devoted to read only text pages.
+The third and fourth columns report the same two figures for
+virtual pages, that is the number of pages that would be
+needed if all processes had all of their pages.
+Finally the last column shows the number of physical pages
+on the free list.
+.Pp
+Below the memory display is a list of the
+average number of processes (over the last refresh interval)
+that are runnable (`r'), in page wait (`p'),
+in disk wait other than paging (`d'),
+sleeping (`s'), and swapped out but desiring to run (`w').
+The row also shows the average number of context switches
+(`Csw'), traps (`Trp'; includes page faults), system calls (`Sys'),
+interrupts (`Int'), network software interrupts (`Sof'), and page
+faults (`Flt').
+.Pp
+Below the process queue length listing is a numerical listing and
+a bar graph showing the amount of
+system (shown as `='), interrupt (shown as `+'), user (shown as `>'),
+nice (shown as `-'), and idle time (shown as ` ').
+.Pp
+Below the process display are statistics on name translations.
+It lists the number of names translated in the previous interval,
+the number and percentage of the translations that were
+handled by the system wide name translation cache, and
+the number and percentage of the translations that were
+handled by the per process name translation cache.
+.Pp
+At the bottom left is the disk usage display.
+It reports the number of
+kilobytes per transaction, transactions per second, megabytes
+per second and the percentage of the time the disk was busy averaged
+over the refresh period of the display (by default, five seconds).
+The system keeps statistics on most every storage device.
+In general, up
+to seven devices are displayed.
+The devices displayed by default are the
+first devices in the kernel's device list.
+See
+.Xr devstat 3
+and
+.Xr devstat 9
+for details on the devstat system.
+.Pp
+Under the date in the upper right hand quadrant are statistics
+on paging and swapping activity.
+The first two columns report the average number of pages
+brought in and out per second over the last refresh interval
+due to page faults and the paging daemon.
+The third and fourth columns report the average number of pages
+brought in and out per second over the last refresh interval
+due to swap requests initiated by the scheduler.
+The first row of the display shows the average
+number of disk transfers per second over the last refresh interval;
+the second row of the display shows the average
+number of pages transferred per second over the last refresh interval.
+.Pp
+Below the paging statistics is a column of lines regarding the virtual
+memory system which list the average number of
+pages copied on write (`cow'),
+pages zero filled on demand (`zfod'),
+slow (on-the-fly) zero fills percentage (`%slo-z'),
+pages wired down (`wire'),
+active pages (`act'),
+inactive pages (`inact'),
+pages on the buffer cache queue (`cache'),
+number of free pages (`free'),
+pages freed by the page daemon (`daefr'),
+pages freed by exiting processes (`prcfr'),
+pages reactivated from the free list (`react'),
+times the page daemon was awakened (`pdwak'),
+pages analyzed by the page daemon (`pdpgs'),
+and
+intransit blocking page faults (`intrn')
+per second over the refresh interval.
+.Pp
+At the bottom of this column are lines showing the
+amount of memory, in kilobytes, used for the buffer cache (`buf'),
+the number of dirty buffers in the buffer cache (`dirtybuf'),
+desired maximum size of vnode cache (`desiredvnodes') (mostly unused,
+except to size the name cache),
+number of vnodes actually allocated (`numvnodes'),
+and
+number of allocated vnodes that are free (`freevnodes').
+.Pp
+Running down the right hand side of the display is a breakdown
+of the interrupts being handled by the system.
+At the top of the list is the total interrupts per second
+over the time interval.
+The rest of the column breaks down the total on a device
+by device basis.
+Only devices that have interrupted at least once since boot time are shown.
+.Pp
+The following commands are specific to the
+.Ic vmstat
+display; the minimum unambiguous prefix may be supplied.
+.Pp
+.Bl -tag -width Ar -compact
+.It Cm boot
+Display cumulative statistics since the system was booted.
+.It Cm run
+Display statistics as a running total from the point this
+command is given.
+.It Cm time
+Display statistics averaged over the refresh interval (the default).
+.It Cm want_fd
+Toggle the display of fd devices in the disk usage display.
+.It Cm zero
+Reset running statistics to zero.
+.El
+.It Ic netstat
+Display, in the lower window, network connections.
+By default,
+network servers awaiting requests are not displayed.
+Each address
+is displayed in the format ``host.port'', with each shown symbolically,
+when possible.
+It is possible to have addresses displayed numerically,
+limit the display to a set of ports, hosts, and/or protocols
+(the minimum unambiguous prefix may be supplied):
+.Pp
+.Bl -tag -width Ar -compact
+.It Cm all
+Toggle the displaying of server processes awaiting requests (this
+is the equivalent of the
+.Fl a
+flag to
+.Xr netstat 1 ) .
+.It Cm numbers
+Display network addresses numerically.
+.It Cm names
+Display network addresses symbolically.
+.It Cm proto Ar protocol
+Display only network connections using the indicated
+.Ar protocol .
+Supported protocols are ``tcp'', ``udp'', and ``all''.
+.It Cm ignore Op Ar items
+Do not display information about connections associated with
+the specified hosts or ports.
+Hosts and ports may be specified
+by name (``vangogh'', ``ftp''), or numerically.
+Host addresses
+use the Internet dot notation (``128.32.0.9'').
+Multiple items
+may be specified with a single command by separating them with
+spaces.
+.It Cm display Op Ar items
+Display information about the connections associated with the
+specified hosts or ports.
+As for
+.Ar ignore ,
+.Op Ar items
+may be names or numbers.
+.It Cm show Op Ar ports\&|hosts
+Show, on the command line, the currently selected protocols,
+hosts, and ports.
+Hosts and ports which are being ignored
+are prefixed with a `!'.
+If
+.Ar ports
+or
+.Ar hosts
+is supplied as an argument to
+.Cm show ,
+then only the requested information will be displayed.
+.It Cm reset
+Reset the port, host, and protocol matching mechanisms to the default
+(any protocol, port, or host).
+.El
+.It Ic ifstat
+Display the network traffic going through active interfaces on the
+system.
+Idle interfaces will not be displayed until they receive some
+traffic.
+.Pp
+For each interface being displayed, the current, peak and total
+statistics are displayed for incoming and outgoing traffic.
+By default,
+the
+.Ic ifstat
+display will automatically scale the units being used so that they are
+in a human-readable format.
+The scaling units used for the current and
+peak
+traffic columns can be altered by the
+.Ic scale
+command.
+.Bl -tag -width ".Cm scale Op Ar units"
+.It Cm scale Op Ar units
+Modify the scale used to display the current and peak traffic over all
+interfaces.
+The following units are recognised: kbit, kbyte, mbit,
+mbyte, gbit, gbyte and auto.
+.El
+.El
+.Pp
+Commands to switch between displays may be abbreviated to the
+minimum unambiguous prefix; for example, ``io'' for ``iostat''.
+Certain information may be discarded when the screen size is
+insufficient for display.
+For example, on a machine with 10
+drives the
+.Ic iostat
+bar graph displays only 3 drives on a 24 line terminal.
+When
+a bar graph would overflow the allotted screen space it is
+truncated and the actual value is printed ``over top'' of the bar.
+.Pp
+The following commands are common to each display which shows
+information about disk drives.
+These commands are used to
+select a set of drives to report on, should your system have
+more drives configured than can normally be displayed on the
+screen.
+.Pp
+.Bl -tag -width Ar -compact
+.It Cm ignore Op Ar drives
+Do not display information about the drives indicated.
+Multiple
+drives may be specified, separated by spaces.
+.It Cm display Op Ar drives
+Display information about the drives indicated.
+Multiple drives
+may be specified, separated by spaces.
+.It Cm only Op Ar drives
+Display only the specified drives.
+Multiple drives may be specified,
+separated by spaces.
+.It Cm drives
+Display a list of available devices.
+.It Cm match Xo
+.Ar type , Ns Ar if , Ns Ar pass
+.Op | Ar ...
+.Xc
+Display devices matching the given pattern.
+The basic matching
+expressions are the same as those used in
+.Xr iostat 8
+with one difference.
+Instead of specifying multiple
+.Fl t
+arguments which are then ORed together, the user instead specifies multiple
+matching expressions joined by the pipe
+.Pq Ql \&|
+character.
+The comma
+separated arguments within each matching expression are ANDed together, and
+then the pipe separated matching expressions are ORed together.
+Any
+device matching the combined expression will be displayed, if there is room
+to display it.
+For example:
+.Pp
+.Dl match da,scsi | cd,ide
+.Pp
+This will display all SCSI Direct Access devices and all IDE CDROM devices.
+.Pp
+.Dl match da | sa | cd,pass
+.Pp
+This will display all Direct Access devices, all Sequential Access devices,
+and all passthrough devices that provide access to CDROM drives.
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr kvm 3 ,
+.Xr icmp 4 ,
+.Xr icmp6 4 ,
+.Xr ip 4 ,
+.Xr ip6 4 ,
+.Xr tcp 4 ,
+.Xr udp 4 ,
+.Xr iostat 8 ,
+.Xr vmstat 8
+.Sh FILES
+.Bl -tag -width /boot/kernel/kernel -compact
+.It Pa /boot/kernel/kernel
+For the namelist.
+.It Pa /dev/kmem
+For information in main memory.
+.It Pa /etc/hosts
+For host names.
+.It Pa /etc/networks
+For network names.
+.It Pa /etc/services
+For port names.
+.El
+.Sh HISTORY
+The
+.Nm
+program appeared in
+.Bx 4.3 .
+The
+.Ic icmp ,
+.Ic ip ,
+and
+.Ic tcp
+displays appeared in
+.Fx 3.0 ;
+the notion of having different display modes for the
+.Tn ICMP ,
+.Tn IP ,
+.Tn TCP ,
+and
+.Tn UDP
+statistics was stolen from the
+.Fl C
+option to
+.Xr netstat 1
+in Silicon Graphics'
+.Tn IRIX
+system.
+.Sh BUGS
+Certain displays presume a minimum of 80 characters per line.
+The
+.Ic vmstat
+display looks out of place because it is (it was added in as
+a separate display rather than created as a new program).
diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h
new file mode 100644
index 000000000000..f37a04ceec5c
--- /dev/null
+++ b/usr.bin/systat/systat.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1980, 1989, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ *
+ * From: @(#)systat.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+#include <curses.h>
+
+struct cmdtab {
+ const char *c_name; /* command name */
+ void (*c_refresh)(void); /* display refresh */
+ void (*c_fetch)(void); /* sets up data structures */
+ void (*c_label)(void); /* label display */
+ int (*c_init)(void); /* initialize namelist, etc. */
+ WINDOW *(*c_open)(void); /* open display */
+ void (*c_close)(WINDOW *); /* close display */
+ int (*c_cmd)(const char *, const char *); /* display command interpreter */
+ void (*c_reset)(void); /* reset ``mode since'' display */
+ char c_flags; /* see below */
+};
+
+/*
+ * If we are started with privileges, use a kmem interface for netstat handling,
+ * otherwise use sysctl.
+ * In case of many open sockets, the sysctl handling might become slow.
+ */
+extern int use_kvm;
+
+#define CF_INIT 0x1 /* been initialized */
+#define CF_LOADAV 0x2 /* display w/ load average */
+
+#define TCP 0x1
+#define UDP 0x2
+
+#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+#define KREAD(addr, buf, len) kvm_ckread((addr), (buf), (len))
+#define NVAL(indx) namelist[(indx)].n_value
+#define NPTR(indx) (void *)NVAL((indx))
+#define NREAD(indx, buf, len) kvm_ckread(NPTR((indx)), (buf), (len))
diff --git a/usr.bin/systat/tcp.c b/usr.bin/systat/tcp.c
new file mode 100644
index 000000000000..40311d6face2
--- /dev/null
+++ b/usr.bin/systat/tcp.c
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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
+/* From: */
+static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+static const char rcsid[] =
+ "Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+
+static struct tcpstat curstat, initstat, oldstat;
+
+/*-
+--0 1 2 3 4 5 6 7
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+01 TCP Connections TCP Packets
+02999999999 connections initiated 999999999 total packets sent
+03999999999 connections accepted 999999999 - data
+04999999999 connections established 999999999 - data (retransmit)
+05999999999 connections dropped 999999999 - ack-only
+06999999999 - in embryonic state 999999999 - window probes
+07999999999 - on retransmit timeout 999999999 - window updates
+08999999999 - by keepalive 999999999 - urgent data only
+09999999999 - from listen queue 999999999 - control
+10 999999999 - resends by PMTU discovery
+11 TCP Timers 999999999 total packets received
+12999999999 potential rtt updates 999999999 - in sequence
+13999999999 - successful 999999999 - completely duplicate
+14999999999 delayed acks sent 999999999 - with some duplicate data
+15999999999 retransmit timeouts 999999999 - out-of-order
+16999999999 persist timeouts 999999999 - duplicate acks
+17999999999 keepalive probes 999999999 - acks
+18999999999 - timeouts 999999999 - window probes
+19 999999999 - window updates
+20 999999999 - bad checksum
+--0123456789012345678901234567890123456789012345678901234567890123456789012345
+--0 1 2 3 4 5 6 7
+*/
+
+WINDOW *
+opentcp(void)
+{
+
+ return (stdscr);
+}
+
+void
+closetcp(w)
+ WINDOW *w;
+{
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+}
+
+void
+labeltcp(void)
+{
+ wmove(wnd, 0, 0); wclrtoeol(wnd);
+#define L(row, str) mvwprintw(wnd, row, 10, str)
+#define R(row, str) mvwprintw(wnd, row, 45, str);
+ L(1, "TCP Connections"); R(1, "TCP Packets");
+ L(2, "connections initiated"); R(2, "total packets sent");
+ L(3, "connections accepted"); R(3, "- data");
+ L(4, "connections established"); R(4, "- data (retransmit)");
+ L(5, "connections dropped"); R(5, "- ack-only");
+ L(6, "- in embryonic state"); R(6, "- window probes");
+ L(7, "- on retransmit timeout"); R(7, "- window updates");
+ L(8, "- by keepalive"); R(8, "- urgent data only");
+ L(9, "- from listen queue"); R(9, "- control");
+ R(10, "- resends by PMTU discovery");
+ L(11, "TCP Timers"); R(11, "total packets received");
+ L(12, "potential rtt updates"); R(12, "- in sequence");
+ L(13, "- successful"); R(13, "- completely duplicate");
+ L(14, "delayed acks sent"); R(14, "- with some duplicate data");
+ L(15, "retransmit timeouts"); R(15, "- out-of-order");
+ L(16, "persist timeouts"); R(16, "- duplicate acks");
+ L(17, "keepalive probes"); R(17, "- acks");
+ L(18, "- timeouts"); R(18, "- window probes");
+ R(19, "- window updates");
+ R(20, "- bad checksum");
+#undef L
+#undef R
+}
+
+static void
+domode(struct tcpstat *ret)
+{
+ const struct tcpstat *sub;
+ int divisor = 1;
+
+ switch(currentmode) {
+ case display_RATE:
+ sub = &oldstat;
+ divisor = naptime;
+ break;
+ case display_DELTA:
+ sub = &oldstat;
+ break;
+ case display_SINCE:
+ sub = &initstat;
+ break;
+ default:
+ *ret = curstat;
+ return;
+ }
+#define DO(stat) ret->stat = (curstat.stat - sub->stat) / divisor
+ DO(tcps_connattempt);
+ DO(tcps_accepts);
+ DO(tcps_connects);
+ DO(tcps_drops);
+ DO(tcps_conndrops);
+ DO(tcps_closed);
+ DO(tcps_segstimed);
+ DO(tcps_rttupdated);
+ DO(tcps_delack);
+ DO(tcps_timeoutdrop);
+ DO(tcps_rexmttimeo);
+ DO(tcps_persisttimeo);
+ DO(tcps_keeptimeo);
+ DO(tcps_keepprobe);
+ DO(tcps_keepdrops);
+
+ DO(tcps_sndtotal);
+ DO(tcps_sndpack);
+ DO(tcps_sndbyte);
+ DO(tcps_sndrexmitpack);
+ DO(tcps_sndrexmitbyte);
+ DO(tcps_sndacks);
+ DO(tcps_sndprobe);
+ DO(tcps_sndurg);
+ DO(tcps_sndwinup);
+ DO(tcps_sndctrl);
+
+ DO(tcps_rcvtotal);
+ DO(tcps_rcvpack);
+ DO(tcps_rcvbyte);
+ DO(tcps_rcvbadsum);
+ DO(tcps_rcvbadoff);
+ DO(tcps_rcvshort);
+ DO(tcps_rcvduppack);
+ DO(tcps_rcvdupbyte);
+ DO(tcps_rcvpartduppack);
+ DO(tcps_rcvpartdupbyte);
+ DO(tcps_rcvoopack);
+ DO(tcps_rcvoobyte);
+ DO(tcps_rcvpackafterwin);
+ DO(tcps_rcvbyteafterwin);
+ DO(tcps_rcvafterclose);
+ DO(tcps_rcvwinprobe);
+ DO(tcps_rcvdupack);
+ DO(tcps_rcvacktoomuch);
+ DO(tcps_rcvackpack);
+ DO(tcps_rcvackbyte);
+ DO(tcps_rcvwinupd);
+ DO(tcps_pawsdrop);
+ DO(tcps_predack);
+ DO(tcps_preddat);
+ DO(tcps_pcbcachemiss);
+ DO(tcps_cachedrtt);
+ DO(tcps_cachedrttvar);
+ DO(tcps_cachedssthresh);
+ DO(tcps_usedrtt);
+ DO(tcps_usedrttvar);
+ DO(tcps_usedssthresh);
+ DO(tcps_persistdrop);
+ DO(tcps_badsyn);
+ DO(tcps_mturesent);
+ DO(tcps_listendrop);
+#undef DO
+}
+
+void
+showtcp(void)
+{
+ struct tcpstat stats;
+
+ memset(&stats, 0, sizeof stats);
+ domode(&stats);
+
+#define DO(stat, row, col) \
+ mvwprintw(wnd, row, col, "%9lu", stats.stat)
+#define L(row, stat) DO(stat, row, 0)
+#define R(row, stat) DO(stat, row, 35)
+ L(2, tcps_connattempt); R(2, tcps_sndtotal);
+ L(3, tcps_accepts); R(3, tcps_sndpack);
+ L(4, tcps_connects); R(4, tcps_sndrexmitpack);
+ L(5, tcps_drops); R(5, tcps_sndacks);
+ L(6, tcps_conndrops); R(6, tcps_sndprobe);
+ L(7, tcps_timeoutdrop); R(7, tcps_sndwinup);
+ L(8, tcps_keepdrops); R(8, tcps_sndurg);
+ L(9, tcps_listendrop); R(9, tcps_sndctrl);
+ R(10, tcps_mturesent);
+ R(11, tcps_rcvtotal);
+ L(12, tcps_segstimed); R(12, tcps_rcvpack);
+ L(13, tcps_rttupdated); R(13, tcps_rcvduppack);
+ L(14, tcps_delack); R(14, tcps_rcvpartduppack);
+ L(15, tcps_rexmttimeo); R(15, tcps_rcvoopack);
+ L(16, tcps_persisttimeo); R(16, tcps_rcvdupack);
+ L(17, tcps_keepprobe); R(17, tcps_rcvackpack);
+ L(18, tcps_keeptimeo); R(18, tcps_rcvwinprobe);
+ R(19, tcps_rcvwinupd);
+ R(20, tcps_rcvbadsum);
+#undef DO
+#undef L
+#undef R
+}
+
+int
+inittcp(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_TCP;
+ name[3] = TCPCTL_STATS;
+
+ len = 0;
+ if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
+ error("sysctl getting tcpstat size failed");
+ return 0;
+ }
+ if (len > sizeof curstat) {
+ error("tcpstat structure has grown--recompile systat!");
+ return 0;
+ }
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting tcpstat failed");
+ return 0;
+ }
+ oldstat = initstat;
+ return 1;
+}
+
+void
+resettcp(void)
+{
+ size_t len;
+ int name[4];
+
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_TCP;
+ name[3] = TCPCTL_STATS;
+
+ len = sizeof initstat;
+ if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
+ error("sysctl getting tcpstat failed");
+ }
+ oldstat = initstat;
+}
+
+void
+fetchtcp(void)
+{
+ int name[4];
+ size_t len;
+
+ oldstat = curstat;
+ name[0] = CTL_NET;
+ name[1] = PF_INET;
+ name[2] = IPPROTO_TCP;
+ name[3] = TCPCTL_STATS;
+ len = sizeof curstat;
+
+ if (sysctl(name, 4, &curstat, &len, 0, 0) < 0)
+ return;
+}
+
diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c
new file mode 100644
index 000000000000..a4a9269edb3f
--- /dev/null
+++ b/usr.bin/systat/vmstat.c
@@ -0,0 +1,877 @@
+/*-
+ * Copyright (c) 1983, 1989, 1992, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifdef lint
+static const char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
+#endif
+
+/*
+ * Cursed vmstat -- from Robert Elz.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/namei.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm_param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <nlist.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <devstat.h>
+#include "systat.h"
+#include "extern.h"
+#include "devs.h"
+
+static struct Info {
+ long time[CPUSTATES];
+ u_int v_swtch; /* context switches */
+ u_int v_trap; /* calls to trap */
+ u_int v_syscall; /* calls to syscall() */
+ u_int v_intr; /* device interrupts */
+ u_int v_soft; /* software interrupts */
+ /*
+ * Virtual memory activity.
+ */
+ u_int v_vm_faults; /* number of address memory faults */
+ u_int v_cow_faults; /* number of copy-on-writes */
+ u_int v_zfod; /* pages zero filled on demand */
+ u_int v_ozfod; /* optimized zero fill pages */
+ u_int v_swapin; /* swap pager pageins */
+ u_int v_swapout; /* swap pager pageouts */
+ u_int v_swappgsin; /* swap pager pages paged in */
+ u_int v_swappgsout; /* swap pager pages paged out */
+ u_int v_vnodein; /* vnode pager pageins */
+ u_int v_vnodeout; /* vnode pager pageouts */
+ u_int v_vnodepgsin; /* vnode_pager pages paged in */
+ u_int v_vnodepgsout; /* vnode pager pages paged out */
+ u_int v_intrans; /* intransit blocking page faults */
+ u_int v_reactivated; /* number of pages reactivated from free list */
+ u_int v_pdwakeups; /* number of times daemon has awaken from sleep */
+ u_int v_pdpages; /* number of pages analyzed by daemon */
+
+ u_int v_dfree; /* pages freed by daemon */
+ u_int v_pfree; /* pages freed by exiting processes */
+ u_int v_tfree; /* total pages freed */
+ /*
+ * Distribution of page usages.
+ */
+ u_int v_page_size; /* page size in bytes */
+ u_int v_free_count; /* number of pages free */
+ u_int v_wire_count; /* number of pages wired down */
+ u_int v_active_count; /* number of pages active */
+ u_int v_inactive_count; /* number of pages inactive */
+ u_int v_cache_count; /* number of pages on buffer cache queue */
+ struct vmtotal Total;
+ struct nchstats nchstats;
+ long nchcount;
+ long *intrcnt;
+ int bufspace;
+ int desiredvnodes;
+ long numvnodes;
+ long freevnodes;
+ int numdirtybuffers;
+} s, s1, s2, z;
+
+struct statinfo cur, last, run;
+
+#define total s.Total
+#define nchtotal s.nchstats
+#define oldnchtotal s1.nchstats
+
+static enum state { BOOT, TIME, RUN } state = TIME;
+
+static void allocinfo(struct Info *);
+static void copyinfo(struct Info *, struct Info *);
+static float cputime(int);
+static void dinfo(int, int, struct statinfo *, struct statinfo *);
+static void getinfo(struct Info *);
+static void putint(int, int, int, int);
+static void putfloat(double, int, int, int, int, int);
+static void putlongdouble(long double, int, int, int, int, int);
+static int ucount(void);
+
+static int ncpu;
+static int ut;
+static char buf[26];
+static time_t t;
+static double etime;
+static int nintr;
+static long *intrloc;
+static char **intrname;
+static int nextintsrow;
+static int extended_vm_stats;
+
+struct utmp utmp;
+
+
+WINDOW *
+openkre()
+{
+
+ ut = open(_PATH_UTMP, O_RDONLY);
+ if (ut < 0)
+ error("No utmp");
+ return (stdscr);
+}
+
+void
+closekre(w)
+ WINDOW *w;
+{
+
+ (void) close(ut);
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+}
+
+/*
+ * These constants define where the major pieces are laid out
+ */
+#define STATROW 0 /* uses 1 row and 68 cols */
+#define STATCOL 2
+#define MEMROW 2 /* uses 4 rows and 31 cols */
+#define MEMCOL 0
+#define PAGEROW 2 /* uses 4 rows and 26 cols */
+#define PAGECOL 46
+#define INTSROW 6 /* uses all rows to bottom and 17 cols */
+#define INTSCOL 61
+#define PROCSROW 7 /* uses 2 rows and 20 cols */
+#define PROCSCOL 0
+#define GENSTATROW 7 /* uses 2 rows and 30 cols */
+#define GENSTATCOL 20
+#define VMSTATROW 6 /* uses 17 rows and 12 cols */
+#define VMSTATCOL 48
+#define GRAPHROW 10 /* uses 3 rows and 51 cols */
+#define GRAPHCOL 0
+#define NAMEIROW 14 /* uses 3 rows and 38 cols */
+#define NAMEICOL 0
+#define DISKROW 18 /* uses 5 rows and 50 cols (for 9 drives) */
+#define DISKCOL 0
+
+#define DRIVESPACE 7 /* max # for space */
+
+#define MAXDRIVES DRIVESPACE /* max # to display */
+
+int
+initkre()
+{
+ char *intrnamebuf, *cp;
+ int i;
+ size_t sz;
+
+ if ((num_devices = devstat_getnumdevs(NULL)) < 0) {
+ warnx("%s", devstat_errbuf);
+ return(0);
+ }
+
+ cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ run.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ bzero(cur.dinfo, sizeof(struct devinfo));
+ bzero(last.dinfo, sizeof(struct devinfo));
+ bzero(run.dinfo, sizeof(struct devinfo));
+
+ if (dsinit(MAXDRIVES, &cur, &last, &run) != 1)
+ return(0);
+
+ if (nintr == 0) {
+ if (sysctlbyname("hw.intrcnt", NULL, &sz, NULL, 0) == -1) {
+ error("sysctl(hw.intrcnt...) failed: %s",
+ strerror(errno));
+ return (0);
+ }
+ nintr = sz / sizeof(u_long);
+ intrloc = calloc(nintr, sizeof (long));
+ intrname = calloc(nintr, sizeof (char *));
+ intrnamebuf = sysctl_dynread("hw.intrnames", NULL);
+ if (intrnamebuf == NULL || intrname == NULL ||
+ intrloc == NULL) {
+ error("Out of memory");
+ if (intrnamebuf)
+ free(intrnamebuf);
+ if (intrname)
+ free(intrname);
+ if (intrloc)
+ free(intrloc);
+ nintr = 0;
+ return(0);
+ }
+ for (cp = intrnamebuf, i = 0; i < nintr; i++) {
+ intrname[i] = cp;
+ cp += strlen(cp) + 1;
+ }
+ nextintsrow = INTSROW + 2;
+ allocinfo(&s);
+ allocinfo(&s1);
+ allocinfo(&s2);
+ allocinfo(&z);
+ }
+ getinfo(&s2);
+ copyinfo(&s2, &s1);
+ return(1);
+}
+
+void
+fetchkre()
+{
+ time_t now;
+ struct tm *tp;
+ static int d_first = -1;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+
+ time(&now);
+ tp = localtime(&now);
+ (void) strftime(buf, sizeof(buf),
+ d_first ? "%e %b %R" : "%b %e %R", tp);
+ getinfo(&s);
+}
+
+void
+labelkre()
+{
+ int i, j;
+
+ clear();
+ mvprintw(STATROW, STATCOL + 4, "users Load");
+ mvprintw(MEMROW, MEMCOL, "Mem:KB REAL VIRTUAL");
+ mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share");
+ mvprintw(MEMROW + 2, MEMCOL, "Act");
+ mvprintw(MEMROW + 3, MEMCOL, "All");
+
+ mvprintw(MEMROW + 1, MEMCOL + 41, "Free");
+
+ mvprintw(PAGEROW, PAGECOL, " VN PAGER SWAP PAGER ");
+ mvprintw(PAGEROW + 1, PAGECOL, " in out in out ");
+ mvprintw(PAGEROW + 2, PAGECOL, "count");
+ mvprintw(PAGEROW + 3, PAGECOL, "pages");
+
+ mvprintw(INTSROW, INTSCOL + 3, " Interrupts");
+ mvprintw(INTSROW + 1, INTSCOL + 9, "total");
+
+ mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "cow");
+ mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "wire");
+ mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "act");
+ mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "inact");
+ mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "cache");
+ mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "free");
+ mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "daefr");
+ mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "prcfr");
+ mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "react");
+ mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "pdwake");
+ mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "pdpgs");
+ mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "intrn");
+ mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "buf");
+ mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "dirtybuf");
+
+ mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "desiredvnodes");
+ mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "numvnodes");
+ mvprintw(VMSTATROW + 17, VMSTATCOL + 10, "freevnodes");
+
+ mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt");
+
+ mvprintw(GRAPHROW, GRAPHCOL,
+ " . %%Sys . %%Intr . %%User . %%Nice . %%Idle");
+ mvprintw(PROCSROW, PROCSCOL, "Proc:r p d s w");
+ mvprintw(GRAPHROW + 1, GRAPHCOL,
+ "| | | | | | | | | | |");
+
+ mvprintw(NAMEIROW, NAMEICOL, "Namei Name-cache Dir-cache");
+ mvprintw(NAMEIROW + 1, NAMEICOL,
+ " Calls hits %% hits %%");
+ mvprintw(DISKROW, DISKCOL, "Disks");
+ mvprintw(DISKROW + 1, DISKCOL, "KB/t");
+ mvprintw(DISKROW + 2, DISKCOL, "tps");
+ mvprintw(DISKROW + 3, DISKCOL, "MB/s");
+ mvprintw(DISKROW + 4, DISKCOL, "%% busy");
+ /*
+ * For now, we don't support a fourth disk statistic. So there's
+ * no point in providing a label for it. If someone can think of a
+ * fourth useful disk statistic, there is room to add it.
+ */
+ /* mvprintw(DISKROW + 4, DISKCOL, " msps"); */
+ j = 0;
+ for (i = 0; i < num_devices && j < MAXDRIVES; i++)
+ if (dev_select[i].selected) {
+ char tmpstr[80];
+ sprintf(tmpstr, "%s%d", dev_select[i].device_name,
+ dev_select[i].unit_number);
+ mvprintw(DISKROW, DISKCOL + 5 + 6 * j,
+ " %5.5s", tmpstr);
+ j++;
+ }
+
+ if (j <= 4) {
+ /*
+ * room for extended VM stats
+ */
+ mvprintw(VMSTATROW + 11, VMSTATCOL - 6, "zfod");
+ mvprintw(VMSTATROW + 12, VMSTATCOL - 6, "ofod");
+ mvprintw(VMSTATROW + 13, VMSTATCOL - 6, "%%slo-z");
+ mvprintw(VMSTATROW + 14, VMSTATCOL - 6, "tfree");
+ extended_vm_stats = 1;
+ } else {
+ extended_vm_stats = 0;
+ mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "zfod");
+ }
+
+ for (i = 0; i < nintr; i++) {
+ if (intrloc[i] == 0)
+ continue;
+ mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s", intrname[i]);
+ }
+}
+
+#define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;}
+#define Q(fld) {t=cur.fld[i]; cur.fld[i]-=last.fld[i]; if(state==TIME) last.fld[i]=t;}
+#define Y(fld) {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;}
+#define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \
+ if(state == TIME) s1.nchstats.fld = t;}
+#define PUTRATE(fld, l, c, w) \
+ Y(fld); \
+ putint((int)((float)s.fld/etime + 0.5), l, c, w)
+#define MAXFAIL 5
+
+static char cpuchar[CPUSTATES] = { '=' , '+', '>', '-', ' ' };
+static char cpuorder[CPUSTATES] = { CP_SYS, CP_INTR, CP_USER, CP_NICE,
+ CP_IDLE };
+
+void
+showkre()
+{
+ float f1, f2;
+ int psiz, inttotal;
+ int i, j, k, l, lc;
+ static int failcnt = 0;
+ char intrbuffer[10];
+
+ etime = 0;
+ for(i = 0; i < CPUSTATES; i++) {
+ X(time);
+ Q(cp_time);
+ etime += s.time[i];
+ }
+ if (etime < 5.0) { /* < 5 ticks - ignore this trash */
+ if (failcnt++ >= MAXFAIL) {
+ clear();
+ mvprintw(2, 10, "The alternate system clock has died!");
+ mvprintw(3, 10, "Reverting to ``pigs'' display.");
+ move(CMDLINE, 0);
+ refresh();
+ failcnt = 0;
+ sleep(5);
+ command("pigs");
+ }
+ return;
+ }
+ failcnt = 0;
+ etime /= hertz;
+ etime /= ncpu;
+ inttotal = 0;
+ for (i = 0; i < nintr; i++) {
+ if (s.intrcnt[i] == 0)
+ continue;
+ if (intrloc[i] == 0) {
+ if (nextintsrow == LINES)
+ continue;
+ intrloc[i] = nextintsrow++;
+ k = 0;
+ for (j = 0; j < (int)sizeof(intrbuffer); j++) {
+ if (strncmp(&intrname[i][j], "irq", 3) == 0)
+ j += 3;
+ intrbuffer[k++] = intrname[i][j];
+ }
+ intrbuffer[k] = '\0';
+ mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s",
+ intrbuffer);
+ }
+ X(intrcnt);
+ l = (int)((float)s.intrcnt[i]/etime + 0.5);
+ inttotal += l;
+ putint(l, intrloc[i], INTSCOL + 2, 6);
+ }
+ putint(inttotal, INTSROW + 1, INTSCOL + 2, 6);
+ Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
+ Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); Z(ncs_neghits);
+ s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
+ nchtotal.ncs_miss + nchtotal.ncs_long + nchtotal.ncs_neghits;
+ if (state == TIME)
+ s1.nchcount = s.nchcount;
+
+ psiz = 0;
+ f2 = 0.0;
+ for (lc = 0; lc < CPUSTATES; lc++) {
+ i = cpuorder[lc];
+ f1 = cputime(i);
+ f2 += f1;
+ l = (int) ((f2 + 1.0) / 2.0) - psiz;
+ if (f1 > 99.9)
+ f1 = 99.9; /* no room to display 100.0 */
+ putfloat(f1, GRAPHROW, GRAPHCOL + 10 * lc, 4, 1, 0);
+ move(GRAPHROW + 2, psiz);
+ psiz += l;
+ while (l-- > 0)
+ addch(cpuchar[lc]);
+ }
+
+ putint(ucount(), STATROW, STATCOL, 3);
+ putfloat(avenrun[0], STATROW, STATCOL + 17, 6, 2, 0);
+ putfloat(avenrun[1], STATROW, STATCOL + 23, 6, 2, 0);
+ putfloat(avenrun[2], STATROW, STATCOL + 29, 6, 2, 0);
+ mvaddstr(STATROW, STATCOL + 53, buf);
+#define pgtokb(pg) ((pg) * s.v_page_size / 1024)
+ putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 3, 8);
+ putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 11, 8);
+ putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 19, 9);
+ putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 28, 9);
+ putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 3, 8);
+ putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 11, 8);
+ putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 19, 9);
+ putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 28, 9);
+ putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 37, 8);
+ putint(total.t_rq - 1, PROCSROW + 1, PROCSCOL + 3, 3);
+ putint(total.t_pw, PROCSROW + 1, PROCSCOL + 6, 3);
+ putint(total.t_dw, PROCSROW + 1, PROCSCOL + 9, 3);
+ putint(total.t_sl, PROCSROW + 1, PROCSCOL + 12, 3);
+ putint(total.t_sw, PROCSROW + 1, PROCSCOL + 15, 3);
+ if (extended_vm_stats == 0) {
+ PUTRATE(v_zfod, VMSTATROW + 0, VMSTATCOL + 4, 5);
+ }
+ PUTRATE(v_cow_faults, VMSTATROW + 1, VMSTATCOL + 3, 6);
+ putint(pgtokb(s.v_wire_count), VMSTATROW + 2, VMSTATCOL, 9);
+ putint(pgtokb(s.v_active_count), VMSTATROW + 3, VMSTATCOL, 9);
+ putint(pgtokb(s.v_inactive_count), VMSTATROW + 4, VMSTATCOL, 9);
+ putint(pgtokb(s.v_cache_count), VMSTATROW + 5, VMSTATCOL, 9);
+ putint(pgtokb(s.v_free_count), VMSTATROW + 6, VMSTATCOL, 9);
+ PUTRATE(v_dfree, VMSTATROW + 7, VMSTATCOL, 9);
+ PUTRATE(v_pfree, VMSTATROW + 8, VMSTATCOL, 9);
+ PUTRATE(v_reactivated, VMSTATROW + 9, VMSTATCOL, 9);
+ PUTRATE(v_pdwakeups, VMSTATROW + 10, VMSTATCOL, 9);
+ PUTRATE(v_pdpages, VMSTATROW + 11, VMSTATCOL, 9);
+ PUTRATE(v_intrans, VMSTATROW + 12, VMSTATCOL, 9);
+
+ if (extended_vm_stats) {
+ PUTRATE(v_zfod, VMSTATROW + 11, VMSTATCOL - 16, 9);
+ PUTRATE(v_ozfod, VMSTATROW + 12, VMSTATCOL - 16, 9);
+ putint(
+ ((s.v_ozfod < s.v_zfod) ?
+ s.v_ozfod * 100 / s.v_zfod :
+ 0
+ ),
+ VMSTATROW + 13,
+ VMSTATCOL - 16,
+ 9
+ );
+ PUTRATE(v_tfree, VMSTATROW + 14, VMSTATCOL - 16, 9);
+ }
+
+ putint(s.bufspace/1024, VMSTATROW + 13, VMSTATCOL, 9);
+ putint(s.numdirtybuffers, VMSTATROW + 14, VMSTATCOL, 9);
+ putint(s.desiredvnodes, VMSTATROW + 15, VMSTATCOL, 9);
+ putint(s.numvnodes, VMSTATROW + 16, VMSTATCOL, 9);
+ putint(s.freevnodes, VMSTATROW + 17, VMSTATCOL, 9);
+ PUTRATE(v_vnodein, PAGEROW + 2, PAGECOL + 5, 5);
+ PUTRATE(v_vnodeout, PAGEROW + 2, PAGECOL + 10, 5);
+ PUTRATE(v_swapin, PAGEROW + 2, PAGECOL + 17, 5);
+ PUTRATE(v_swapout, PAGEROW + 2, PAGECOL + 22, 5);
+ PUTRATE(v_vnodepgsin, PAGEROW + 3, PAGECOL + 5, 5);
+ PUTRATE(v_vnodepgsout, PAGEROW + 3, PAGECOL + 10, 5);
+ PUTRATE(v_swappgsin, PAGEROW + 3, PAGECOL + 17, 5);
+ PUTRATE(v_swappgsout, PAGEROW + 3, PAGECOL + 22, 5);
+ PUTRATE(v_swtch, GENSTATROW + 1, GENSTATCOL, 5);
+ PUTRATE(v_trap, GENSTATROW + 1, GENSTATCOL + 5, 5);
+ PUTRATE(v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 5);
+ PUTRATE(v_intr, GENSTATROW + 1, GENSTATCOL + 15, 5);
+ PUTRATE(v_soft, GENSTATROW + 1, GENSTATCOL + 20, 5);
+ PUTRATE(v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 5);
+ mvprintw(DISKROW, DISKCOL + 5, " ");
+ for (i = 0, lc = 0; i < num_devices && lc < MAXDRIVES; i++)
+ if (dev_select[i].selected) {
+ char tmpstr[80];
+ sprintf(tmpstr, "%s%d", dev_select[i].device_name,
+ dev_select[i].unit_number);
+ mvprintw(DISKROW, DISKCOL + 5 + 6 * lc,
+ " %5.5s", tmpstr);
+ switch(state) {
+ case TIME:
+ dinfo(i, ++lc, &cur, &last);
+ break;
+ case RUN:
+ dinfo(i, ++lc, &cur, &run);
+ break;
+ case BOOT:
+ dinfo(i, ++lc, &cur, NULL);
+ break;
+ }
+ }
+ putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
+ putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits),
+ NAMEIROW + 2, NAMEICOL + 9, 9);
+#define nz(x) ((x) ? (x) : 1)
+ putfloat((nchtotal.ncs_goodhits+nchtotal.ncs_neghits) *
+ 100.0 / nz(s.nchcount),
+ NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1);
+ putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 23, 9);
+ putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount),
+ NAMEIROW + 2, NAMEICOL + 33, 4, 0, 1);
+#undef nz
+}
+
+int
+cmdkre(cmd, args)
+ const char *cmd, *args;
+{
+ int retval;
+
+ if (prefix(cmd, "run")) {
+ retval = 1;
+ copyinfo(&s2, &s1);
+ switch (devstat_getdevs(NULL, &run)) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1:
+ num_devices = run.dinfo->numdevs;
+ generation = run.dinfo->generation;
+ retval = dscmd("refresh", NULL, MAXDRIVES, &cur);
+ if (retval == 2)
+ labelkre();
+ break;
+ default:
+ break;
+ }
+ state = RUN;
+ return (retval);
+ }
+ if (prefix(cmd, "boot")) {
+ state = BOOT;
+ copyinfo(&z, &s1);
+ return (1);
+ }
+ if (prefix(cmd, "time")) {
+ state = TIME;
+ return (1);
+ }
+ if (prefix(cmd, "zero")) {
+ retval = 1;
+ if (state == RUN) {
+ getinfo(&s1);
+ switch (devstat_getdevs(NULL, &run)) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1:
+ num_devices = run.dinfo->numdevs;
+ generation = run.dinfo->generation;
+ retval = dscmd("refresh",NULL, MAXDRIVES, &cur);
+ if (retval == 2)
+ labelkre();
+ break;
+ default:
+ break;
+ }
+ }
+ return (retval);
+ }
+ retval = dscmd(cmd, args, MAXDRIVES, &cur);
+
+ if (retval == 2)
+ labelkre();
+
+ return(retval);
+}
+
+/* calculate number of users on the system */
+static int
+ucount()
+{
+ int nusers = 0;
+
+ if (ut < 0)
+ return (0);
+ while (read(ut, &utmp, sizeof(utmp)))
+ if (utmp.ut_name[0] != '\0')
+ nusers++;
+
+ lseek(ut, 0L, L_SET);
+ return (nusers);
+}
+
+static float
+cputime(indx)
+ int indx;
+{
+ double lt;
+ int i;
+
+ lt = 0;
+ for (i = 0; i < CPUSTATES; i++)
+ lt += s.time[i];
+ if (lt == 0.0)
+ lt = 1.0;
+ return (s.time[indx] * 100.0 / lt);
+}
+
+static void
+putint(n, l, lc, w)
+ int n, l, lc, w;
+{
+ char b[128];
+
+ move(l, lc);
+ if (n == 0) {
+ while (w-- > 0)
+ addch(' ');
+ return;
+ }
+ snprintf(b, sizeof(b), "%*d", w, n);
+ if ((int)strlen(b) > w)
+ snprintf(b, sizeof(b), "%*dk", w - 1, n / 1000);
+ if ((int)strlen(b) > w)
+ snprintf(b, sizeof(b), "%*dM", w - 1, n / 1000000);
+ addstr(b);
+}
+
+static void
+putfloat(f, l, lc, w, d, nz)
+ double f;
+ int l, lc, w, d, nz;
+{
+ char b[128];
+
+ move(l, lc);
+ if (nz && f == 0.0) {
+ while (--w >= 0)
+ addch(' ');
+ return;
+ }
+ snprintf(b, sizeof(b), "%*.*f", w, d, f);
+ if ((int)strlen(b) > w)
+ snprintf(b, sizeof(b), "%*.0f", w, f);
+ if ((int)strlen(b) > w) {
+ while (--w >= 0)
+ addch('*');
+ return;
+ }
+ addstr(b);
+}
+
+static void
+putlongdouble(f, l, lc, w, d, nz)
+ long double f;
+ int l, lc, w, d, nz;
+{
+ char b[128];
+
+ move(l, lc);
+ if (nz && f == 0.0) {
+ while (--w >= 0)
+ addch(' ');
+ return;
+ }
+ sprintf(b, "%*.*Lf", w, d, f);
+ if ((int)strlen(b) > w)
+ sprintf(b, "%*.0Lf", w, f);
+ if ((int)strlen(b) > w) {
+ while (--w >= 0)
+ addch('*');
+ return;
+ }
+ addstr(b);
+}
+
+static void
+getinfo(ls)
+ struct Info *ls;
+{
+ struct devinfo *tmp_dinfo;
+ size_t size;
+ int mib[2];
+
+ GETSYSCTL("kern.cp_time", ls->time);
+ GETSYSCTL("kern.cp_time", cur.cp_time);
+ GETSYSCTL("vm.stats.sys.v_swtch", ls->v_swtch);
+ GETSYSCTL("vm.stats.sys.v_trap", ls->v_trap);
+ GETSYSCTL("vm.stats.sys.v_syscall", ls->v_syscall);
+ GETSYSCTL("vm.stats.sys.v_intr", ls->v_intr);
+ GETSYSCTL("vm.stats.sys.v_soft", ls->v_soft);
+ GETSYSCTL("vm.stats.vm.v_vm_faults", ls->v_vm_faults);
+ GETSYSCTL("vm.stats.vm.v_cow_faults", ls->v_cow_faults);
+ GETSYSCTL("vm.stats.vm.v_zfod", ls->v_zfod);
+ GETSYSCTL("vm.stats.vm.v_ozfod", ls->v_ozfod);
+ GETSYSCTL("vm.stats.vm.v_swapin", ls->v_swapin);
+ GETSYSCTL("vm.stats.vm.v_swapout", ls->v_swapout);
+ GETSYSCTL("vm.stats.vm.v_swappgsin", ls->v_swappgsin);
+ GETSYSCTL("vm.stats.vm.v_swappgsout", ls->v_swappgsout);
+ GETSYSCTL("vm.stats.vm.v_vnodein", ls->v_vnodein);
+ GETSYSCTL("vm.stats.vm.v_vnodeout", ls->v_vnodeout);
+ GETSYSCTL("vm.stats.vm.v_vnodepgsin", ls->v_vnodepgsin);
+ GETSYSCTL("vm.stats.vm.v_vnodepgsout", ls->v_vnodepgsout);
+ GETSYSCTL("vm.stats.vm.v_intrans", ls->v_intrans);
+ GETSYSCTL("vm.stats.vm.v_reactivated", ls->v_reactivated);
+ GETSYSCTL("vm.stats.vm.v_pdwakeups", ls->v_pdwakeups);
+ GETSYSCTL("vm.stats.vm.v_pdpages", ls->v_pdpages);
+ GETSYSCTL("vm.stats.vm.v_dfree", ls->v_dfree);
+ GETSYSCTL("vm.stats.vm.v_pfree", ls->v_pfree);
+ GETSYSCTL("vm.stats.vm.v_tfree", ls->v_tfree);
+ GETSYSCTL("vm.stats.vm.v_page_size", ls->v_page_size);
+ GETSYSCTL("vm.stats.vm.v_free_count", ls->v_free_count);
+ GETSYSCTL("vm.stats.vm.v_wire_count", ls->v_wire_count);
+ GETSYSCTL("vm.stats.vm.v_active_count", ls->v_active_count);
+ GETSYSCTL("vm.stats.vm.v_inactive_count", ls->v_inactive_count);
+ GETSYSCTL("vm.stats.vm.v_cache_count", ls->v_cache_count);
+ GETSYSCTL("vfs.bufspace", ls->bufspace);
+ GETSYSCTL("kern.maxvnodes", ls->desiredvnodes);
+ GETSYSCTL("vfs.numvnodes", ls->numvnodes);
+ GETSYSCTL("vfs.freevnodes", ls->freevnodes);
+ GETSYSCTL("vfs.cache.nchstats", ls->nchstats);
+ GETSYSCTL("vfs.numdirtybuffers", ls->numdirtybuffers);
+ getsysctl("hw.intrcnt", ls->intrcnt, nintr * sizeof(u_long));
+
+ size = sizeof(ls->Total);
+ mib[0] = CTL_VM;
+ mib[1] = VM_TOTAL;
+ if (sysctl(mib, 2, &ls->Total, &size, NULL, 0) < 0) {
+ error("Can't get kernel info: %s\n", strerror(errno));
+ bzero(&ls->Total, sizeof(ls->Total));
+ }
+ size = sizeof(ncpu);
+ if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0 ||
+ size != sizeof(ncpu))
+ ncpu = 1;
+
+ tmp_dinfo = last.dinfo;
+ last.dinfo = cur.dinfo;
+ cur.dinfo = tmp_dinfo;
+
+ last.snap_time = cur.snap_time;
+ switch (devstat_getdevs(NULL, &cur)) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1:
+ num_devices = cur.dinfo->numdevs;
+ generation = cur.dinfo->generation;
+ cmdkre("refresh", NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+allocinfo(ls)
+ struct Info *ls;
+{
+
+ ls->intrcnt = (long *) calloc(nintr, sizeof(long));
+ if (ls->intrcnt == NULL)
+ errx(2, "out of memory");
+}
+
+static void
+copyinfo(from, to)
+ struct Info *from, *to;
+{
+ long *intrcnt;
+
+ /*
+ * time, wds, seek, and xfer are malloc'd so we have to
+ * save the pointers before the structure copy and then
+ * copy by hand.
+ */
+ intrcnt = to->intrcnt;
+ *to = *from;
+
+ bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int));
+}
+
+static void
+dinfo(dn, lc, now, then)
+ int dn, lc;
+ struct statinfo *now, *then;
+{
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ long double elapsed_time, device_busy;
+ int di;
+
+ di = dev_select[dn].position;
+
+ if (then != NULL) {
+ /* Calculate relative to previous sample */
+ elapsed_time = now->snap_time - then->snap_time;
+ } else {
+ /* Calculate relative to device creation */
+ elapsed_time = now->snap_time - devstat_compute_etime(
+ &now->dinfo->devices[di].creation_time, NULL);
+ }
+
+ if (devstat_compute_statistics(&now->dinfo->devices[di], then ?
+ &then->dinfo->devices[di] : NULL, elapsed_time,
+ DSM_KB_PER_TRANSFER, &kb_per_transfer,
+ DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
+ DSM_MB_PER_SECOND, &mb_per_second,
+ DSM_BUSY_PCT, &device_busy,
+ DSM_NONE) != 0)
+ errx(1, "%s", devstat_errbuf);
+
+ lc = DISKCOL + lc * 6;
+ putlongdouble(kb_per_transfer, DISKROW + 1, lc, 5, 2, 0);
+ putlongdouble(transfers_per_second, DISKROW + 2, lc, 5, 0, 0);
+ putlongdouble(mb_per_second, DISKROW + 3, lc, 5, 2, 0);
+ putlongdouble(device_busy, DISKROW + 4, lc, 5, 0, 0);
+}