diff options
Diffstat (limited to 'usr.bin/systat')
-rw-r--r-- | usr.bin/systat/Makefile | 12 | ||||
-rw-r--r-- | usr.bin/systat/cmds.c | 192 | ||||
-rw-r--r-- | usr.bin/systat/cmdtab.c | 62 | ||||
-rw-r--r-- | usr.bin/systat/disks.c | 199 | ||||
-rw-r--r-- | usr.bin/systat/extern.h | 118 | ||||
-rw-r--r-- | usr.bin/systat/fetch.c | 54 | ||||
-rw-r--r-- | usr.bin/systat/iostat.c | 389 | ||||
-rw-r--r-- | usr.bin/systat/keyboard.c | 119 | ||||
-rw-r--r-- | usr.bin/systat/main.c | 286 | ||||
-rw-r--r-- | usr.bin/systat/mbufs.c | 163 | ||||
-rw-r--r-- | usr.bin/systat/netcmds.c | 308 | ||||
-rw-r--r-- | usr.bin/systat/netstat.c | 470 | ||||
-rw-r--r-- | usr.bin/systat/pigs.c | 245 | ||||
-rw-r--r-- | usr.bin/systat/swap.c | 257 | ||||
-rw-r--r-- | usr.bin/systat/systat.1 | 423 | ||||
-rw-r--r-- | usr.bin/systat/systat.h | 60 | ||||
-rw-r--r-- | usr.bin/systat/vmstat.c | 687 |
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); +} |