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