summaryrefslogtreecommitdiffstats
path: root/usr.bin/systat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/systat')
-rw-r--r--usr.bin/systat/Makefile12
-rw-r--r--usr.bin/systat/cmds.c192
-rw-r--r--usr.bin/systat/cmdtab.c62
-rw-r--r--usr.bin/systat/disks.c199
-rw-r--r--usr.bin/systat/extern.h118
-rw-r--r--usr.bin/systat/fetch.c54
-rw-r--r--usr.bin/systat/iostat.c389
-rw-r--r--usr.bin/systat/keyboard.c119
-rw-r--r--usr.bin/systat/main.c286
-rw-r--r--usr.bin/systat/mbufs.c163
-rw-r--r--usr.bin/systat/netcmds.c308
-rw-r--r--usr.bin/systat/netstat.c470
-rw-r--r--usr.bin/systat/pigs.c245
-rw-r--r--usr.bin/systat/swap.c257
-rw-r--r--usr.bin/systat/systat.1423
-rw-r--r--usr.bin/systat/systat.h60
-rw-r--r--usr.bin/systat/vmstat.c687
17 files changed, 4044 insertions, 0 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
new file mode 100644
index 0000000..67e3624
--- /dev/null
+++ b/usr.bin/systat/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= systat
+CFLAGS+=-I/sys -I${.CURDIR}/../vmstat
+SRCS= cmds.c cmdtab.c disks.c fetch.c iostat.c keyboard.c vmstat.c main.c \
+ mbufs.c netcmds.c netstat.c pigs.c swap.c
+LDADD= -lcurses -ltermcap -lm -lkvm
+DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM}
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/systat/cmds.c b/usr.bin/systat/cmds.c
new file mode 100644
index 0000000..4987c2c
--- /dev/null
+++ b/usr.bin/systat/cmds.c
@@ -0,0 +1,192 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include "systat.h"
+#include "extern.h"
+
+void
+command(cmd)
+ char *cmd;
+{
+ register struct cmdtab *p;
+ register char *cp;
+ int interval, omask;
+
+ omask = sigblock(sigmask(SIGALRM));
+ for (cp = cmd; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (*cmd == '\0')
+ return;
+ for (; *cp && isspace(*cp); cp++)
+ ;
+ if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "q") == 0)
+ die(0);
+ if (strcmp(cmd, "load") == 0) {
+ load();
+ goto done;
+ }
+ if (strcmp(cmd, "stop") == 0) {
+ alarm(0);
+ mvaddstr(CMDLINE, 0, "Refresh disabled.");
+ clrtoeol();
+ goto done;
+ }
+ if (strcmp(cmd, "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(cmd);
+ if (interval <= 0 &&
+ (strcmp(cmd, "start") == 0 || strcmp(cmd, "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(cmd);
+ if (p == (struct cmdtab *)-1) {
+ error("%s: Ambiguous command.", cmd);
+ goto done;
+ }
+ if (p) {
+ if (curcmd == p)
+ goto done;
+ alarm(0);
+ (*curcmd->c_close)(wnd);
+ 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)(cmd, cp))
+ error("%s: Unknown command.", cmd);
+done:
+ sigsetmask(omask);
+}
+
+struct cmdtab *
+lookup(name)
+ register char *name;
+{
+ register char *p, *q;
+ register struct cmdtab *c, *found;
+ register int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = (struct cmdtab *) 0;
+ for (c = cmdtab; p = c->c_name; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return (c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } 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)
+ register 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 0000000..71eef34
--- /dev/null
+++ b/usr.bin/systat/cmdtab.c
@@ -0,0 +1,62 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "systat.h"
+#include "extern.h"
+
+struct cmdtab cmdtab[] = {
+ { "pigs", showpigs, fetchpigs, labelpigs,
+ initpigs, openpigs, closepigs, 0,
+ CF_LOADAV },
+ { "swap", showswap, fetchswap, labelswap,
+ initswap, openswap, closeswap, 0,
+ CF_LOADAV },
+ { "mbufs", showmbufs, fetchmbufs, labelmbufs,
+ initmbufs, openmbufs, closembufs, 0,
+ CF_LOADAV },
+ { "iostat", showiostat, fetchiostat, labeliostat,
+ initiostat, openiostat, closeiostat, cmdiostat,
+ CF_LOADAV },
+ { "vmstat", showkre, fetchkre, labelkre,
+ initkre, openkre, closekre, cmdkre,
+ 0 },
+ { "netstat", shownetstat, fetchnetstat, labelnetstat,
+ initnetstat, opennetstat, closenetstat, cmdnetstat,
+ CF_LOADAV },
+ { 0 }
+};
+struct cmdtab *curcmd = &cmdtab[0];
diff --git a/usr.bin/systat/disks.c b/usr.bin/systat/disks.c
new file mode 100644
index 0000000..f412e30
--- /dev/null
+++ b/usr.bin/systat/disks.c
@@ -0,0 +1,199 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/buf.h>
+
+#include <nlist.h>
+#include <ctype.h>
+#include <paths.h>
+#include <string.h>
+#include <stdlib.h>
+#include "systat.h"
+#include "extern.h"
+
+static void dkselect __P((char *, int, int []));
+static int read_names __P((void));
+
+static struct nlist namelist[] = {
+#define X_DK_NDRIVE 0
+ { "_dk_ndrive" },
+#define X_DK_WPMS 1
+ { "_dk_wpms" },
+#ifdef vax
+#define X_MBDINIT (X_DK_WPMS+1)
+ { "_mbdinit" },
+#define X_UBDINIT (X_DK_WPMS+2)
+ { "_ubdinit" },
+#endif
+#ifdef sun
+#define X_MBDINIT (X_DK_WPMS+1)
+ { "_mbdinit" },
+#endif
+#ifdef tahoe
+#define X_VBDINIT (X_DK_WPMS+1)
+ { "_vbdinit" },
+#endif
+#if defined(hp300) || defined(luna68k)
+#define X_HPDINIT (X_DK_WPMS+1)
+ { "_hp_dinit" },
+#endif
+#ifdef mips
+#define X_SCSI_DINIT (X_DK_WPMS+1)
+ { "_scsi_dinit" },
+#endif
+ { "" },
+};
+
+float *dk_mspw;
+int dk_ndrive, *dk_select;
+char **dr_name;
+
+#include "names.c" /* XXX */
+
+int
+dkinit()
+{
+ register int i;
+ register char *cp;
+ static int once = 0;
+ static char buf[1024];
+
+ if (once)
+ return(1);
+
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[X_DK_NDRIVE].n_value == 0) {
+ error("dk_ndrive undefined in kernel");
+ return(0);
+ }
+ NREAD(X_DK_NDRIVE, &dk_ndrive, LONG);
+ if (dk_ndrive <= 0) {
+ error("dk_ndrive=%d according to %s", dk_ndrive, _PATH_UNIX);
+ return(0);
+ }
+ dk_mspw = (float *)calloc(dk_ndrive, sizeof (float));
+ {
+ long *wpms = (long *)calloc(dk_ndrive, sizeof(long));
+ KREAD(NPTR(X_DK_WPMS), wpms, dk_ndrive * sizeof (long));
+ for (i = 0; i < dk_ndrive; i++)
+ *(dk_mspw + i) = (*(wpms + i) == 0)? 0.0:
+ (float) 1.0 / *(wpms + i);
+ free(wpms);
+ }
+ dr_name = (char **)calloc(dk_ndrive, sizeof (char *));
+ dk_select = (int *)calloc(dk_ndrive, sizeof (int));
+ for (cp = buf, i = 0; i < dk_ndrive; i++) {
+ dr_name[i] = cp;
+ sprintf(dr_name[i], "dk%d", i);
+ cp += strlen(dr_name[i]) + 1;
+ if (dk_mspw[i] != 0.0)
+ dk_select[i] = 1;
+ }
+ if (!read_names()) {
+ free(dr_name);
+ free(dk_select);
+ free(dk_mspw);
+ return(0);
+ }
+ once = 1;
+ return(1);
+}
+
+int
+dkcmd(cmd, args)
+ char *cmd, *args;
+{
+ if (prefix(cmd, "display") || prefix(cmd, "add")) {
+ dkselect(args, 1, dk_select);
+ return (1);
+ }
+ if (prefix(cmd, "ignore") || prefix(cmd, "delete")) {
+ dkselect(args, 0, dk_select);
+ return (1);
+ }
+ if (prefix(cmd, "drives")) {
+ register int i;
+
+ move(CMDLINE, 0); clrtoeol();
+ for (i = 0; i < dk_ndrive; i++)
+ if (dk_mspw[i] != 0.0)
+ printw("%s ", dr_name[i]);
+ return (1);
+ }
+ return (0);
+}
+
+static void
+dkselect(args, truefalse, selections)
+ char *args;
+ int truefalse, selections[];
+{
+ register char *cp;
+ register int i;
+ char *index();
+
+ cp = index(args, '\n');
+ if (cp)
+ *cp = '\0';
+ for (;;) {
+ for (cp = args; *cp && isspace(*cp); cp++)
+ ;
+ args = cp;
+ for (; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (cp - args == 0)
+ break;
+ for (i = 0; i < dk_ndrive; i++)
+ if (strcmp(args, dr_name[i]) == 0) {
+ if (dk_mspw[i] != 0.0)
+ selections[i] = truefalse;
+ else
+ error("%s: drive not configured",
+ dr_name[i]);
+ break;
+ }
+ if (i >= dk_ndrive)
+ error("%s: unknown drive", args);
+ args = cp;
+ }
+}
diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h
new file mode 100644
index 0000000..673278b
--- /dev/null
+++ b/usr.bin/systat/extern.h
@@ -0,0 +1,118 @@
+/*-
+ * 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
+ */
+
+#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 int naptime, col;
+extern int nhosts;
+extern int nports;
+extern int protos;
+extern int verbose;
+
+struct inpcb;
+
+int checkhost __P((struct inpcb *));
+int checkport __P((struct inpcb *));
+void closeiostat __P((WINDOW *));
+void closekre __P((WINDOW *));
+void closembufs __P((WINDOW *));
+void closenetstat __P((WINDOW *));
+void closepigs __P((WINDOW *));
+void closeswap __P((WINDOW *));
+int cmdiostat __P((char *, char *));
+int cmdkre __P((char *, char *));
+int cmdnetstat __P((char *, char *));
+struct cmdtab *lookup __P((char *));
+void command __P((char *));
+void die __P((int));
+void display __P((int));
+int dkinit __P((void));
+int dkcmd __P((char *, char *));
+void error __P((const char *fmt, ...));
+void fetchiostat __P((void));
+void fetchkre __P((void));
+void fetchmbufs __P((void));
+void fetchnetstat __P((void));
+void fetchpigs __P((void));
+void fetchswap __P((void));
+int initiostat __P((void));
+int initkre __P((void));
+int initmbufs __P((void));
+int initnetstat __P((void));
+int initpigs __P((void));
+int initswap __P((void));
+int keyboard __P((void));
+int kvm_ckread __P((void *, void *, int));
+void labeliostat __P((void));
+void labelkre __P((void));
+void labelmbufs __P((void));
+void labelnetstat __P((void));
+void labelpigs __P((void));
+void labels __P((void));
+void labelswap __P((void));
+void load __P((void));
+int netcmd __P((char *, char *));
+void nlisterr __P((struct nlist []));
+WINDOW *openiostat __P((void));
+WINDOW *openkre __P((void));
+WINDOW *openmbufs __P((void));
+WINDOW *opennetstat __P((void));
+WINDOW *openpigs __P((void));
+WINDOW *openswap __P((void));
+int prefix __P((char *, char *));
+void showiostat __P((void));
+void showkre __P((void));
+void showmbufs __P((void));
+void shownetstat __P((void));
+void showpigs __P((void));
+void showswap __P((void));
+void status __P((void));
+void suspend __P((int));
diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c
new file mode 100644
index 0000000..49b296c
--- /dev/null
+++ b/usr.bin/systat/fetch.c
@@ -0,0 +1,54 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)fetch.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.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 %x\n", a);
+ return (0);
+ }
+ else
+ return (1);
+}
diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c
new file mode 100644
index 0000000..b5412a5
--- /dev/null
+++ b/usr.bin/systat/iostat.c
@@ -0,0 +1,389 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
+#endif not lint
+
+#include <sys/param.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <nlist.h>
+#include <paths.h>
+#include "systat.h"
+#include "extern.h"
+
+static struct nlist namelist[] = {
+#define X_DK_BUSY 0
+ { "_dk_busy" },
+#define X_DK_TIME 1
+ { "_dk_time" },
+#define X_DK_XFER 2
+ { "_dk_xfer" },
+#define X_DK_WDS 3
+ { "_dk_wds" },
+#define X_DK_SEEK 4
+ { "_dk_seek" },
+#define X_CP_TIME 5
+ { "_cp_time" },
+#ifdef vax
+#define X_MBDINIT (X_CP_TIME+1)
+ { "_mbdinit" },
+#define X_UBDINIT (X_CP_TIME+2)
+ { "_ubdinit" },
+#endif
+#ifdef tahoe
+#define X_VBDINIT (X_CP_TIME+1)
+ { "_vbdinit" },
+#endif
+ { "" },
+};
+
+static struct {
+ int dk_busy;
+ long cp_time[CPUSTATES];
+ long *dk_time;
+ long *dk_wds;
+ long *dk_seek;
+ long *dk_xfer;
+} s, s1;
+
+static int linesperregion;
+static double etime;
+static int numbers = 0; /* default display bar graphs */
+static int msps = 0; /* default ms/seek shown */
+
+static int barlabels __P((int));
+static void histogram __P((double, int, double));
+static int numlabels __P((int));
+static int stats __P((int, int, int));
+static void stat1 __P((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 (namelist[X_DK_BUSY].n_type == 0) {
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[X_DK_BUSY].n_type == 0) {
+ error("Disk init information isn't in namelist");
+ return(0);
+ }
+ }
+ if (! dkinit())
+ return(0);
+ if (dk_ndrive) {
+#define allocate(e, t) \
+ s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
+ s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
+ allocate(dk_time, long);
+ allocate(dk_wds, long);
+ allocate(dk_seek, long);
+ allocate(dk_xfer, long);
+#undef allocate
+ }
+ return(1);
+}
+
+void
+fetchiostat()
+{
+ if (namelist[X_DK_BUSY].n_type == 0)
+ return;
+ NREAD(X_DK_BUSY, &s.dk_busy, LONG);
+ NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG);
+ NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG);
+ NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG);
+ NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG);
+ NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time);
+}
+
+#define INSET 10
+
+void
+labeliostat()
+{
+ int row;
+
+ if (namelist[X_DK_BUSY].n_type == 0) {
+ error("No dk_busy defined.");
+ return;
+ }
+ 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, " idle|");
+ if (numbers)
+ row = numlabels(row + 1);
+ else
+ row = barlabels(row + 1);
+}
+
+static int
+numlabels(row)
+ int row;
+{
+ int i, col, regions, ndrives;
+
+#define COLWIDTH 14
+#define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH)
+ for (ndrives = 0, i = 0; i < dk_ndrive; i++)
+ if (dk_select[i])
+ 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 = 0;
+ for (i = 0; i < dk_ndrive; i++)
+ if (dk_select[i] && dk_mspw[i] != 0.0) {
+ if (col + COLWIDTH >= wnd->maxx - INSET) {
+ col = 0, row += linesperregion + 1;
+ if (row > wnd->maxy - (linesperregion + 1))
+ break;
+ }
+ mvwaddstr(wnd, row, col + 4, dr_name[i]);
+ mvwaddstr(wnd, row + 1, col, "bps tps msps");
+ col += COLWIDTH;
+ }
+ if (col)
+ row += linesperregion + 1;
+ return (row);
+}
+
+static int
+barlabels(row)
+ int row;
+{
+ int i;
+
+ mvwaddstr(wnd, row++, INSET,
+ "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50");
+ linesperregion = 2 + msps;
+ for (i = 0; i < dk_ndrive; i++)
+ if (dk_select[i] && dk_mspw[i] != 0.0) {
+ if (row > wnd->maxy - linesperregion)
+ break;
+ mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]);
+ mvwaddstr(wnd, row++, 0, " tps|");
+ if (msps)
+ mvwaddstr(wnd, row++, 0, " msps|");
+ }
+ return (row);
+}
+
+
+void
+showiostat()
+{
+ register long t;
+ register int i, row, col;
+
+ if (namelist[X_DK_BUSY].n_type == 0)
+ return;
+ for (i = 0; i < dk_ndrive; i++) {
+#define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
+ X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
+ }
+ etime = 0;
+ for(i = 0; i < CPUSTATES; i++) {
+ X(cp_time);
+ etime += s.cp_time[i];
+ }
+ if (etime == 0.0)
+ etime = 1.0;
+ etime /= (float) hz;
+ row = 1;
+
+ /*
+ * Last CPU state not calculated yet.
+ */
+ for (i = 0; i < CPUSTATES - 1; i++)
+ stat1(row++, i);
+ if (!numbers) {
+ row += 2;
+ for (i = 0; i < dk_ndrive; i++)
+ if (dk_select[i] && dk_mspw[i] != 0.0) {
+ if (row > wnd->maxy - linesperregion)
+ break;
+ row = stats(row, INSET, i);
+ }
+ return;
+ }
+ col = 0;
+ wmove(wnd, row + linesperregion, 0);
+ wdeleteln(wnd);
+ wmove(wnd, row + 3, 0);
+ winsertln(wnd);
+ for (i = 0; i < dk_ndrive; i++)
+ if (dk_select[i] && dk_mspw[i] != 0.0) {
+ if (col + COLWIDTH >= wnd->maxx) {
+ col = 0, 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) stats(row + 3, col, i);
+ col += COLWIDTH;
+ }
+}
+
+static int
+stats(row, col, dn)
+ int row, col, dn;
+{
+ double atime, words, xtime, itime;
+
+ atime = s.dk_time[dn];
+ atime /= (float) hz;
+ words = s.dk_wds[dn]*32.0; /* number of words transferred */
+ xtime = dk_mspw[dn]*words; /* transfer time */
+ itime = atime - xtime; /* time not transferring */
+ if (xtime < 0)
+ itime += xtime, xtime = 0;
+ if (itime < 0)
+ xtime += itime, itime = 0;
+ if (numbers) {
+ mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
+ words / 512 / etime, s.dk_xfer[dn] / etime,
+ s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
+ return (row);
+ }
+ wmove(wnd, row++, col);
+ histogram(words / 512 / etime, 50, 1.0);
+ wmove(wnd, row++, col);
+ histogram(s.dk_xfer[dn] / etime, 50, 1.0);
+ if (msps) {
+ wmove(wnd, row++, col);
+ histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
+ 50, 1.0);
+ }
+ return (row);
+}
+
+static void
+stat1(row, o)
+ int row, o;
+{
+ register int i;
+ double time;
+
+ time = 0;
+ for (i = 0; i < CPUSTATES; i++)
+ time += s.cp_time[i];
+ if (time == 0.0)
+ time = 1.0;
+ wmove(wnd, row, INSET);
+#define CPUSCALE 0.5
+ histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
+}
+
+static void
+histogram(val, colwidth, scale)
+ double val;
+ int colwidth;
+ double scale;
+{
+ char buf[10];
+ register int k;
+ register int v = (int)(val * scale) + 0.5;
+
+ k = MIN(v, colwidth);
+ if (v > colwidth) {
+ sprintf(buf, "%4.1f", val);
+ k -= strlen(buf);
+ while (k--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ return;
+ }
+ while (k--)
+ waddch(wnd, 'X');
+ wclrtoeol(wnd);
+}
+
+int
+cmdiostat(cmd, args)
+ char *cmd, *args;
+{
+
+ if (prefix(cmd, "msps"))
+ msps = !msps;
+ else if (prefix(cmd, "numbers"))
+ numbers = 1;
+ else if (prefix(cmd, "bars"))
+ numbers = 0;
+ else if (!dkcmd(cmd, args))
+ return (0);
+ wclear(wnd);
+ labeliostat();
+ refresh();
+ return (1);
+}
diff --git a/usr.bin/systat/keyboard.c b/usr.bin/systat/keyboard.c
new file mode 100644
index 0000000..ae4feb5
--- /dev/null
+++ b/usr.bin/systat/keyboard.c
@@ -0,0 +1,119 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)keyboard.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#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 0000000..f9f7672
--- /dev/null
+++ b/usr.bin/systat/main.c
@@ -0,0 +1,286 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <nlist.h>
+#include <signal.h>
+#include <stdio.h>
+#include "systat.h"
+#include "extern.h"
+
+static struct nlist namelist[] = {
+#define X_FIRST 0
+#define X_HZ 0
+ { "_hz" },
+#define X_STATHZ 1
+ { "_stathz" },
+ { "" }
+};
+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 */
+int hz, stathz;
+char c;
+char *namp;
+char hostname[MAXHOSTNAMELEN];
+WINDOW *wnd;
+int CMDLINE;
+
+static WINDOW *wload; /* one line window for load average */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char errbuf[80];
+
+ argc--, argv++;
+ while (argc > 0) {
+ if (argv[0][0] == '-') {
+ struct cmdtab *p;
+
+ p = lookup(&argv[0][1]);
+ if (p == (struct cmdtab *)-1) {
+ fprintf(stderr, "%s: unknown request\n",
+ &argv[0][1]);
+ exit(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) {
+ error("%s", errbuf);
+ exit(1);
+ }
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ exit(1);
+ }
+ if (namelist[X_FIRST].n_type == 0) {
+ fprintf(stderr, "couldn't read namelist.\n");
+ 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) {
+ fprintf(stderr, "Couldn't initialize display.\n");
+ die(0);
+ }
+ wload = newwin(1, 0, 3, 20);
+ if (wload == NULL) {
+ fprintf(stderr, "Couldn't set up load average window.\n");
+ die(0);
+ }
+ gethostname(hostname, sizeof (hostname));
+ NREAD(X_HZ, &hz, LONG);
+ NREAD(X_STATHZ, &stathz, LONG);
+ (*curcmd->c_init)();
+ curcmd->c_flags |= CF_INIT;
+ labels();
+
+ dellave = 0.0;
+
+ signal(SIGALRM, display);
+ display(0);
+ noecho();
+ crmode();
+ keyboard();
+ /*NOTREACHED*/
+}
+
+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;
+{
+ register 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;
+{
+ move(CMDLINE, 0);
+ clrtoeol();
+ refresh();
+ endwin();
+ exit(0);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if __STDC__
+void
+error(const char *fmt, ...)
+#else
+void
+error(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ char buf[255];
+ int oy, ox;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ if (wnd) {
+ getyx(stdscr, oy, ox);
+ (void) vsprintf(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(namelist)
+ struct nlist namelist[];
+{
+ int i, n;
+
+ n = 0;
+ clear();
+ mvprintw(2, 10, "systat: nlist: can't find following symbols:");
+ for (i = 0;
+ namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
+ if (namelist[i].n_value == 0)
+ mvprintw(2 + ++n, 10, "%s", namelist[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 0000000..4b5ca66
--- /dev/null
+++ b/usr.bin/systat/mbufs.c
@@ -0,0 +1,163 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mbuf.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <nlist.h>
+#include <paths.h>
+#include "systat.h"
+#include "extern.h"
+
+static struct mbstat *mb;
+
+char *mtnames[] = {
+ "free",
+ "data",
+ "headers",
+ "sockets",
+ "pcbs",
+ "routes",
+ "hosts",
+ "arps",
+ "socknames",
+ "zombies",
+ "sockopts",
+ "frags",
+ "rights",
+ "ifaddrs",
+};
+
+#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()
+{
+ register int i, j, max, index;
+ char buf[10];
+
+ if (mb == 0)
+ return;
+ for (j = 0; j < wnd->maxy; j++) {
+ max = 0, index = -1;
+ for (i = 0; i < wnd->maxy; i++)
+ if (mb->m_mtypes[i] > max) {
+ max = mb->m_mtypes[i];
+ index = i;
+ }
+ if (max == 0)
+ break;
+ if (j > NNAMES)
+ mvwprintw(wnd, 1+j, 0, "%10d", index);
+ else
+ mvwprintw(wnd, 1+j, 0, "%-10.10s", mtnames[index]);
+ wmove(wnd, 1 + j, 10);
+ if (max > 60) {
+ sprintf(buf, " %d", max);
+ max = 60;
+ while (max--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ } else {
+ while (max--)
+ waddch(wnd, 'X');
+ wclrtoeol(wnd);
+ }
+ mb->m_mtypes[index] = 0;
+ }
+ wmove(wnd, 1+j, 0); wclrtobot(wnd);
+}
+
+static struct nlist namelist[] = {
+#define X_MBSTAT 0
+ { "_mbstat" },
+ { "" }
+};
+
+int
+initmbufs()
+{
+ if (namelist[X_MBSTAT].n_type == 0) {
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[X_MBSTAT].n_type == 0) {
+ error("namelist on %s failed", _PATH_UNIX);
+ return(0);
+ }
+ }
+ if (mb == 0)
+ mb = (struct mbstat *)calloc(1, sizeof (*mb));
+ return(1);
+}
+
+void
+fetchmbufs()
+{
+ if (namelist[X_MBSTAT].n_type == 0)
+ return;
+ NREAD(X_MBSTAT, mb, sizeof (*mb));
+}
diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c
new file mode 100644
index 0000000..3790c2a
--- /dev/null
+++ b/usr.bin/systat/netcmds.c
@@ -0,0 +1,308 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Common network command support routines.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.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 <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.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 __P((char *, int));
+static int selectproto __P((char *));
+static void showprotos __P((void));
+static int selectport __P((long, int));
+static void showports __P((void));
+static int selecthost __P((struct in_addr *, int));
+static void showhosts __P((void));
+
+int
+netcmd(cmd, args)
+ char *cmd, *args;
+{
+
+ if (prefix(cmd, "tcp") || prefix(cmd, "udp")) {
+ selectproto(cmd);
+ 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)
+ char *args;
+ int onoff;
+{
+ register char *cp;
+ struct servent *sp;
+ struct hostent *hp;
+ struct in_addr in;
+ char *index();
+
+ cp = index(args, '\n');
+ if (cp)
+ *cp = '\0';
+ for (;;args = cp) {
+ for (cp = args; *cp && isspace(*cp); cp++)
+ ;
+ args = cp;
+ for (; *cp && !isspace(*cp); cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+ if (cp - args == 0)
+ break;
+ sp = getservbyname(args,
+ protos == TCP ? "tcp" : protos == UDP ? "udp" : 0);
+ if (sp) {
+ selectport(sp->s_port, onoff);
+ continue;
+ }
+ hp = gethostbyname(args);
+ if (hp == 0) {
+ in.s_addr = inet_addr(args);
+ if (in.s_addr == -1) {
+ error("%s: unknown host or port", args);
+ continue;
+ }
+ } else
+ in = *(struct in_addr *)hp->h_addr;
+ selecthost(&in, onoff);
+ }
+}
+
+static int
+selectproto(proto)
+ char *proto;
+{
+ int new = protos;
+
+ if (proto == 0 || streq(proto, "all"))
+ new = TCP|UDP;
+ else if (streq(proto, "tcp"))
+ new = TCP;
+ else if (streq(proto, "udp"))
+ new = UDP;
+ return (new != protos, protos = new);
+}
+
+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 0000000..0303bf5
--- /dev/null
+++ b/usr.bin/systat/netstat.c
@@ -0,0 +1,470 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * netstat
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+
+#include <netinet/in.h>
+#include <net/route.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#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>
+#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 <stdlib.h>
+#include <string.h>
+#include <nlist.h>
+#include <paths.h>
+#include "systat.h"
+#include "extern.h"
+
+static void enter __P((struct inpcb *, struct socket *, int, char *));
+static char *inetname __P((struct in_addr));
+static void inetprint __P((struct in_addr *, int, 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 {
+ struct netinfo *ni_forw, *ni_prev;
+ 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 */
+ 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 */
+ long ni_rcvcc; /* rcv buffer character count */
+ long ni_sndcc; /* snd buffer character count */
+};
+
+static struct {
+ struct netinfo *ni_forw, *ni_prev;
+} netcb;
+
+static int aflag = 0;
+static int nflag = 0;
+static int lastrow = 1;
+static void enter(), inetprint();
+static char *inetname();
+
+void
+closenetstat(w)
+ WINDOW *w;
+{
+ register struct netinfo *p;
+
+ endhostent();
+ endnetent();
+ p = (struct netinfo *)netcb.ni_forw;
+ while (p != (struct netinfo *)&netcb) {
+ if (p->ni_line != -1)
+ lastrow--;
+ p->ni_line = -1;
+ p = p->ni_forw;
+ }
+ if (w != NULL) {
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+ }
+}
+
+static struct nlist namelist[] = {
+#define X_TCB 0
+ { "_tcb" },
+#define X_UDB 1
+ { "_udb" },
+ { "" },
+};
+
+int
+initnetstat()
+{
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[X_TCB].n_value == 0) {
+ error("No symbols in namelist");
+ return(0);
+ }
+ netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb;
+ protos = TCP|UDP;
+ return(1);
+}
+
+void
+fetchnetstat()
+{
+ register struct inpcb *prev, *next;
+ register struct netinfo *p;
+ struct inpcb inpcb;
+ struct socket sockb;
+ struct tcpcb tcpcb;
+ void *off;
+ int istcp;
+
+ if (namelist[X_TCB].n_value == 0)
+ return;
+ for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw)
+ 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, &inpcb, sizeof (struct inpcb));
+ prev = off;
+ for (; inpcb.inp_next != off; prev = next) {
+ next = inpcb.inp_next;
+ KREAD(next, &inpcb, sizeof (inpcb));
+ if (inpcb.inp_prev != prev) {
+ p = netcb.ni_forw;
+ for (; p != (struct netinfo *)&netcb; p = p->ni_forw)
+ p->ni_seen = 1;
+ error("Kernel state in transition");
+ return;
+ }
+ if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
+ continue;
+ if (nhosts && !checkhost(&inpcb))
+ continue;
+ if (nports && !checkport(&inpcb))
+ continue;
+ KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
+ if (istcp) {
+ KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
+ enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
+ } else
+ enter(&inpcb, &sockb, 0, "udp");
+ }
+ if (istcp && (protos&UDP)) {
+ istcp = 0;
+ off = NPTR(X_UDB);
+ goto again;
+ }
+}
+
+static void
+enter(inp, so, state, proto)
+ register struct inpcb *inp;
+ register struct socket *so;
+ int state;
+ char *proto;
+{
+ register 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.
+ */
+ for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
+ 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 == (struct netinfo *)&netcb) {
+ if ((p = malloc(sizeof(*p))) == NULL) {
+ error("Out of memory");
+ return;
+ }
+ p->ni_prev = (struct netinfo *)&netcb;
+ p->ni_forw = netcb.ni_forw;
+ netcb.ni_forw->ni_prev = p;
+ netcb.ni_forw = p;
+ 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 = proto;
+ p->ni_flags = NIF_LACHG|NIF_FACHG;
+ }
+ p->ni_rcvcc = so->so_rcv.sb_cc;
+ p->ni_sndcc = so->so_snd.sb_cc;
+ p->ni_state = state;
+ p->ni_seen = 1;
+}
+
+/* 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 (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()
+{
+ register 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 = netcb.ni_forw;
+ while (p != (struct netinfo *)&netcb) {
+ if (p->ni_line == -1 || p->ni_seen) {
+ p = p->ni_forw;
+ continue;
+ }
+ wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
+ q = netcb.ni_forw;
+ for (; q != (struct netinfo *)&netcb; q = q->ni_forw)
+ 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 = p->ni_forw;
+ p->ni_prev->ni_forw = p->ni_forw;
+ p->ni_forw->ni_prev = p->ni_prev;
+ free(p);
+ p = q;
+ }
+ /*
+ * Update existing connections and add new ones.
+ */
+ for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
+ 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, "%6d", p->ni_rcvcc);
+ mvwprintw(wnd, p->ni_line, SNDCC, "%6d", 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)
+ register struct in_addr *in;
+ int port;
+ char *proto;
+{
+ struct servent *sp = 0;
+ char line[80], *cp, *index();
+
+ sprintf(line, "%.*s.", 16, inetname(*in));
+ cp = index(line, '\0');
+ if (!nflag && port)
+ sp = getservbyport(port, proto);
+ if (sp || port == 0)
+ sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+ else
+ sprintf(cp, "%d", ntohs((u_short)port));
+ /* pad to full column to clear any garbage */
+ cp = index(line, '\0');
+ while (cp - line < 22)
+ *cp++ = ' ';
+ *cp = '\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)
+ strcpy(line, cp);
+ else {
+ in.s_addr = ntohl(in.s_addr);
+#define C(x) ((x) & 0xff)
+ sprintf(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)
+ char *cmd, *args;
+{
+ register struct netinfo *p;
+
+ if (prefix(cmd, "all")) {
+ aflag = !aflag;
+ goto fixup;
+ }
+ if (prefix(cmd, "numbers") || prefix(cmd, "names")) {
+ int new;
+
+ new = prefix(cmd, "numbers");
+ if (new == nflag)
+ return (1);
+ p = netcb.ni_forw;
+ for (; p != (struct netinfo *)&netcb; p = p->ni_forw) {
+ 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 0000000..4c49494
--- /dev/null
+++ b/usr.bin/systat/pigs.c
@@ -0,0 +1,245 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+
+/*
+ * Pigs display from Bill Reeves at Lucasfilm
+ */
+
+#include <sys/param.h>
+#include <sys/dkstat.h>
+#include <sys/dir.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <curses.h>
+#include <math.h>
+#include <nlist.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+#include "extern.h"
+#include "systat.h"
+
+int compar __P((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;
+ struct eproc *ep;
+ float total;
+ int factor;
+ char *uname, *pname, 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 {
+ ep = &pt[k].pt_kp->kp_eproc;
+ uname = (char *)user_from_uid(ep->e_ucred.cr_uid, 0);
+ pname = pt[k].pt_kp->kp_proc.p_comm;
+ }
+ wmove(wnd, y, 0);
+ wclrtoeol(wnd);
+ mvwaddstr(wnd, y, 0, uname);
+ sprintf(pidname, "%10.10s", pname, 0);
+ 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);
+}
+
+static struct nlist namelist[] = {
+#define X_FIRST 0
+#define X_CPTIME 0
+ { "_cp_time" },
+#define X_CCPU 1
+ { "_ccpu" },
+#define X_FSCALE 2
+ { "_fscale" },
+
+ { "" }
+};
+
+int
+initpigs()
+{
+ fixpt_t ccpu;
+
+ if (namelist[X_FIRST].n_type == 0) {
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[X_FIRST].n_type == 0) {
+ error("namelist failed");
+ return(0);
+ }
+ }
+ KREAD(NPTR(X_CPTIME), stime, sizeof (stime));
+ NREAD(X_CCPU, &ccpu, LONG);
+ NREAD(X_FSCALE, &fscale, LONG);
+ lccpu = log((double) ccpu / fscale);
+
+ return(1);
+}
+
+void
+fetchpigs()
+{
+ register int i;
+ register float time;
+ register struct proc *pp;
+ register float *pctp;
+ struct kinfo_proc *kpp;
+ long ctime[CPUSTATES];
+ double t;
+ static int lastnproc = 0;
+
+ if (namelist[X_FIRST].n_type == 0)
+ return;
+ 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];
+ pp = &kpp[i].kp_proc;
+ pctp = &pt[i].pt_pctcpu;
+ time = pp->p_swtime;
+ if (time == 0 || (pp->p_flag & P_INMEM) == 0)
+ *pctp = 0;
+ else
+ *pctp = ((double) pp->p_pctcpu /
+ fscale) / (1.0 - exp(time * lccpu));
+ }
+ /*
+ * and for the imaginary "idle" process
+ */
+ KREAD(NPTR(X_CPTIME), ctime, sizeof (ctime));
+ t = 0;
+ for (i = 0; i < CPUSTATES; i++)
+ t += ctime[i] - stime[i];
+ if (t == 0.0)
+ t = 1.0;
+ pt[nproc].pt_kp = NULL;
+ pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t;
+ for (i = 0; i < CPUSTATES; i++)
+ stime[i] = ctime[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 (((struct p_times *) a)->pt_pctcpu >
+ ((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 0000000..f587eb4
--- /dev/null
+++ b/usr.bin/systat/swap.c
@@ -0,0 +1,257 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)swap.c 8.2 (Berkeley) 2/21/94";
+#endif /* not lint */
+
+/*
+ * swapinfo - based on a program of the same name by Kevin Lahey
+ */
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/map.h>
+#include <sys/stat.h>
+
+#include <kvm.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "systat.h"
+#include "extern.h"
+
+extern char *devname __P((int, int));
+extern char *getbsize __P((int *headerlenp, long *blocksizep));
+void showspace __P((char *header, int hlen, long blocksize));
+
+kvm_t *kd;
+
+struct nlist syms[] = {
+ { "_swapmap" }, /* list of free swap areas */
+#define VM_SWAPMAP 0
+ { "_nswapmap" },/* size of the swap map */
+#define VM_NSWAPMAP 1
+ { "_swdevt" }, /* list of swap devices and sizes */
+#define VM_SWDEVT 2
+ { "_nswap" }, /* size of largest swap device */
+#define VM_NSWAP 3
+ { "_nswdev" }, /* number of swap devices */
+#define VM_NSWDEV 4
+ { "_dmmax" }, /* maximum size of a swap block */
+#define VM_DMMAX 5
+ 0
+};
+
+static int nswap, nswdev, dmmax, nswapmap;
+static struct swdevt *sw;
+static long *perdev, blocksize;
+static struct map *swapmap, *kswapmap;
+static struct mapent *mp;
+static int nfree, hlen;
+
+#define SVAR(var) __STRING(var) /* to force expansion */
+#define KGET(idx, var) \
+ KGET1(idx, &var, sizeof(var), SVAR(var))
+#define KGET1(idx, p, s, msg) \
+ KGET2(syms[idx].n_value, p, s, msg)
+#define KGET2(addr, p, s, msg) \
+ if (kvm_read(kd, addr, p, s) != s) { \
+ error("cannot read %s: %s", msg, kvm_geterr(kd)); \
+ return (0); \
+ }
+
+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);
+}
+
+initswap()
+{
+ int i;
+ char msgbuf[BUFSIZ];
+ static int once = 0;
+
+ if (once)
+ return (1);
+ if (kvm_nlist(kd, syms)) {
+ strcpy(msgbuf, "systat: swap: cannot find");
+ for (i = 0; syms[i].n_name != NULL; i++) {
+ if (syms[i].n_value == 0) {
+ strcat(msgbuf, " ");
+ strcat(msgbuf, syms[i].n_name);
+ }
+ }
+ error(msgbuf);
+ return (0);
+ }
+ KGET(VM_NSWAP, nswap);
+ KGET(VM_NSWDEV, nswdev);
+ KGET(VM_DMMAX, dmmax);
+ KGET(VM_NSWAPMAP, nswapmap);
+ KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */
+ if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
+ (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
+ (mp = malloc(nswapmap * sizeof(*mp))) == NULL) {
+ error("swap malloc");
+ return (0);
+ }
+ KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
+ once = 1;
+ return (1);
+}
+
+void
+fetchswap()
+{
+ int s, e, i;
+
+ s = nswapmap * sizeof(*mp);
+ if (kvm_read(kd, (long)kswapmap, mp, s) != s)
+ error("cannot read swapmap: %s", kvm_geterr(kd));
+
+ /* first entry in map is `struct map'; rest are mapent's */
+ swapmap = (struct map *)mp;
+ if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
+ error("panic: swap: nswapmap goof");
+
+ /*
+ * Count up swap space.
+ */
+ nfree = 0;
+ bzero(perdev, nswdev * sizeof(*perdev));
+ for (mp++; mp->m_addr != 0; mp++) {
+ s = mp->m_addr; /* start of swap region */
+ e = mp->m_addr + mp->m_size; /* end of region */
+ nfree += mp->m_size;
+
+ /*
+ * Swap space is split up among the configured disks.
+ * The first dmmax blocks of swap space some from the
+ * first disk, the next dmmax blocks from the next,
+ * and so on. The list of free space joins adjacent
+ * free blocks, ignoring device boundries. If we want
+ * to keep track of this information per device, we'll
+ * just have to extract it ourselves.
+ */
+
+ /* calculate first device on which this falls */
+ i = (s / dmmax) % nswdev;
+ while (s < e) { /* XXX this is inefficient */
+ int bound = roundup(s + 1, dmmax);
+
+ if (bound > e)
+ bound = e;
+ perdev[i] += bound - s;
+ if (++i >= nswdev)
+ i = 0;
+ s = bound;
+ }
+ }
+}
+
+void
+labelswap()
+{
+ char *header;
+ int row, i;
+
+ 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 < nswdev; i++) {
+ mvwprintw(wnd, i + 1, 0, "%-5s",
+ devname(sw[i].sw_dev, S_IFBLK));
+ }
+}
+
+void
+showswap()
+{
+ int col, row, div, i, j, avail, npfree, used, xsize, xfree;
+
+ div = blocksize / 512;
+ avail = npfree = 0;
+ for (i = 0; i < nswdev; i++) {
+ col = 5;
+ mvwprintw(wnd, i + 1, col, "%*d", hlen, sw[i].sw_nblks / div);
+ col += hlen;
+ /*
+ * Don't report statistics for partitions which have not
+ * yet been activated via swapon(8).
+ */
+ if (!sw[i].sw_freed) {
+ mvwprintw(wnd, i + 1, col + 8,
+ "0 *** not available for swapping ***");
+ continue;
+ }
+ xsize = sw[i].sw_nblks;
+ xfree = perdev[i];
+ used = xsize - xfree;
+ mvwprintw(wnd, i + 1, col, "%9d ", used / div);
+ for (j = (100 * used / xsize + 1) / 2; j > 0; j--)
+ waddch(wnd, 'X');
+ npfree++;
+ avail += xsize;
+ }
+ /*
+ * If only one partition has been set up via swapon(8), we don't
+ * need to bother with totals.
+ */
+ if (npfree > 1) {
+ used = avail - nfree;
+ mvwprintw(wnd, i + 1, 0, "%-5s%*d%9d ",
+ "Total", hlen, avail / div, used / div);
+ for (j = (100 * used / avail + 1) / 2; j > 0; j--)
+ waddch(wnd, 'X');
+ }
+}
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
new file mode 100644
index 0000000..3b9a5d9
--- /dev/null
+++ b/usr.bin/systat/systat.1
@@ -0,0 +1,423 @@
+.\" 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
+.\"
+.Dd December 30, 1993
+.Dt SYSTAT 1
+.Os BSD 4.3
+.Sh NAME
+.Nm systat
+.Nd display system statistics on a crt
+.Sh SYNOPSIS
+.Nm systat
+.Op Fl display
+.Op Ar refresh-interval
+.Sh DESCRIPTION
+.Nm Systat
+displays various system statistics in a screen oriented fashion
+using the curses screen display library,
+.Xr curses 3 .
+.Pp
+While
+.Nm systat
+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 systat
+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 1 ) ,
+virtual memory statistics (a la
+.Xr vmstat 1 ) ,
+network ``mbuf'' utilization, 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 pigs ,
+.Ic iostat ,
+.Ic swap ,
+.Ic mbufs ,
+.Ic vmstat
+or
+.Ic netstat .
+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 systat .
+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 \&^Z
+Stop
+.Nm systat .
+.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 systat .
+(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 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''), and idle (``idle''). Statistics
+on disk throughput show, for each drive, kilobytes of data transferred,
+number of disk transactions performed, and average seek time
+(in milliseconds). 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 msps
+Toggle the display of average seek time (the default is to
+not display seek times).
+.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 the disk usage display.
+It reports the number of seeks, transfers, and number
+of kilobyte blocks transferred per second averaged over the
+refresh period of the display (by default, five seconds).
+For some disks it also reports the average milliseconds per seek.
+Note that the system only keeps statistics on at most four disks.
+.Pp
+Below the disk 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').
+Below the queue length listing is a numerical listing and
+a bar graph showing the amount of
+system (shown as `='), user (shown as `>'),
+nice (shown as `-'), and idle time (shown as ` ').
+.Pp
+At the bottom left 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
+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 line listing the average number of
+total reclaims ('Rec'),
+intransit blocking page faults (`It'),
+swap text pages found in free list (`F/S'),
+file system text pages found in free list (`F/F'),
+reclaims from free list
+pages freed by the clock daemon (`Fre'),
+and sequential process pages freed (`SFr')
+per second over the refresh interval.
+.Pp
+Below this line are statistics on the average number of
+zero filled pages (`zf') and demand filled text pages (`xf')
+per second over the refresh period.
+The first row indicates the number of requests that were
+resolved, the second row shows the number that were set up,
+and the last row shows the percentage of setup requests that were
+actually used.
+Note that this percentage is usually less than 100%,
+however it may exceed 100% if a large number of requests
+are actually used long after they were set up during a
+period when no new pages are being set up.
+Thus this figure is most interesting when observed over
+a long time period, such as from boot time
+(see below on getting such a display).
+.Pp
+Below the page fill statistics is a column that
+lists the average number of context switches (`Csw'),
+traps (`Trp'; includes page faults), system calls (`Sys'), interrupts (`Int'),
+characters output to DZ ports using
+.No pseudo Ns -DMA
+(`Pdm'),
+network software interrupts (`Sof'),
+page faults (`Flt'), pages scanned by the page daemon (`Scn'),
+and revolutions of the page daemon's hand (`Rev')
+per second over the refresh interval.
+.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 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
+.Ar netstat 1 ) .
+.It Cm numbers
+Display network addresses numerically.
+.It Cm names
+Display network addresses symbolically.
+.It Ar protocol
+Display only network connections using the indicated protocol
+(currently either ``tcp'' or ``udp'').
+.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
+.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 Tx -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.
+.El
+.Sh FILES
+.Bl -tag -width /etc/networks -compact
+.It Pa /vmunix
+For the namelist.
+.It Pa /dev/kmem
+For information in main memory.
+.It Pa /dev/drum
+For information about swapped out processes.
+.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 systat
+program appeared in
+.Bx 4.3 .
+.Sh BUGS
+Takes 2-10 percent of the cpu.
+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 0000000..72f65ff
--- /dev/null
+++ b/usr.bin/systat/systat.h
@@ -0,0 +1,60 @@
+/*-
+ * 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.
+ *
+ * @(#)systat.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <curses.h>
+
+struct cmdtab {
+ char *c_name; /* command name */
+ void (*c_refresh)(); /* display refresh */
+ void (*c_fetch)(); /* sets up data structures */
+ void (*c_label)(); /* label display */
+ int (*c_init)(); /* initialize namelist, etc. */
+ WINDOW *(*c_open)(); /* open display */
+ void (*c_close)(); /* close display */
+ int (*c_cmd)(); /* display command interpreter */
+ char c_flags; /* see below */
+};
+
+#define CF_INIT 0x1 /* been initialized */
+#define CF_LOADAV 0x2 /* display w/ load average */
+
+#define TCP 0x1
+#define UDP 0x2
+
+#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))
+#define LONG (sizeof (long))
diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c
new file mode 100644
index 0000000..3558c50
--- /dev/null
+++ b/usr.bin/systat/vmstat.c
@@ -0,0 +1,687 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
+#endif /* not lint */
+
+/*
+ * Cursed vmstat -- from Robert Elz.
+ */
+
+#include <sys/param.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+
+#include <signal.h>
+#include <nlist.h>
+#include <ctype.h>
+#include <utmp.h>
+#include <paths.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "systat.h"
+#include "extern.h"
+
+static struct Info {
+ long time[CPUSTATES];
+ struct vmmeter Cnt;
+ struct vmtotal Total;
+ long *dk_time;
+ long *dk_wds;
+ long *dk_seek;
+ long *dk_xfer;
+ int dk_busy;
+ struct nchstats nchstats;
+ long nchcount;
+ long *intrcnt;
+} s, s1, s2, z;
+
+#define cnt s.Cnt
+#define oldcnt s1.Cnt
+#define total s.Total
+#define nchtotal s.nchstats
+#define oldnchtotal s1.nchstats
+
+static enum state { BOOT, TIME, RUN } state = TIME;
+
+static void allocinfo __P((struct Info *));
+static void copyinfo __P((struct Info *, struct Info *));
+static float cputime __P((int));
+static void dinfo __P((int, int));
+static void getinfo __P((struct Info *, enum state));
+static void putint __P((int, int, int, int));
+static void putfloat __P((double, int, int, int, int, int));
+static int ucount __P((void));
+
+static int ut;
+static char buf[26];
+static time_t t;
+static double etime;
+static float hertz;
+static int nintr;
+static long *intrloc;
+static char **intrname;
+static int nextintsrow;
+
+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);
+}
+
+
+static struct nlist namelist[] = {
+#define X_CPTIME 0
+ { "_cp_time" },
+#define X_CNT 1
+ { "_cnt" },
+#define X_TOTAL 2
+ { "_total" },
+#define X_DK_BUSY 3
+ { "_dk_busy" },
+#define X_DK_TIME 4
+ { "_dk_time" },
+#define X_DK_XFER 5
+ { "_dk_xfer" },
+#define X_DK_WDS 6
+ { "_dk_wds" },
+#define X_DK_SEEK 7
+ { "_dk_seek" },
+#define X_NCHSTATS 8
+ { "_nchstats" },
+#define X_INTRNAMES 9
+ { "_intrnames" },
+#define X_EINTRNAMES 10
+ { "_eintrnames" },
+#define X_INTRCNT 11
+ { "_intrcnt" },
+#define X_EINTRCNT 12
+ { "_eintrcnt" },
+ { "" },
+};
+
+/*
+ * 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 36
+#define INTSROW 2 /* uses all rows to bottom and 17 cols */
+#define INTSCOL 63
+#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 7 /* 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 9 /* max # for space */
+
+#if DK_NDRIVE > DRIVESPACE
+#define MAXDRIVES DRIVESPACE /* max # to display */
+#else
+#define MAXDRIVES DK_NDRIVE /* max # to display */
+#endif
+
+int
+initkre()
+{
+ char *intrnamebuf, *cp;
+ int i;
+ static int once = 0;
+
+ if (namelist[0].n_type == 0) {
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ return(0);
+ }
+ if (namelist[0].n_type == 0) {
+ error("No namelist");
+ return(0);
+ }
+ }
+ hertz = stathz ? stathz : hz;
+ if (! dkinit())
+ return(0);
+ if (dk_ndrive && !once) {
+#define allocate(e, t) \
+ s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
+ s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
+ s2./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
+ z./**/e = (t *)calloc(dk_ndrive, sizeof (t));
+ allocate(dk_time, long);
+ allocate(dk_wds, long);
+ allocate(dk_seek, long);
+ allocate(dk_xfer, long);
+ once = 1;
+#undef allocate
+ }
+ if (nintr == 0) {
+ nintr = (namelist[X_EINTRCNT].n_value -
+ namelist[X_INTRCNT].n_value) / sizeof (long);
+ intrloc = calloc(nintr, sizeof (long));
+ intrname = calloc(nintr, sizeof (long));
+ intrnamebuf = malloc(namelist[X_EINTRNAMES].n_value -
+ namelist[X_INTRNAMES].n_value);
+ if (intrnamebuf == 0 || intrname == 0 || intrloc == 0) {
+ error("Out of memory\n");
+ if (intrnamebuf)
+ free(intrnamebuf);
+ if (intrname)
+ free(intrname);
+ if (intrloc)
+ free(intrloc);
+ nintr = 0;
+ return(0);
+ }
+ NREAD(X_INTRNAMES, intrnamebuf, NVAL(X_EINTRNAMES) -
+ NVAL(X_INTRNAMES));
+ 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, RUN);
+ copyinfo(&s2, &s1);
+ return(1);
+}
+
+void
+fetchkre()
+{
+ time_t now;
+
+ time(&now);
+ strcpy(buf, ctime(&now));
+ buf[16] = '\0';
+ getinfo(&s, state);
+}
+
+void
+labelkre()
+{
+ register 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 + 31, "Free");
+
+ mvprintw(PAGEROW, PAGECOL, " PAGING SWAPPING ");
+ 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 + 0, VMSTATCOL + 10, "cow");
+ mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "objlk");
+ mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "objht");
+ mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "zfod");
+ mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "nzfod");
+ mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "%%zfod");
+ mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "kern");
+ mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "wire");
+ mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "act");
+ mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "inact");
+ mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "free");
+ mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "daefr");
+ mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "prcfr");
+ mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "react");
+ mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "scan");
+ mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "hdrev");
+ if (LINES - 1 > VMSTATROW + 16)
+ mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "intrn");
+
+ mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt");
+
+ mvprintw(GRAPHROW, GRAPHCOL,
+ " . %% Sys . %% User . %% Nice . %% Idle");
+ mvprintw(PROCSROW, PROCSCOL, "Proc:r p d s w");
+ mvprintw(GRAPHROW + 1, GRAPHCOL,
+ "| | | | | | | | | | |");
+
+ mvprintw(NAMEIROW, NAMEICOL, "Namei Sys-cache Proc-cache");
+ mvprintw(NAMEIROW + 1, NAMEICOL,
+ " Calls hits %% hits %%");
+ mvprintw(DISKROW, DISKCOL, "Discs");
+ mvprintw(DISKROW + 1, DISKCOL, "seeks");
+ mvprintw(DISKROW + 2, DISKCOL, "xfers");
+ mvprintw(DISKROW + 3, DISKCOL, " blks");
+ mvprintw(DISKROW + 4, DISKCOL, " msps");
+ j = 0;
+ for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++)
+ if (dk_select[i]) {
+ mvprintw(DISKROW, DISKCOL + 5 + 5 * j,
+ " %3.3s", dr_name[j]);
+ j++;
+ }
+ for (i = 0; i < nintr; i++) {
+ if (intrloc[i] == 0)
+ continue;
+ mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", intrname[i]);
+ }
+}
+
+#define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.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_USER, CP_NICE, CP_IDLE };
+
+void
+showkre()
+{
+ float f1, f2;
+ int psiz, inttotal;
+ int i, l, c;
+ static int failcnt = 0;
+
+ for (i = 0; i < dk_ndrive; i++) {
+ X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
+ }
+ etime = 0;
+ for(i = 0; i < CPUSTATES; i++) {
+ X(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;
+ 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++;
+ mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s",
+ intrname[i]);
+ }
+ X(intrcnt);
+ l = (int)((float)s.intrcnt[i]/etime + 0.5);
+ inttotal += l;
+ putint(l, intrloc[i], INTSCOL, 8);
+ }
+ putint(inttotal, INTSROW + 1, INTSCOL, 8);
+ Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
+ Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes);
+ s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
+ nchtotal.ncs_miss + nchtotal.ncs_long;
+ if (state == TIME)
+ s1.nchcount = s.nchcount;
+
+ psiz = 0;
+ f2 = 0.0;
+
+ /*
+ * Last CPU state not calculated yet.
+ */
+ for (c = 0; c < CPUSTATES - 1; c++) {
+ i = cpuorder[c];
+ f1 = cputime(i);
+ f2 += f1;
+ l = (int) ((f2 + 1.0) / 2.0) - psiz;
+ if (c == 0)
+ putfloat(f1, GRAPHROW, GRAPHCOL + 1, 5, 1, 0);
+ else
+ putfloat(f1, GRAPHROW, GRAPHCOL + 12 * c,
+ 5, 1, 0);
+ move(GRAPHROW + 2, psiz);
+ psiz += l;
+ while (l-- > 0)
+ addch(cpuchar[c]);
+ }
+
+ 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) * cnt.v_page_size / 1024)
+ putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 3, 6);
+ putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 9, 6);
+ putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 15, 7);
+ putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 22, 7);
+ putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 3, 6);
+ putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 9, 6);
+ putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 15, 7);
+ putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 22, 7);
+ putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 29, 6);
+ 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);
+ PUTRATE(Cnt.v_cow_faults, VMSTATROW + 0, VMSTATCOL + 3, 6);
+ PUTRATE(Cnt.v_lookups, VMSTATROW + 1, VMSTATCOL + 3, 6);
+ PUTRATE(Cnt.v_hits, VMSTATROW + 2, VMSTATCOL + 3, 6);
+ PUTRATE(Cnt.v_zfod, VMSTATROW + 3, VMSTATCOL + 4, 5);
+ PUTRATE(Cnt.v_nzfod, VMSTATROW + 4, VMSTATCOL + 3, 6);
+ putfloat(cnt.v_nzfod == 0 ? 0.0 : (100.0 * cnt.v_zfod / cnt.v_nzfod),
+ VMSTATROW + 5, VMSTATCOL + 2, 7, 2, 1);
+ putint(pgtokb(cnt.v_kernel_pages), VMSTATROW + 6, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_wire_count), VMSTATROW + 7, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_active_count), VMSTATROW + 8, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_inactive_count), VMSTATROW + 9, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_free_count), VMSTATROW + 10, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_dfree, VMSTATROW + 11, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_pfree, VMSTATROW + 12, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_reactivated, VMSTATROW + 13, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_scan, VMSTATROW + 14, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_rev, VMSTATROW + 15, VMSTATCOL, 9);
+ if (LINES - 1 > VMSTATROW + 16)
+ PUTRATE(Cnt.v_intrans, VMSTATROW + 16, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_pageins, PAGEROW + 2, PAGECOL + 5, 5);
+ PUTRATE(Cnt.v_pageouts, PAGEROW + 2, PAGECOL + 10, 5);
+ PUTRATE(Cnt.v_swpin, PAGEROW + 2, PAGECOL + 15, 5); /* - */
+ PUTRATE(Cnt.v_swpout, PAGEROW + 2, PAGECOL + 20, 5); /* - */
+ PUTRATE(Cnt.v_pgpgin, PAGEROW + 3, PAGECOL + 5, 5); /* ? */
+ PUTRATE(Cnt.v_pgpgout, PAGEROW + 3, PAGECOL + 10, 5); /* ? */
+ PUTRATE(Cnt.v_pswpin, PAGEROW + 3, PAGECOL + 15, 5); /* - */
+ PUTRATE(Cnt.v_pswpout, PAGEROW + 3, PAGECOL + 20, 5); /* - */
+ PUTRATE(Cnt.v_swtch, GENSTATROW + 1, GENSTATCOL, 5);
+ PUTRATE(Cnt.v_trap, GENSTATROW + 1, GENSTATCOL + 5, 5);
+ PUTRATE(Cnt.v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 5);
+ PUTRATE(Cnt.v_intr, GENSTATROW + 1, GENSTATCOL + 15, 5);
+ PUTRATE(Cnt.v_soft, GENSTATROW + 1, GENSTATCOL + 20, 5);
+ PUTRATE(Cnt.v_faults, GENSTATROW + 1, GENSTATCOL + 25, 5);
+ mvprintw(DISKROW, DISKCOL + 5, " ");
+ for (i = 0, c = 0; i < dk_ndrive && c < MAXDRIVES; i++)
+ if (dk_select[i]) {
+ mvprintw(DISKROW, DISKCOL + 5 + 5 * c,
+ " %3.3s", dr_name[i]);
+ dinfo(i, ++c);
+ }
+ putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
+ putint(nchtotal.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 9, 9);
+#define nz(x) ((x) ? (x) : 1)
+ putfloat(nchtotal.ncs_goodhits * 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 + 34, 4, 0, 1);
+#undef nz
+}
+
+int
+cmdkre(cmd, args)
+ char *cmd, *args;
+{
+
+ if (prefix(cmd, "run")) {
+ copyinfo(&s2, &s1);
+ state = RUN;
+ return (1);
+ }
+ if (prefix(cmd, "boot")) {
+ state = BOOT;
+ copyinfo(&z, &s1);
+ return (1);
+ }
+ if (prefix(cmd, "time")) {
+ state = TIME;
+ return (1);
+ }
+ if (prefix(cmd, "zero")) {
+ if (state == RUN)
+ getinfo(&s1, RUN);
+ return (1);
+ }
+ return (dkcmd(cmd, args));
+}
+
+/* calculate number of users on the system */
+static int
+ucount()
+{
+ register 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 t;
+ register int i;
+
+ t = 0;
+ for (i = 0; i < CPUSTATES; i++)
+ t += s.time[i];
+ if (t == 0.0)
+ t = 1.0;
+ return (s.time[indx] * 100.0 / t);
+}
+
+static void
+putint(n, l, c, w)
+ int n, l, c, w;
+{
+ char b[128];
+
+ move(l, c);
+ if (n == 0) {
+ while (w-- > 0)
+ addch(' ');
+ return;
+ }
+ sprintf(b, "%*d", w, n);
+ if (strlen(b) > w) {
+ while (w-- > 0)
+ addch('*');
+ return;
+ }
+ addstr(b);
+}
+
+static void
+putfloat(f, l, c, w, d, nz)
+ double f;
+ int l, c, w, d, nz;
+{
+ char b[128];
+
+ move(l, c);
+ if (nz && f == 0.0) {
+ while (--w >= 0)
+ addch(' ');
+ return;
+ }
+ sprintf(b, "%*.*f", w, d, f);
+ if (strlen(b) > w) {
+ while (--w >= 0)
+ addch('*');
+ return;
+ }
+ addstr(b);
+}
+
+static void
+getinfo(s, st)
+ struct Info *s;
+ enum state st;
+{
+ int mib[2], size;
+ extern int errno;
+
+ NREAD(X_CPTIME, s->time, sizeof s->time);
+ NREAD(X_CNT, &s->Cnt, sizeof s->Cnt);
+ NREAD(X_DK_BUSY, &s->dk_busy, LONG);
+ NREAD(X_DK_TIME, s->dk_time, dk_ndrive * LONG);
+ NREAD(X_DK_XFER, s->dk_xfer, dk_ndrive * LONG);
+ NREAD(X_DK_WDS, s->dk_wds, dk_ndrive * LONG);
+ NREAD(X_DK_SEEK, s->dk_seek, dk_ndrive * LONG);
+ NREAD(X_NCHSTATS, &s->nchstats, sizeof s->nchstats);
+ NREAD(X_INTRCNT, s->intrcnt, nintr * LONG);
+ size = sizeof(s->Total);
+ mib[0] = CTL_VM;
+ mib[1] = VM_METER;
+ if (sysctl(mib, 2, &s->Total, &size, NULL, 0) < 0) {
+ error("Can't get kernel info: %s\n", strerror(errno));
+ bzero(&s->Total, sizeof(s->Total));
+ }
+}
+
+static void
+allocinfo(s)
+ struct Info *s;
+{
+
+ s->intrcnt = (long *) malloc(nintr * sizeof(long));
+ if (s->intrcnt == NULL) {
+ fprintf(stderr, "systat: out of memory\n");
+ exit(2);
+ }
+}
+
+static void
+copyinfo(from, to)
+ register struct Info *from, *to;
+{
+ long *time, *wds, *seek, *xfer;
+ 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.
+ */
+ time = to->dk_time; wds = to->dk_wds; seek = to->dk_seek;
+ xfer = to->dk_xfer; intrcnt = to->intrcnt;
+ *to = *from;
+ bcopy(from->dk_time, to->dk_time = time, dk_ndrive * sizeof (long));
+ bcopy(from->dk_wds, to->dk_wds = wds, dk_ndrive * sizeof (long));
+ bcopy(from->dk_seek, to->dk_seek = seek, dk_ndrive * sizeof (long));
+ bcopy(from->dk_xfer, to->dk_xfer = xfer, dk_ndrive * sizeof (long));
+ bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int));
+}
+
+static void
+dinfo(dn, c)
+ int dn, c;
+{
+ double words, atime, itime, xtime;
+
+ c = DISKCOL + c * 5;
+ atime = s.dk_time[dn];
+ atime /= hertz;
+ words = s.dk_wds[dn]*32.0; /* number of words transferred */
+ xtime = dk_mspw[dn]*words; /* transfer time */
+ itime = atime - xtime; /* time not transferring */
+ if (xtime < 0)
+ itime += xtime, xtime = 0;
+ if (itime < 0)
+ xtime += itime, itime = 0;
+ putint((int)((float)s.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5);
+ putint((int)((float)s.dk_xfer[dn]/etime+0.5), DISKROW + 2, c, 5);
+ putint((int)(words/etime/512.0 + 0.5), DISKROW + 3, c, 5);
+ if (s.dk_seek[dn])
+ putfloat(itime*1000.0/s.dk_seek[dn], DISKROW + 4, c, 5, 1, 1);
+ else
+ putint(0, DISKROW + 4, c, 5);
+}
OpenPOWER on IntegriCloud