diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index f0de9fbaeecf..ca3f7ed72ce4 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -1,21 +1,21 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ .include PROG= systat -SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \ +SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c sysput.c \ netcmds.c netstat.c pigs.c swap.c icmp.c \ mode.c ip.c sctp.c tcp.c zarc.c \ vmstat.c convtbl.c ifcmds.c ifstat.c .if ${MK_INET6_SUPPORT} != "no" SRCS+= icmp6.c ip6.c CFLAGS+= -DINET6 .endif WARNS?= 1 -LIBADD= ncursesw m devstat kvm +LIBADD= ncursesw m devstat kvm util .include diff --git a/usr.bin/systat/devs.c b/usr.bin/systat/devs.c index 3c74fb7690e3..6c0461fd531f 100644 --- a/usr.bin/systat/devs.c +++ b/usr.bin/systat/devs.c @@ -1,321 +1,431 @@ /* * Copyright (c) 1998 Kenneth D. Merry. + * 2015 Yoshihiro Ota * 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. * 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 __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93"; #endif #include #include #include #include -#include #include #include #include #include "systat.h" #include "extern.h" #include "devs.h" typedef enum { DS_MATCHTYPE_NONE, DS_MATCHTYPE_SPEC, DS_MATCHTYPE_PATTERN } last_match_type; +struct statinfo cur_dev, last_dev, run_dev; + 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) +dsinit(int maxshowdevs) { - /* * 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); + if( cur_dev.dinfo ) // init was alreay ran + return(1); + + if ((num_devices = devstat_getnumdevs(NULL)) < 0) { + warnx("%s", devstat_errbuf); + return(0); + } + + cur_dev.dinfo = calloc(1, sizeof(struct devinfo)); + last_dev.dinfo = calloc(1, sizeof(struct devinfo)); + run_dev.dinfo = calloc(1, sizeof(struct devinfo)); + 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) + if (devstat_getdevs(NULL, &cur_dev) == -1) errx(1, "%s", devstat_errbuf); - num_devices = s1->dinfo->numdevs; - generation = s1->dinfo->generation; + num_devices = cur_dev.dinfo->numdevs; + generation = cur_dev.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, + &select_generation, generation, cur_dev.dinfo->devices, num_devices, NULL, 0, NULL, 0, DS_SELECT_ADD, maxshowdevs, 0) == -1) errx(1, "%d %s", __LINE__, devstat_errbuf); return(1); } + +void +dsgetinfo(struct statinfo* dev) +{ + switch (devstat_getdevs(NULL, dev)) { + case -1: + errx(1, "%s", devstat_errbuf); + break; + case 1: + num_devices = dev->dinfo->numdevs; + generation = dev->dinfo->generation; + cmdkre("refresh", NULL); + break; + default: + break; + } +} + 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")) { 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 = strchr(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); } + + +void +dslabel(int maxdrives, int diskcol, int diskrow) +{ + int i, j; + + 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++; + } +} + +static void +dsshow2(int diskcol, int diskrow, int dn, int lc, struct statinfo *now, struct statinfo *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); +} + +static void +dsshow3(int diskcol, int diskrow, int dn, int lc, struct statinfo *now, struct statinfo *then) +{ + dsshow2(diskcol, diskrow, dn, lc, now, then); +} + +void +dsshow(int maxdrives, int diskcol, int diskrow, struct statinfo *now, struct statinfo *then) +{ + int i, lc; + + for (i = 0, lc = 0; i < num_devices && lc < maxdrives; i++) + if (dev_select[i].selected) + dsshow3(diskcol, diskrow, i, ++lc, now, then); +} diff --git a/usr.bin/systat/devs.h b/usr.bin/systat/devs.h index b25cc962bb21..cbedd844290e 100644 --- a/usr.bin/systat/devs.h +++ b/usr.bin/systat/devs.h @@ -1,32 +1,46 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1998 David E. O'Brien + * 2015 Yoshihiro Ota * 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 *); +#ifndef DEVS_H +#define DEVS_H + +#include + +int dsinit(int); +void dsgetinfo(struct statinfo *); int dscmd(const char *, const char *, int, struct statinfo *); + +void dslabel(int, int, int); +void dsshow(int, int, int, struct statinfo *, struct statinfo *); + +extern struct statinfo cur_dev, last_dev, run_dev; + +#endif diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h index 272eead74c01..c36255e531b4 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -1,177 +1,182 @@ /*- * 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. * 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 #include #include 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 col; extern int nhosts; extern int nports; extern int protos; extern int verbose; extern unsigned int delay; 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 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(void); 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 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 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 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 *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 shownetstat(void); void showpigs(void); void showswap(void); void showtcp(void); void status(void); void suspend(int); char *sysctl_dynread(const char *, size_t *); +void sysputpage(WINDOW* , int, int, int, uint64_t, int); +void sysputspaces(WINDOW* , int, int, int); +void sysputstrs(WINDOW* , int, int, int); +void sysputuint64(WINDOW* , int, int, int, uint64_t, int); +void sysputwuint64(WINDOW* , int, int, int, uint64_t, int); #define SYSTAT_CMD(name) \ void close ## name(WINDOW *); \ void fetch ## name(void); \ int init ## name(void); \ void label ## name(void); \ WINDOW *open ## name(void); \ void reset ## name(void); \ void show ## name(void) SYSTAT_CMD( zarc ); -SYSTAT_CMD ( sctp ); +SYSTAT_CMD( sctp ); diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c index d159e51c1e79..4cd9af64b43d 100644 --- a/usr.bin/systat/fetch.c +++ b/usr.bin/systat/fetch.c @@ -1,138 +1,139 @@ /*- * 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. * 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 __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)fetch.c 8.1 (Berkeley) 6/6/93"; #endif #include #include #include #include #include #include #include "systat.h" #include "extern.h" int kvm_ckread(void *a, void *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(const char *name, void *ptr, size_t len) +void +getsysctl(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); - } + error("sysctl(%s...) expected %zu, got %zu", name, len, 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(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/icmp6.c b/usr.bin/systat/icmp6.c index 2a3bbb70289c..4260179b5689 100644 --- a/usr.bin/systat/icmp6.c +++ b/usr.bin/systat/icmp6.c @@ -1,278 +1,279 @@ /*- * 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. * 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 __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 #include #include #include #include #include +#include #include #include #include #include "systat.h" #include "extern.h" #include "mode.h" static struct icmp6stat icmp6stat, initstat, oldstat; /*- --0 1 2 3 4 5 6 7 --0123456789012345678901234567890123456789012345678901234567890123456789012345 00 ICMPv6 Input ICMPv6 Output 01999999999 total messages 999999999 total messages 02999999999 with bad code 999999999 errors generated 03999999999 with bad length 999999999 suppressed - original too short 04999999999 with bad checksum 999999999 suppressed - original was ICMP 05999999999 with insufficient data 999999999 responses sent 06 07 Input Histogram Output Histogram 08999999999 echo response 999999999 echo response 09999999999 echo request 999999999 echo request 10999999999 destination unreachable 999999999 destination unreachable 11999999999 redirect 999999999 redirect 12999999999 time-to-live exceeded 999999999 time-to-line exceeded 13999999999 parameter problem 999999999 parameter problem 14999999999 neighbor solicitation 999999999 neighbor solicitation 15999999999 neighbor advertisement 999999999 neighbor advertisement 16999999999 router advertisement 999999999 router solicitation 17 18 --0123456789012345678901234567890123456789012345678901234567890123456789012345 --0 1 2 3 4 5 6 7 */ WINDOW * openicmp6(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closeicmp6(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(0, "ICMPv6 Input"); R(0, "ICMPv6 Output"); L(1, "total messages"); R(1, "total messages"); L(2, "with bad code"); R(2, "errors generated"); L(3, "with bad length"); R(3, "suppressed - original too short"); L(4, "with bad checksum"); R(4, "suppressed - original was ICMP"); L(5, "with insufficient data"); R(5, "responses sent"); L(7, "Input Histogram"); R(7, "Output Histogram"); #define B(row, str) L(row, str); R(row, str) B(8, "echo response"); B(9, "echo request"); B(10, "destination unreachable"); B(11, "redirect"); B(12, "time-to-live exceeded"); B(13, "parameter problem"); B(14, "neighbor solicitation"); B(15, "neighbor advertisement"); L(16, "router advertisement"); R(16, "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 = (delay > 1000000) ? delay / 1000000 : 1; 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; + uint64_t 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, 1, 0, "%9lu", totalin); - mvwprintw(wnd, 1, 35, "%9lu", totalout); + mvwprintw(wnd, 1, 0, "%9"PRIu64, totalin); + mvwprintw(wnd, 1, 35, "%9"PRIu64, totalout); #define DO(stat, row, col) \ - mvwprintw(wnd, row, col, "%9lu", stats.stat) + mvwprintw(wnd, row, col, "%9"PRIu64, stats.stat) DO(icp6s_badcode, 2, 0); DO(icp6s_badlen, 3, 0); DO(icp6s_checksum, 4, 0); DO(icp6s_tooshort, 5, 0); DO(icp6s_error, 2, 35); DO(icp6s_tooshort, 3, 35); DO(icp6s_canterror, 4, 35); DO(icp6s_reflect, 5, 35); #define DO2(type, row) DO(icp6s_inhist[type], row, 0); DO(icp6s_outhist[type], \ row, 35) DO2(ICMP6_ECHO_REPLY, 8); DO2(ICMP6_ECHO_REQUEST, 9); DO2(ICMP6_DST_UNREACH, 10); DO2(ND_REDIRECT, 11); DO2(ICMP6_TIME_EXCEEDED, 12); DO2(ICMP6_PARAM_PROB, 13); DO2(ND_NEIGHBOR_SOLICIT, 14); DO2(ND_NEIGHBOR_ADVERT, 15); DO(icp6s_inhist[ND_ROUTER_SOLICIT], 16, 0); DO(icp6s_outhist[ND_ROUTER_ADVERT], 16, 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 index f5091603d0e9..5336075f7472 100644 --- a/usr.bin/systat/ifcmds.c +++ b/usr.bin/systat/ifcmds.c @@ -1,79 +1,81 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2003, Trent Nelson, . * 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 #include "systat.h" #include "extern.h" #include "convtbl.h" #include #include int curscale = SC_AUTO; char *matchline = NULL; int showpps = 0; int needsort = 0; int ifcmd(const char *cmd, const char *args) { int scale; if (prefix(cmd, "scale")) { if ((scale = get_scale(args)) != -1) curscale = scale; else { move(CMDLINE, 0); clrtoeol(); addstr("what scale? "); addstr(get_helplist()); } } else if (prefix(cmd, "match")) { if (args != NULL && *args != '\0' && memcmp(args, "*", 2) != 0) { /* We got a valid match line */ if (matchline != NULL) free(matchline); needsort = 1; matchline = strdup(args); } else { /* Empty or * pattern, turn filtering off */ if (matchline != NULL) free(matchline); needsort = 1; matchline = NULL; } } else if (prefix(cmd, "pps")) showpps = !showpps; + else + return (0); return (1); } diff --git a/usr.bin/systat/ifstat.c b/usr.bin/systat/ifstat.c index 4c174c0b89e1..37ea81ba558c 100644 --- a/usr.bin/systat/ifstat.c +++ b/usr.bin/systat/ifstat.c @@ -1,498 +1,524 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2003, Trent Nelson, . * 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 #include #include #include #include +#include #include #include #include #include #include #include "systat.h" #include "extern.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]; + char display_name[IF_NAMESIZE]; + char dev_name[IFNAMSIZ]; /* copied from ifmibdata */ struct ifmibdata if_mib; struct timeval tv; struct timeval tv_lastchanged; uint64_t if_in_curtraffic; uint64_t if_out_curtraffic; uint64_t if_in_traffic_peak; uint64_t if_out_traffic_peak; uint64_t if_in_curpps; uint64_t if_out_curpps; uint64_t if_in_pps_peak; uint64_t if_out_pps_peak; u_int if_row; /* Index into ifmib sysctl */ int if_ypos; /* -1 if not being displayed */ - u_int display; + bool display; u_int match; }; extern int curscale; extern char *matchline; extern int showpps; extern int needsort; static int needclear = 0; +static bool displayall = false; -static void right_align_string(struct if_stat *); -static void getifmibdata(const int, struct ifmibdata *); +static void format_device_name(struct if_stat *); +static int getifmibdata(const int, struct ifmibdata *); static void sort_interface_list(void); static u_int getifnum(void); +static void clearifstat(void); #define IFSTAT_ERR(n, s) do { \ putchar('\014'); \ closeifstat(wnd); \ err((n), (s)); \ } while (0) #define TOPLINE 3 #define TOPLABEL \ " Interface Traffic Peak Total" #define STARTING_ROW (TOPLINE + 1) #define ROW_SPACING (3) #define IN_col2 (showpps ? ifp->if_in_curpps : ifp->if_in_curtraffic) #define OUT_col2 (showpps ? ifp->if_out_curpps : ifp->if_out_curtraffic) #define IN_col3 (showpps ? \ ifp->if_in_pps_peak : ifp->if_in_traffic_peak) #define OUT_col3 (showpps ? \ ifp->if_out_pps_peak : ifp->if_out_traffic_peak) #define IN_col4 (showpps ? \ ifp->if_mib.ifmd_data.ifi_ipackets : ifp->if_mib.ifmd_data.ifi_ibytes) #define OUT_col4 (showpps ? \ ifp->if_mib.ifmd_data.ifi_opackets : 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); \ if (showpps) { \ mvprintw(r, (c), "%10.3f %cp%s ", \ convert(d##_##c, curscale), \ *get_string(d##_##c, curscale), \ "/s"); \ } \ else { \ 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)); \ if (showpps) { \ mvprintw((r), (c), "%12.3f %cp ", \ convert(d##_##c, SC_AUTO), \ *get_string(d##_##c, SC_AUTO)); \ } \ else { \ 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, 0, "%s", p->display_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-3-1, 0, MAINWIN_ROW, 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->if_ypos < LINES - 3 && ifp->if_ypos != -1) - if (ifp->display == 0 || ifp->match == 0) { + if (!ifp->display || ifp->match == 0) { wmove(wnd, ifp->if_ypos, 0); wclrtoeol(wnd); wmove(wnd, ifp->if_ypos + 1, 0); wclrtoeol(wnd); } else { 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; + u_int n, i; n = getifnum(); if (n <= 0) return (-1); SLIST_INIT(&curlist); for (i = 0; i < n; i++) { p = (struct if_stat *)calloc(1, sizeof(struct if_stat)); if (p == NULL) IFSTAT_ERR(1, "out of memory"); - SLIST_INSERT_HEAD(&curlist, p, link); p->if_row = i+1; - getifmibdata(p->if_row, &p->if_mib); - right_align_string(p); + if (getifmibdata(p->if_row, &p->if_mib) == -1) { + free(p); + continue; + } + SLIST_INSERT_HEAD(&curlist, p, link); + format_device_name(p); p->match = 1; /* * Initially, we only display interfaces that have - * received some traffic. + * received some traffic unless display-all is on. */ - if (p->if_mib.ifmd_data.ifi_ibytes != 0) - p->display = 1; + if (displayall || p->if_mib.ifmd_data.ifi_ibytes != 0) + p->display = true; } sort_interface_list(); return (1); } void fetchifstat(void) { - struct if_stat *ifp = NULL; + struct if_stat *ifp = NULL, *temp_var; struct timeval tv, new_tv, old_tv; double elapsed = 0.0; uint64_t new_inb, new_outb, old_inb, old_outb = 0; uint64_t new_inp, new_outp, old_inp, old_outp = 0; - SLIST_FOREACH(ifp, &curlist, link) { + SLIST_FOREACH_SAFE(ifp, &curlist, link, temp_var) { /* * 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; old_inp = ifp->if_mib.ifmd_data.ifi_ipackets; old_outp = ifp->if_mib.ifmd_data.ifi_opackets; ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange; (void)gettimeofday(&new_tv, NULL); - (void)getifmibdata(ifp->if_row, &ifp->if_mib); + if (getifmibdata(ifp->if_row, &ifp->if_mib) == -1 ) { + /* if a device was removed */ + SLIST_REMOVE(&curlist, ifp, if_stat, link); + free(ifp); + needsort = 1; + clearifstat(); + } else if (strcmp(ifp->dev_name, ifp->if_mib.ifmd_name) != 0 ) { + /* a device was removed and another one was added */ + format_device_name(ifp); + /* clear to the current value for the new device */ + old_inb = ifp->if_mib.ifmd_data.ifi_ibytes; + old_outb = ifp->if_mib.ifmd_data.ifi_obytes; + old_inp = ifp->if_mib.ifmd_data.ifi_ipackets; + old_outp = ifp->if_mib.ifmd_data.ifi_opackets; + needsort = 1; + } new_inb = ifp->if_mib.ifmd_data.ifi_ibytes; new_outb = ifp->if_mib.ifmd_data.ifi_obytes; new_inp = ifp->if_mib.ifmd_data.ifi_ipackets; new_outp = ifp->if_mib.ifmd_data.ifi_opackets; /* Display interface if it's received some traffic. */ - if (new_inb > 0 && old_inb == 0) { - ifp->display = 1; + if (!ifp->display && new_inb > 0 && old_inb == 0) { + ifp->display = true; needsort = 1; } /* * 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; ifp->if_in_curpps = new_inp - old_inp; ifp->if_out_curpps = new_outp - old_outp; /* * 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; ifp->if_in_curpps /= elapsed; ifp->if_out_curpps /= 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; if (ifp->if_in_curpps > ifp->if_in_pps_peak) ifp->if_in_pps_peak = ifp->if_in_curpps; if (ifp->if_out_curpps > ifp->if_out_pps_peak) ifp->if_out_pps_peak = ifp->if_out_curpps; ifp->tv.tv_sec = new_tv.tv_sec; ifp->tv.tv_usec = new_tv.tv_usec; } if (needsort) 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. + * We save original name so that we can find a same spot is take by a + * different device. */ static void -right_align_string(struct if_stat *ifp) +format_device_name(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 = 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; + if (ifp != NULL ) { + snprintf(ifp->display_name, IF_NAMESIZE, "%*s", IF_NAMESIZE-1, + ifp->if_mib.ifmd_name); + strcpy(ifp->dev_name, ifp->if_mib.ifmd_name); + } } static int check_match(const char *ifname) { char *p = matchline, *c, t; int match = 0, mlen; if (matchline == NULL) return (0); /* Strip leading whitespaces */ while (*p == ' ') p ++; c = p; while ((mlen = strcspn(c, " ;,")) != 0) { p = c + mlen; t = *p; if (p - c > 0) { *p = '\0'; if (fnmatch(c, ifname, FNM_CASEFOLD) == 0) { *p = t; return (1); } *p = t; c = p + strspn(p, " ;,"); } else { c = p + strspn(p, " ;,"); } } return (match); } /* * 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 (matchline && !check_match(ifp->if_mib.ifmd_name)) ifp->match = 0; else ifp->match = 1; if (ifp->display && ifp->match) { ifp->if_ypos = y; y += ROW_SPACING; } else ifp->if_ypos = -1; } needsort = 0; needclear = 1; } 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 +static int getifmibdata(int row, struct ifmibdata *data) { + int ret = 0; 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) && (errno != ENOENT)) + ret = sysctl(name, 6, (void *)data, (size_t *)&datalen, (void *)NULL, + (size_t)0); + if ((ret != 0) && (errno != ENOENT)) IFSTAT_ERR(2, "sysctl error getting interface data"); + + return (ret); } int cmdifstat(const char *cmd, const char *args) { int retval = 0; retval = ifcmd(cmd, args); /* ifcmd() returns 1 on success */ if (retval == 1) { - if (needclear) { - showifstat(); - refresh(); - werase(wnd); - labelifstat(); - needclear = 0; - } + if (needclear) + clearifstat(); + } + else if (prefix(cmd, "all")) { + retval = 1; + displayall = true; } return (retval); } + +static void +clearifstat(void) +{ + + showifstat(); + refresh(); + werase(wnd); + labelifstat(); + needclear = 0; +} diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c index fa275ebbbf2a..28cc40b9c760 100644 --- a/usr.bin/systat/iostat.c +++ b/usr.bin/systat/iostat.c @@ -1,395 +1,387 @@ /* * 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. * 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 __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; #endif #include #include #include #include #include #include #include #include #include #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(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closeiostat(WINDOW *w) { if (w == NULL) return; wclear(w); wrefresh(w); delwin(w); } int initiostat(void) { - if ((num_devices = devstat_getnumdevs(NULL)) < 0) - return(0); - - cur.dinfo = calloc(1, sizeof(struct devinfo)); - last.dinfo = calloc(1, 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) + if (dsinit(7) != 1) return(0); return(1); } void fetchiostat(void) { 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)) { + len = sizeof(cur_dev.cp_time); + if (sysctlbyname("kern.cp_time", &cur_dev.cp_time, &len, NULL, 0) + || len != sizeof(cur_dev.cp_time)) { perror("kern.cp_time"); exit (1); } - tmp_dinfo = last.dinfo; - last.dinfo = cur.dinfo; - cur.dinfo = tmp_dinfo; + tmp_dinfo = last_dev.dinfo; + last_dev.dinfo = cur_dev.dinfo; + cur_dev.dinfo = tmp_dinfo; - last.snap_time = cur.snap_time; + last_dev.snap_time = cur_dev.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)) { + switch (devstat_getdevs(NULL, &cur_dev)) { 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; + num_devices = cur_dev.dinfo->numdevs; + generation = cur_dev.dinfo->generation; } #define INSET 10 void labeliostat(void) { 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(int row) { int i, _col, regions, ndrives; char tmpstr[10]; #define COLWIDTH 17 #define DRIVESPERLINE ((getmaxx(wnd) - 1 - 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 = (getmaxy(wnd) - 1 - 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 >= getmaxx(wnd) - 1 - INSET) { _col = INSET, row += linesperregion + 1; if (row > getmaxy(wnd) - 1 - (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(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 > getmaxy(wnd) - 1 - 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(void) { long t; int i, row, _col; -#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t +#define X(fld) t = cur_dev.fld[i]; cur_dev.fld[i] -= last_dev.fld[i]; last_dev.fld[i] = t etime = 0; for(i = 0; i < CPUSTATES; i++) { X(cp_time); - etime += cur.cp_time[i]; + etime += cur_dev.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 > getmaxy(wnd) - 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 >= getmaxx(wnd) - 1 - INSET) { _col = INSET, row += linesperregion + 1; if (row > getmaxy(wnd) - 1 - (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(int row, int _col, int 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; + busy_seconds = cur_dev.snap_time - last_dev.snap_time; - if (devstat_compute_statistics(&cur.dinfo->devices[di], - &last.dinfo->devices[di], busy_seconds, + if (devstat_compute_statistics(&cur_dev.dinfo->devices[di], + &last_dev.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(int row, int o) { int i; double dtime; dtime = 0.0; for (i = 0; i < CPUSTATES; i++) - dtime += cur.cp_time[i]; + dtime += cur_dev.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); + histogram(100.0 * cur_dev.cp_time[o] / dtime, 50, CPUSCALE); } static void histogram(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(const char *cmd, const char *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)) + else if (!dscmd(cmd, args, 100, &cur_dev)) return (0); wclear(wnd); labeliostat(); refresh(); return (1); } diff --git a/usr.bin/systat/ip.c b/usr.bin/systat/ip.c index 8e12a6a0b0b8..471ae2648133 100644 --- a/usr.bin/systat/ip.c +++ b/usr.bin/systat/ip.c @@ -1,339 +1,340 @@ /*- * 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. * 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 __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 #include #include #include #include #include #include #include #include #include +#include #include #include #include #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 00 IP Input IP Output 01999999999 total packets received 999999999 total packets sent 02999999999 - with bad checksums 999999999 - generated locally 03999999999 - too short for header 999999999 - output drops 04999999999 - too short for data 999999999 output fragments generated 05999999999 - with invalid hlen 999999999 - fragmentation failed 06999999999 - with invalid length 999999999 destinations unreachable 07999999999 - with invalid version 999999999 packets output via raw IP 08999999999 - jumbograms 09999999999 total fragments received UDP Statistics 10999999999 - fragments dropped 999999999 total input packets 11999999999 - fragments timed out 999999999 - too short for header 12999999999 - packets reassembled ok 999999999 - invalid checksum 13999999999 packets forwarded 999999999 - no checksum 14999999999 - unreachable dests 999999999 - invalid length 15999999999 - redirects generated 999999999 - no socket for dest port 16999999999 option errors 999999999 - no socket for broadcast 17999999999 unwanted multicasts 999999999 - socket buffer full 18999999999 delivered to upper layer 999999999 total output packets --0123456789012345678901234567890123456789012345678901234567890123456789012345 --0 1 2 3 4 5 6 7 */ WINDOW * openip(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closeip(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(0, "IP Input"); R(0, "IP Output"); L(1, "total packets received"); R(1, "total packets sent"); L(2, "- with bad checksums"); R(2, "- generated locally"); L(3, "- too short for header"); R(3, "- output drops"); L(4, "- too short for data"); R(4, "output fragments generated"); L(5, "- with invalid hlen"); R(5, "- fragmentation failed"); L(6, "- with invalid length"); R(6, "destinations unreachable"); L(7, "- with invalid version"); R(7, "packets output via raw IP"); L(8, "- jumbograms"); L(9, "total fragments received"); R(9, "UDP Statistics"); L(10, "- fragments dropped"); R(10, "total input packets"); L(11, "- fragments timed out"); R(11, "- too short for header"); L(12, "- packets reassembled ok"); R(12, "- invalid checksum"); L(13, "packets forwarded"); R(13, "- no checksum"); L(14, "- unreachable dests"); R(14, "- invalid length"); L(15, "- redirects generated"); R(15, "- no socket for dest port"); L(16, "option errors"); R(16, "- no socket for broadcast"); L(17, "unwanted multicasts"); R(17, "- socket buffer full"); L(18, "delivered to upper layer"); R(18, "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 = (delay > 1000000) ? delay / 1000000 : 1; 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; + uint64_t totalout; domode(&stats); totalout = stats.i.ips_forward + stats.i.ips_localout; #define DO(stat, row, col) \ - mvwprintw(wnd, row, col, "%9lu", stats.stat) + mvwprintw(wnd, row, col, "%9"PRIu64, stats.stat) DO(i.ips_total, 1, 0); - mvwprintw(wnd, 1, 35, "%9lu", totalout); + mvwprintw(wnd, 1, 35, "%9"PRIu64, totalout); DO(i.ips_badsum, 2, 0); DO(i.ips_localout, 2, 35); DO(i.ips_tooshort, 3, 0); DO(i.ips_odropped, 3, 35); DO(i.ips_toosmall, 4, 0); DO(i.ips_ofragments, 4, 35); DO(i.ips_badhlen, 5, 0); DO(i.ips_cantfrag, 5, 35); DO(i.ips_badlen, 6, 0); DO(i.ips_noroute, 6, 35); DO(i.ips_badvers, 7, 0); DO(i.ips_rawout, 7, 35); DO(i.ips_toolong, 8, 0); DO(i.ips_fragments, 9, 0); DO(i.ips_fragdropped, 10, 0); DO(u.udps_ipackets, 10, 35); DO(i.ips_fragtimeout, 11, 0); DO(u.udps_hdrops, 11, 35); DO(i.ips_reassembled, 12, 0); DO(u.udps_badsum, 12, 35); DO(i.ips_forward, 13, 0); DO(u.udps_nosum, 13, 35); DO(i.ips_cantforward, 14, 0); DO(u.udps_badlen, 14, 35); DO(i.ips_redirectsent, 15, 0); DO(u.udps_noport, 15, 35); DO(i.ips_badoptions, 16, 0); DO(u.udps_noportbcast, 16, 35); DO(i.ips_notmember, 17, 0); DO(u.udps_fullsock, 17, 35); DO(i.ips_delivered, 18, 0); DO(u.udps_opackets, 18, 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 index 5d2c2103cf45..f5b943801211 100644 --- a/usr.bin/systat/ip6.c +++ b/usr.bin/systat/ip6.c @@ -1,300 +1,301 @@ /*- * 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. * 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 __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 #include #include #include #include #include #include #include +#include #include #include #include #include "systat.h" #include "extern.h" #include "mode.h" static struct ip6stat curstat, initstat, oldstat; /*- --0 1 2 3 4 5 6 7 --0123456789012345678901234567890123456789012345678901234567890123456789012345 00 IPv6 Input IPv6 Output 019999999 total packets received 999999999 total packets sent 029999999 - too short for header 999999999 - generated locally 039999999 - too short for data 999999999 - output drops 049999999 - with invalid version 999999999 output fragments generated 059999999 total fragments received 999999999 - fragmentation failed 069999999 - fragments dropped 999999999 destinations unreachable 079999999 - fragments timed out 999999999 packets output via raw IP 089999999 - fragments overflown 099999999 - packets reassembled ok Input next-header histogram 109999999 packets forwarded 999999999 - destination options 119999999 - unreachable dests 999999999 - hop-by-hop options 129999999 - redirects generated 999999999 - IPv4 139999999 option errors 999999999 - TCP 149999999 unwanted multicasts 999999999 - UDP 159999999 delivered to upper layer 999999999 - IPv6 169999999 bad scope packets 999999999 - routing header 179999999 address selection failed 999999999 - fragmentation header 18 999999999 - ICMP6 19 999999999 - none --0123456789012345678901234567890123456789012345678901234567890123456789012345 --0 1 2 3 4 5 6 7 */ WINDOW * openip6(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closeip6(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(0, "IPv6 Input"); R(0, "IPv6 Output"); L(1, "total packets received"); R(1, "total packets sent"); L(2, "- too short for header"); R(2, "- generated locally"); L(3, "- too short for data"); R(3, "- output drops"); L(4, "- with invalid version"); R(4, "output fragments generated"); L(5, "total fragments received"); R(5, "- fragmentation failed"); L(6, "- fragments dropped"); R(6, "destinations unreachable"); L(7, "- fragments timed out"); R(7, "packets output via raw IP"); L(8, "- fragments overflown"); L(9, "- packets reassembled ok"); R(9, "Input next-header histogram"); L(10, "packets forwarded"); R(10, " - destination options"); L(11, "- unreachable dests"); R(11, " - hop-by-hop options"); L(12, "- redirects generated"); R(12, " - IPv4"); L(13, "option errors"); R(13, " - TCP"); L(14, "unwanted multicasts"); R(14, " - UDP"); L(15, "delivered to upper layer"); R(15, " - IPv6"); L(16, "bad scope packets"); R(16, " - routing header"); L(17, "address selection failed"); R(17, " - fragmentation header"); R(18, " - ICMP6"); 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 = (delay > 1000000) ? delay / 1000000 : 1; 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; + uint64_t totalout; domode(&stats); totalout = stats.ip6s_forward + stats.ip6s_localout; #define DO(stat, row, col) \ - mvwprintw(wnd, row, col, "%9lu", stats.stat) + mvwprintw(wnd, row, col, "%9"PRIu64, stats.stat) DO(ip6s_total, 1, 0); - mvwprintw(wnd, 1, 35, "%9lu", totalout); + mvwprintw(wnd, 1, 35, "%9"PRIu64, totalout); DO(ip6s_tooshort, 2, 0); DO(ip6s_localout, 2, 35); DO(ip6s_toosmall, 3, 0); DO(ip6s_odropped, 3, 35); DO(ip6s_badvers, 4, 0); DO(ip6s_ofragments, 4, 35); DO(ip6s_fragments, 5, 0); DO(ip6s_cantfrag, 5, 35); DO(ip6s_fragdropped, 6, 0); DO(ip6s_noroute, 6, 35); DO(ip6s_fragtimeout, 7, 0); DO(ip6s_rawout, 7, 35); DO(ip6s_fragoverflow, 8, 0); DO(ip6s_reassembled, 9, 0); DO(ip6s_forward, 10, 0); DO(ip6s_nxthist[IPPROTO_DSTOPTS], 10, 35); DO(ip6s_cantforward, 11, 0); DO(ip6s_nxthist[IPPROTO_HOPOPTS], 11, 35); DO(ip6s_redirectsent, 12, 0); DO(ip6s_nxthist[IPPROTO_IPV4], 12, 35); DO(ip6s_badoptions, 13, 0); DO(ip6s_nxthist[IPPROTO_TCP], 13, 35); DO(ip6s_notmember, 14, 0); DO(ip6s_nxthist[IPPROTO_UDP], 14, 35); DO(ip6s_delivered, 15, 0); DO(ip6s_nxthist[IPPROTO_IPV6], 15, 35); DO(ip6s_badscope, 16, 0); DO(ip6s_nxthist[IPPROTO_ROUTING], 16, 35); DO(ip6s_sources_none, 17, 0); DO(ip6s_nxthist[IPPROTO_FRAGMENT], 17, 35); DO(ip6s_nxthist[IPPROTO_ICMPV6], 18, 35); DO(ip6s_nxthist[IPPROTO_NONE], 19, 35); #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/main.c b/usr.bin/systat/main.c index 74195f606aec..983d319f464f 100644 --- a/usr.bin/systat/main.c +++ b/usr.bin/systat/main.c @@ -1,380 +1,371 @@ /*- * 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. * 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 __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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" static int dellave; kvm_t *kd; sig_t sigtstpdfl; double avenrun[3]; int col; unsigned int delay = 5000000; /* in microseconds */ 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 */ struct cmdentry { SLIST_ENTRY(cmdentry) link; char *cmd; /* Command name */ char *argv; /* Arguments vector for a command */ }; SLIST_HEAD(, cmdentry) commands; static void parse_cmd_args (int argc, char **argv) { int in_command = 0; struct cmdentry *cmd = NULL; double t; while (argc) { if (argv[0][0] == '-') { if (in_command) SLIST_INSERT_HEAD(&commands, cmd, link); if (memcmp(argv[0], "--", 3) == 0) { in_command = 0; /*-- ends a command explicitly*/ argc --, argv ++; continue; } cmd = calloc(1, sizeof(struct cmdentry)); if (cmd == NULL) errx(1, "memory allocating failure"); cmd->cmd = strdup(&argv[0][1]); if (cmd->cmd == NULL) errx(1, "memory allocating failure"); in_command = 1; } else if (!in_command) { t = strtod(argv[0], NULL) * 1000000.0; if (t > 0 && t < (double)UINT_MAX) delay = (unsigned int)t; } else if (cmd != NULL) { cmd->argv = strdup(argv[0]); if (cmd->argv == NULL) errx(1, "memory allocating failure"); in_command = 0; SLIST_INSERT_HEAD(&commands, cmd, link); } else errx(1, "invalid arguments list"); argc--, argv++; } if (in_command && cmd != NULL) SLIST_INSERT_HEAD(&commands, cmd, link); } int main(int argc, char **argv) { char errbuf[_POSIX2_LINE_MAX], dummy; size_t size; struct cmdentry *cmd = NULL; (void) setlocale(LC_ALL, ""); SLIST_INIT(&commands); argc--, argv++; if (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; argc--, argv++; } parse_cmd_args (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(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, O_RDONLY, errbuf); if (kd == NULL) { error("%s", errbuf); exit(1); } } signal(SIGHUP, die); 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, 1, 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(); if (curcmd->c_cmd != NULL) SLIST_FOREACH (cmd, &commands, link) if (!curcmd->c_cmd(cmd->cmd, cmd->argv)) warnx("command is not understood"); dellave = 0.0; display(); noecho(); crmode(); keyboard(); /*NOTREACHED*/ return EXIT_SUCCESS; } void labels(void) { if (curcmd->c_flags & CF_LOADAV) { mvaddstr(0, 20, "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); mvaddstr(1, 5, "Load Average"); } if (curcmd->c_flags & CF_ZFSARC) { mvaddstr(0, 20, " Total MFU MRU Anon Hdr L2Hdr Other"); mvaddstr(1, 5, "ZFS ARC "); } (*curcmd->c_label)(); #ifdef notdef mvprintw(21, 25, "CPU usage on %s", hostname); #endif refresh(); } void display(void) { int i, j; /* Get the load average over the last minute. */ (void) getloadavg(avenrun, nitems(avenrun)); (*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 = MIN(j, 50); i > 0; i--) waddch(wload, c); if (j > 50) wprintw(wload, " %4.1f", avenrun[0]); } if (curcmd->c_flags & CF_ZFSARC) { uint64_t arc[7] = {}; size_t size = sizeof(arc[0]); if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arc[0], &size, NULL, 0) == 0 ) { GETSYSCTL("vfs.zfs.mfu_size", arc[1]); GETSYSCTL("vfs.zfs.mru_size", arc[2]); GETSYSCTL("vfs.zfs.anon_size", arc[3]); GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]); GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]); GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc[6]); wmove(wload, 0, 0); wclrtoeol(wload); - for (i = 0 ; i < nitems(arc); i++) { - if (arc[i] > 10llu * 1024 * 1024 * 1024 ) { - wprintw(wload, "%7lluG", arc[i] >> 30); - } - else if (arc[i] > 10 * 1024 * 1024 ) { - wprintw(wload, "%7lluM", arc[i] >> 20); - } - else { - wprintw(wload, "%7lluK", arc[i] >> 10); - } - } + for (i = 0 ; i < nitems(arc); i++) + sysputuint64(wload, 0, i*8+2, 6, arc[i], 0); } } (*curcmd->c_refresh)(); if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC)) wrefresh(wload); wrefresh(wnd); move(CMDLINE, col); refresh(); } void load(void) { (void) getloadavg(avenrun, nitems(avenrun)); mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", avenrun[0], avenrun[1], avenrun[2]); clrtoeol(); } void die(int signo __unused) { move(CMDLINE, 0); clrtoeol(); refresh(); endwin(); exit(0); } #include 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(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/swap.c b/usr.bin/systat/swap.c index 01d4ed0378fe..bb84187c8944 100644 --- a/usr.bin/systat/swap.c +++ b/usr.bin/systat/swap.c @@ -1,216 +1,231 @@ /*- * Copyright (c) 1980, 1992, 1993 * The Regents of the University of California. All rights reserved. + * Copyright (c) 2017 Yoshihiro Ota * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __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 #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" +#include "devs.h" static char *header; static long blocksize; static int dlen, odlen; static int hlen; static int ulen, oulen; static int pagesize; WINDOW * openswap(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closeswap(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 . */ #define NSWAP 16 static struct kvm_swap kvmsw[NSWAP]; static int kvnsw, okvnsw; static void calclens(void); #define CONVERT(v) ((int)((int64_t)(v) * pagesize / blocksize)) static void calclens(void) { int i, n; int len; dlen = sizeof("Disk"); for (i = 0; i < kvnsw; ++i) { len = strlen(kvmsw[i].ksw_devname); if (dlen < len) dlen = len; } ulen = sizeof("Used"); for (n = CONVERT(kvmsw[kvnsw].ksw_used), len = 2; n /= 10; ++len); if (ulen < len) ulen = len; } int initswap(void) { static int once = 0; if (once) return (1); header = getbsize(&hlen, &blocksize); pagesize = getpagesize(); if ((kvnsw = kvm_getswapinfo(kd, kvmsw, NSWAP, 0)) < 0) { error("systat: kvm_getswapinfo failed"); return (0); } okvnsw = kvnsw; calclens(); odlen = dlen; oulen = ulen; once = 1; + + dsinit(12); + return (1); } void fetchswap(void) { - okvnsw = kvnsw; if ((kvnsw = kvm_getswapinfo(kd, kvmsw, NSWAP, 0)) < 0) { error("systat: kvm_getswapinfo failed"); return; } odlen = dlen; oulen = ulen; calclens(); + + struct devinfo *tmp_dinfo; + + tmp_dinfo = last_dev.dinfo; + last_dev.dinfo = cur_dev.dinfo; + cur_dev.dinfo = tmp_dinfo; + + last_dev.snap_time = cur_dev.snap_time; + dsgetinfo( &cur_dev ); } void labelswap(void) { const char *name; int i; fetchswap(); werase(wnd); mvwprintw(wnd, 0, 0, "%*s%*s%*s %s", -dlen, "Disk", hlen, header, ulen, "Used", "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); for (i = 0; i <= kvnsw; ++i) { if (i == kvnsw) { if (kvnsw == 1) break; name = "Total"; } else name = kvmsw[i].ksw_devname; mvwprintw(wnd, i + 1, 0, "%*s", -dlen, name); } + dslabel(12, 0, 18); } void showswap(void) { int count; int i; if (kvnsw != okvnsw || dlen != odlen || ulen != oulen) labelswap(); for (i = 0; i <= kvnsw; ++i) { if (i == kvnsw) { if (kvnsw == 1) break; } if (kvmsw[i].ksw_total == 0) { mvwprintw( wnd, i + 1, dlen + hlen + ulen + 1, "(swap not configured)" ); continue; } wmove(wnd, i + 1, dlen); wprintw(wnd, "%*d", hlen, CONVERT(kvmsw[i].ksw_total)); wprintw(wnd, "%*d", ulen, CONVERT(kvmsw[i].ksw_used)); count = 50.0 * kvmsw[i].ksw_used / kvmsw[i].ksw_total + 1; waddch(wnd, ' '); while (count--) waddch(wnd, 'X'); wclrtoeol(wnd); } + dsshow(12, 0, 18, &cur_dev, &last_dev); } diff --git a/usr.bin/systat/sysput.c b/usr.bin/systat/sysput.c new file mode 100644 index 000000000000..31c9127a83b7 --- /dev/null +++ b/usr.bin/systat/sysput.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2019 Yoshihiro Ota + * + * 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. 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 +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include + +#include "systat.h" +#include "extern.h" + +void +sysputspaces(WINDOW *wd, int row, int col, int width) +{ + static char str40[] = " "; + + mvwaddstr(wd, row, col, str40 + sizeof(str40) - width - 1); +} + +void +sysputstrs(WINDOW *wd, int row, int col, int width) +{ + static char str40[] = "****************************************"; + + mvwaddstr(wnd, row, col, str40 + sizeof(str40) - width - 1); +} + +void +sysputuint64(WINDOW *wd, int row, int col, int width, uint64_t val, int flags) +{ + char unit, *ptr, *start, wrtbuf[width + width + 1]; + int len; + + unit = 0; + start = wrtbuf; + flags |= HN_NOSPACE; + + if (val > INT64_MAX) + goto error; + else + len = humanize_number(&wrtbuf[width], width + 1, val, "", + HN_AUTOSCALE, flags); + if (len < 0) + goto error; + else if (len < width) + memset(wrtbuf + len, ' ', width - len); + start += len; + + mvwaddstr(wd, row, col, start); + return; + +error: + sysputstrs(wd, row, col, width); +} + +void +sysputwuint64(WINDOW *wd, int row, int col, int width, uint64_t val, int flags) +{ + if(val == 0) + sysputspaces(wd, row, col, width); + else + sysputuint64(wd, row, col, width, val, flags); +} + +static int +calc_page_shift() +{ + u_int page_size; + int shifts; + + shifts = 0; + GETSYSCTL("vm.stats.vm.v_page_size", page_size); + for(; page_size > 1; page_size >>= 1) + shifts++; + return shifts; +} + +void +sysputpage(WINDOW *wd, int row, int col, int width, uint64_t pages, int flags) +{ + static int shifts = 0; + + if (shifts == 0) + shifts = calc_page_shift(); + pages <<= shifts; + sysputuint64(wd, row, col, width, pages, flags); +} diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 index 4a0e833e0a90..9e2dd9bf7428 100644 --- a/usr.bin/systat/systat.1 +++ b/usr.bin/systat/systat.1 @@ -1,686 +1,687 @@ .\" 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. .\" 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 December 5, 2016 .Dt SYSTAT 1 .Os .Sh NAME .Nm systat .Nd display system statistics .Sh SYNOPSIS .Nm .Op Fl display .Op Ar display-commands .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 ) , .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 netstat , .Ic pigs , .Ic sctp , .Ic swap , .Ic tcp , .Ic vmstat , or .Ic zarc , 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. Time interval can be fractional. .It Ar display-commands A list of commands specific to this display. These commands can also be entered interactively and are described for each display separately below. If the command requires arguments, they can be specified as separate command line arguments. A command line argument .Fl - will finish display commands. For example: .Pp .Dl Nm Fl ifstat Fl match Ar bge0,em1 Fl pps .Pp This will display statistics of packets per second for network interfaces named as bge0 and em1. .Pp .Dl Nm Fl iostat Fl numbers Fl - Ar 2.1 .Pp This will display all IO statistics in a numeric format and the information will be refreshed each 2.1 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 statistics. It does not display .Tn UDP statistics. .It Ic sctp Like .Ic icmp , but with .Tn SCTP 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 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 caching, 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 kilobytes in physical pages claimed by processes. The second column reports the number of kilobytes in 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 kilobytes in pages that would be needed if all processes had all of their pages. Finally the last column shows the number of kilobytes in 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 To the right of the name translations display are lines showing the number of dirty buffers in the buffer cache (`dtbuf'), desired maximum size of vnode cache (`desvn'), number of vnodes actually allocated (`numvn'), and number of allocated vnodes that are free (`frevn'). .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. The first few lines describe, in units (except as noted below) of pages per second averaged over the sampling interval, pages copied on write (`cow'), pages zero filled on demand (`zfod'), pages optimally zero filled on demand (`ozfod'), the ratio of the (average) ozfod / zfod as a percentage (`%ozfod'), pages freed by the page daemon (`daefr'), pages freed by exiting processes (`prcfr'), total pages freed (`totfr'), pages reactivated from the free list (`react'), the average number of times per second that the page daemon was awakened (`pdwak'), pages analyzed by the page daemon (`pdpgs'), and in-transit blocking page faults (`intrn'). Note that the units are special for `%ozfod' and `pdwak'. The next few lines describe, as amounts of memory in kilobytes, pages wired down (`wire'), active pages (`act'), inactive pages (`inact'), dirty pages queued for laundering (`laund'), and free pages (`free'). Note that the values displayed are the current transient ones; they are not averages. .Pp At the bottom of this column is a line showing the amount of virtual memory, in kilobytes, mapped into the buffer cache (`buf'). This statistic is not useful. It exists only as a placeholder for the corresponding useful statistic (the amount of real memory used to cache disks). The most important component of the latter (the amount of real memory used by the vm system to cache disks) is not available, but can be guessed from the `inact' amount under some system loads. .Pp Running down the right hand side of the display is a breakdown of the interrupts being handled by the system. At the top of the list is the total interrupts per second over the time interval. The rest of the column breaks down the total on a device by device basis. Only devices that have interrupted at least once since boot time are shown. .Pp The following commands are specific to the .Ic vmstat display; the minimum unambiguous prefix may be supplied. .Pp .Bl -tag -width Ar -compact .It Cm boot Display cumulative statistics since the system was booted. .It Cm run Display statistics as a running total from the point this command is given. .It Cm time Display statistics averaged over the refresh interval (the default). .It Cm zero Reset running statistics to zero. .El .It Ic zarc display arc cache usage and hit/miss statistics. .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. .It Cm pps Show statistics in packets per second instead of bytes/bits per second. A subsequent call of .Ic pps switches this mode off. .It Cm match Op Ar patterns Display only interfaces that match pattern provided as an argument. Patterns should be in shell syntax separated by whitespaces or commas. If this command is called without arguments then all interfaces are displayed. For example: .Pp .Dl match em0, bge1 .Pp This will display em0 and bge1 interfaces. .Pp .Dl match em*, bge*, lo0 .Pp This will display all .Ic em interfaces, all .Ic bge interfaces and the loopback interface. .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 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 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 gstat 8 , .Xr iostat 8 , .Xr vmstat 8 .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. +Ifstat does not detect new interfaces. 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 index ebd409e217ae..b2adddc1eb98 100644 --- a/usr.bin/systat/systat.h +++ b/usr.bin/systat/systat.h @@ -1,68 +1,72 @@ /*- * 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. * 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 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 CF_ZFSARC 0x4 /* display w/ ZFS cache usage */ #define TCP 0x1 #define UDP 0x2 #define MAINWIN_ROW 3 /* top row for the main/lower window */ #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)) + +extern void putint(int, int, int, int); +extern void putfloat(double, int, int, int, int, int); +extern void putlongdouble(long double, int, int, int, int, int); diff --git a/usr.bin/systat/tcp.c b/usr.bin/systat/tcp.c index c9e8e9ae1821..e27638f4b9af 100644 --- a/usr.bin/systat/tcp.c +++ b/usr.bin/systat/tcp.c @@ -1,326 +1,327 @@ /*- * 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. * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include "systat.h" #include "extern.h" #include "mode.h" static struct tcpstat curstat, initstat, oldstat; /*- --0 1 2 3 4 5 6 7 --0123456789012345678901234567890123456789012345678901234567890123456789012345 00 TCP Connections TCP Packets 01999999999999 connections initiated 999999999999 total packets sent 02999999999999 connections accepted 999999999999 - data 03999999999999 connections established 999999999999 - data (retransmit by dupack) 04999999999999 connections dropped 999999999999 - data (retransmit by sack) 05999999999999 - in embryonic state 999999999999 - ack-only 06999999999999 - on retransmit timeout 999999999999 - window probes 07999999999999 - by keepalive 999999999999 - window updates 08999999999999 - from listen queue 999999999999 - urgent data only 09 999999999999 - control 10 999999999999 - resends by PMTU discovery 11 TCP Timers 999999999999 total packets received 12999999999999 potential rtt updates 999999999999 - in sequence 13999999999999 - successful 999999999999 - completely duplicate 14999999999999 delayed acks sent 999999999999 - with some duplicate data 15999999999999 retransmit timeouts 999999999999 - out-of-order 16999999999999 persist timeouts 999999999999 - duplicate acks 17999999999999 keepalive probes 999999999999 - acks 18999999999999 - timeouts 999999999999 - window probes 19 999999999999 - window updates 20 999999999999 - bad checksum --0123456789012345678901234567890123456789012345678901234567890123456789012345 --0 1 2 3 4 5 6 7 */ WINDOW * opentcp(void) { return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } void closetcp(WINDOW *w) { if (w == NULL) return; wclear(w); wrefresh(w); delwin(w); } void labeltcp(void) { wmove(wnd, 0, 0); wclrtoeol(wnd); #define L(row, str) mvwprintw(wnd, row, 13, str) #define R(row, str) mvwprintw(wnd, row, 51, str); L(0, "TCP Connections"); R(0, "TCP Packets"); L(1, "connections initiated"); R(1, "total packets sent"); L(2, "connections accepted"); R(2, "- data"); L(3, "connections established"); R(3, "- data (retransmit by dupack)"); L(4, "connections dropped"); R(4, "- data (retransmit by sack)"); L(5, "- in embryonic state"); R(5, "- ack-only"); L(6, "- on retransmit timeout"); R(6, "- window probes"); L(7, "- by keepalive"); R(7, "- window updates"); L(8, "- from listen queue"); R(8, "- urgent data only"); 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 = (delay > 1000000) ? delay / 1000000 : 1; 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_sack_rexmits); 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, "%12lu", stats.stat) + mvwprintw(wnd, row, col, "%12"PRIu64, stats.stat) #define L(row, stat) DO(stat, row, 0) #define R(row, stat) DO(stat, row, 38) L(1, tcps_connattempt); R(1, tcps_sndtotal); L(2, tcps_accepts); R(2, tcps_sndpack); L(3, tcps_connects); R(3, tcps_sndrexmitpack); L(4, tcps_drops); R(4, tcps_sack_rexmits); L(5, tcps_conndrops); R(5, tcps_sndacks); L(6, tcps_timeoutdrop); R(6, tcps_sndprobe); L(7, tcps_keepdrops); R(7, tcps_sndwinup); L(8, tcps_listendrop); R(8, tcps_sndurg); 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 index 25f79d7e9308..ff4dbfcc2869 100644 --- a/usr.bin/systat/vmstat.c +++ b/usr.bin/systat/vmstat.c @@ -1,896 +1,829 @@ /*- * 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. * 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 __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94"; #endif /* * Cursed vmstat -- from Robert Elz. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include -#include #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_io_faults; /* page faults requiring I/O */ 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 by pagedaemon */ 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_laundry_count; /* number of pages in laundry queue */ u_long v_kmem_map_size; /* Current kmem allocation size */ struct vmtotal Total; struct nchstats nchstats; long nchcount; long *intrcnt; long bufspace; int desiredvnodes; long numvnodes; long freevnodes; int numdirtybuffers; } s, s1, s2, z; static u_long kmem_size; static u_int v_page_count; -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; +enum divisor { IEC = 0, SI = HN_DIVISOR_1000 }; 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 do_putuint64(uint64_t, int, int, int, int); 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 void putuint64(uint64_t, int, int, int); static int ucount(void); static int ncpu; static char buf[26]; static time_t t; static double etime; static int nintr; static long *intrloc; static char **intrname; static int nextintsrow; WINDOW * openkre(void) { return (stdscr); } void closekre(WINDOW *w) { 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 67 cols */ #define STATCOL 0 #define MEMROW 2 /* uses 4 rows and 45 cols */ #define MEMCOL 0 -#define PAGEROW 2 /* uses 4 rows and 30 cols */ +#define PAGEROW 1 /* uses 4 rows and 30 cols */ #define PAGECOL 47 -#define INTSROW 6 /* uses all rows to bottom and 16 cols */ +#define INTSROW 5 /* uses all rows to bottom and 16 cols */ #define INTSCOL 64 #define PROCSROW 6 /* uses 3 rows and 19 cols */ #define PROCSCOL 0 #define GENSTATROW 7 /* uses 2 rows and 29 cols */ #define GENSTATCOL 21 -#define VMSTATROW 7 /* uses 17 rows and 12-14 cols */ +#define VMSTATROW 5 /* uses 17 rows and 12-14 cols */ #define VMSTATCOL 49 /* actually 50-51 for some fields */ #define GRAPHROW 10 /* uses 3 rows and 49-51 cols */ #define GRAPHCOL 0 #define VNSTATROW 13 /* uses 4 rows and 13 columns */ #define VNSTATCOL 35 #define NAMEIROW 14 /* uses 3 rows and 32 cols */ #define NAMEICOL 0 #define DISKROW 18 /* uses 5 rows and 47 cols (for 7 drives) */ #define DISKCOL 0 #define DRIVESPACE 7 /* max # for space */ #define MAXDRIVES DRIVESPACE /* max # to display */ int initkre(void) { char *cp, *cp1, *cp2, *intrnamebuf, *nextcp; int i; size_t sz; - if ((num_devices = devstat_getnumdevs(NULL)) < 0) { - warnx("%s", devstat_errbuf); - return(0); - } - - cur.dinfo = calloc(1, sizeof(struct devinfo)); - last.dinfo = calloc(1, sizeof(struct devinfo)); - run.dinfo = calloc(1, sizeof(struct devinfo)); - - if (dsinit(MAXDRIVES, &cur, &last, &run) != 1) + if (dsinit(MAXDRIVES) != 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++) { nextcp = cp + strlen(cp) + 1; /* Discard trailing spaces. */ for (cp1 = nextcp - 1; cp1 > cp && *(cp1 - 1) == ' '; ) *--cp1 = '\0'; /* Convert "irqN: name" to "name irqN". */ if (strncmp(cp, "irq", 3) == 0) { cp1 = cp + 3; while (isdigit((u_char)*cp1)) cp1++; if (cp1 != cp && *cp1 == ':' && *(cp1 + 1) == ' ') { sz = strlen(cp); *cp1 = '\0'; cp1 = cp1 + 2; cp2 = strdup(cp); bcopy(cp1, cp, sz - (cp1 - cp) + 1); if (sz <= 10 + 4) { strcat(cp, " "); strcat(cp, cp2 + 3); } free(cp2); } } /* * Convert "name irqN" to "name N" if the former is * longer than the field width. */ if ((cp1 = strstr(cp, "irq")) != NULL && strlen(cp) > 10) bcopy(cp1 + 3, cp1, strlen(cp1 + 3) + 1); intrname[i] = cp; cp = nextcp; } nextintsrow = INTSROW + 2; allocinfo(&s); allocinfo(&s1); allocinfo(&s2); allocinfo(&z); } GETSYSCTL("vm.kmem_size", kmem_size); GETSYSCTL("vm.stats.vm.v_page_count", v_page_count); getinfo(&s2); copyinfo(&s2, &s1); return(1); } void fetchkre(void) { 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(void) { int i, j; clear(); mvprintw(STATROW, STATCOL + 6, "users Load"); mvprintw(STATROW + 1, STATCOL + 3, "Mem usage: %%Phy %%Kmem"); - mvprintw(MEMROW, MEMCOL, "Mem: KB REAL VIRTUAL"); + mvprintw(MEMROW, MEMCOL, "Mem: 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 + 1, "Interrupts"); mvprintw(INTSROW + 1, INTSCOL + 6, "total"); mvprintw(VMSTATROW, VMSTATCOL + 9, "ioflt"); mvprintw(VMSTATROW + 1, VMSTATCOL + 9, "cow"); mvprintw(VMSTATROW + 2, VMSTATCOL + 9, "zfod"); mvprintw(VMSTATROW + 3, VMSTATCOL + 9, "ozfod"); mvprintw(VMSTATROW + 4, VMSTATCOL + 9 - 1, "%%ozfod"); mvprintw(VMSTATROW + 5, VMSTATCOL + 9, "daefr"); mvprintw(VMSTATROW + 6, VMSTATCOL + 9, "prcfr"); mvprintw(VMSTATROW + 7, VMSTATCOL + 9, "totfr"); mvprintw(VMSTATROW + 8, VMSTATCOL + 9, "react"); mvprintw(VMSTATROW + 9, VMSTATCOL + 9, "pdwak"); mvprintw(VMSTATROW + 10, VMSTATCOL + 9, "pdpgs"); mvprintw(VMSTATROW + 11, VMSTATCOL + 9, "intrn"); mvprintw(VMSTATROW + 12, VMSTATCOL + 9, "wire"); mvprintw(VMSTATROW + 13, VMSTATCOL + 9, "act"); mvprintw(VMSTATROW + 14, VMSTATCOL + 9, "inact"); mvprintw(VMSTATROW + 15, VMSTATCOL + 9, "laund"); mvprintw(VMSTATROW + 16, VMSTATCOL + 9, "free"); if (LINES - 1 > VMSTATROW + 17) mvprintw(VMSTATROW + 17, VMSTATCOL + 9, "buf"); mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt"); mvprintw(GRAPHROW, GRAPHCOL, " . %%Sys . %%Intr . %%User . %%Nice . %%Idle"); mvprintw(PROCSROW, PROCSCOL, "Proc:"); mvprintw(PROCSROW + 1, PROCSCOL, " r p d s w"); mvprintw(GRAPHROW + 1, GRAPHCOL, "| | | | | | | | | | |"); mvprintw(VNSTATROW, VNSTATCOL + 8, "dtbuf"); mvprintw(VNSTATROW + 1, VNSTATCOL + 8, "desvn"); mvprintw(VNSTATROW + 2, VNSTATCOL + 8, "numvn"); mvprintw(VNSTATROW + 3, VNSTATCOL + 8, "frevn"); 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++; - } + dslabel(MAXDRIVES, DISKCOL, DISKROW); for (i = 0; i < nintr; i++) { if (intrloc[i] == 0) continue; mvprintw(intrloc[i], INTSCOL + 6, "%-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 Q(fld) {t=cur_dev.fld[i]; cur_dev.fld[i]-=last_dev.fld[i]; if(state==TIME) last_dev.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) \ do { \ Y(fld); \ - putint((int)((float)s.fld/etime + 0.5), l, c, w); \ + sysputwuint64(wnd, l, c, w, (s.fld/etime + 0.5), 0); \ } while (0) #define MAXFAIL 5 static char cpuchar[CPUSTATES] = { '=' , '+', '>', '-', ' ' }; static char cpuorder[CPUSTATES] = { CP_SYS, CP_INTR, CP_USER, CP_NICE, CP_IDLE }; void showkre(void) { float f1, f2; int psiz, inttotal; int i, l, lc; static int failcnt = 0; 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; X(intrcnt); l = (int)((float)s.intrcnt[i]/etime + 0.5); inttotal += l; if (intrloc[i] == 0) { if (nextintsrow == LINES) continue; intrloc[i] = nextintsrow++; mvprintw(intrloc[i], INTSCOL + 6, "%-10.10s", intrname[i]); } putint(l, intrloc[i], INTSCOL, 5); } putint(inttotal, INTSROW + 1, INTSCOL, 5); 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; 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, 5); putfloat(avenrun[0], STATROW, STATCOL + 20, 5, 2, 0); putfloat(avenrun[1], STATROW, STATCOL + 26, 5, 2, 0); putfloat(avenrun[2], STATROW, STATCOL + 32, 5, 2, 0); mvaddstr(STATROW, STATCOL + 55, buf); -#define pgtokb(pg) ((pg) * (s.v_page_size / 1024)) putfloat(100.0 * (v_page_count - total.t_free) / v_page_count, STATROW + 1, STATCOL + 15, 2, 0, 1); putfloat(100.0 * s.v_kmem_map_size / kmem_size, STATROW + 1, STATCOL + 22, 2, 0, 1); - putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 4, 7); - putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 12, 7); - putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 20, 8); - putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 29, 8); - putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 4, 7); - putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 12, 7); - putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 20, 8); - putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 29, 8); - putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 38, 7); + sysputpage(wnd, MEMROW + 2, MEMCOL + 4, 7, total.t_arm, 0); + sysputpage(wnd, MEMROW + 2, MEMCOL + 12, 7, total.t_armshr, 0); + sysputpage(wnd, MEMROW + 2, MEMCOL + 20, 8, total.t_avm, 0); + sysputpage(wnd, MEMROW + 2, MEMCOL + 29, 8, total.t_avmshr, 0); + sysputpage(wnd, MEMROW + 3, MEMCOL + 4, 7, total.t_rm, 0); + sysputpage(wnd, MEMROW + 3, MEMCOL + 12, 7, total.t_rmshr, 0); + sysputpage(wnd, MEMROW + 3, MEMCOL + 20, 8, total.t_vm, 0); + sysputpage(wnd, MEMROW + 3, MEMCOL + 29, 8, total.t_vmshr, 0); + sysputpage(wnd, MEMROW + 2, MEMCOL + 38, 7, total.t_free, 0); putint(total.t_rq - 1, PROCSROW + 2, PROCSCOL, 3); putint(total.t_pw, PROCSROW + 2, PROCSCOL + 4, 3); putint(total.t_dw, PROCSROW + 2, PROCSCOL + 8, 3); putint(total.t_sl, PROCSROW + 2, PROCSCOL + 12, 3); putint(total.t_sw, PROCSROW + 2, PROCSCOL + 16, 3); PUTRATE(v_io_faults, VMSTATROW, VMSTATCOL + 2, 8 - 2); PUTRATE(v_cow_faults, VMSTATROW + 1, VMSTATCOL + 2, 8 - 2); PUTRATE(v_zfod, VMSTATROW + 2, VMSTATCOL + 2, 8 - 2); PUTRATE(v_ozfod, VMSTATROW + 3, VMSTATCOL, 8); putint(s.v_zfod != 0 ? (int)(s.v_ozfod * 100.0 / s.v_zfod) : 0, VMSTATROW + 4, VMSTATCOL + 1, 8 - 1); PUTRATE(v_dfree, VMSTATROW + 5, VMSTATCOL + 2, 8 - 2); PUTRATE(v_pfree, VMSTATROW + 6, VMSTATCOL + 2, 8 - 2); PUTRATE(v_tfree, VMSTATROW + 7, VMSTATCOL, 8); PUTRATE(v_reactivated, VMSTATROW + 8, VMSTATCOL, 8); PUTRATE(v_pdwakeups, VMSTATROW + 9, VMSTATCOL, 8); PUTRATE(v_pdpages, VMSTATROW + 10, VMSTATCOL, 8); PUTRATE(v_intrans, VMSTATROW + 11, VMSTATCOL, 8); - putint(pgtokb(s.v_wire_count), VMSTATROW + 12, VMSTATCOL, 8); - putint(pgtokb(s.v_active_count), VMSTATROW + 13, VMSTATCOL, 8); - putint(pgtokb(s.v_inactive_count), VMSTATROW + 14, VMSTATCOL, 8); - putint(pgtokb(s.v_laundry_count), VMSTATROW + 15, VMSTATCOL, 8); - putint(pgtokb(s.v_free_count), VMSTATROW + 16, VMSTATCOL, 8); + sysputpage(wnd, VMSTATROW + 12, VMSTATCOL + 2, 8 - 2, s.v_wire_count, 0); + sysputpage(wnd, VMSTATROW + 13, VMSTATCOL + 2, 8 - 2, s.v_active_count, 0); + sysputpage(wnd, VMSTATROW + 14, VMSTATCOL + 2, 8 - 2, s.v_inactive_count, 0); + sysputpage(wnd, VMSTATROW + 15, VMSTATCOL + 2, 8 - 2, s.v_laundry_count, 0); + sysputpage(wnd, VMSTATROW + 16, VMSTATCOL + 2, 8 - 2, s.v_free_count, 0); if (LINES - 1 > VMSTATROW + 17) - putint(s.bufspace / 1024, VMSTATROW + 17, VMSTATCOL, 8); + sysputuint64(wnd, VMSTATROW + 17, VMSTATCOL + 2, 8 - 2, s.bufspace, 0); PUTRATE(v_vnodein, PAGEROW + 2, PAGECOL + 6, 5); PUTRATE(v_vnodeout, PAGEROW + 2, PAGECOL + 12, 5); PUTRATE(v_swapin, PAGEROW + 2, PAGECOL + 19, 5); PUTRATE(v_swapout, PAGEROW + 2, PAGECOL + 25, 5); PUTRATE(v_vnodepgsin, PAGEROW + 3, PAGECOL + 6, 5); PUTRATE(v_vnodepgsout, PAGEROW + 3, PAGECOL + 12, 5); PUTRATE(v_swappgsin, PAGEROW + 3, PAGECOL + 19, 5); PUTRATE(v_swappgsout, PAGEROW + 3, PAGECOL + 25, 5); PUTRATE(v_swtch, GENSTATROW + 1, GENSTATCOL, 4); PUTRATE(v_trap, GENSTATROW + 1, GENSTATCOL + 5, 4); PUTRATE(v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 4); PUTRATE(v_intr, GENSTATROW + 1, GENSTATCOL + 15, 4); PUTRATE(v_soft, GENSTATROW + 1, GENSTATCOL + 20, 4); PUTRATE(v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 4); - for (i = 0, lc = 0; i < num_devices && lc < MAXDRIVES; i++) - if (dev_select[i].selected) { - 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; - } - } + switch(state) { + case TIME: + dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, &last_dev); + break; + case RUN: + dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, &run_dev); + break; + case BOOT: + dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, NULL); + break; + } putint(s.numdirtybuffers, VNSTATROW, VNSTATCOL, 7); putint(s.desiredvnodes, VNSTATROW + 1, VNSTATCOL, 7); putint(s.numvnodes, VNSTATROW + 2, VNSTATCOL, 7); putint(s.freevnodes, VNSTATROW + 3, VNSTATCOL, 7); putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 8); putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits), NAMEIROW + 2, NAMEICOL + 9, 7); #define nz(x) ((x) ? (x) : 1) putfloat((nchtotal.ncs_goodhits+nchtotal.ncs_neghits) * 100.0 / nz(s.nchcount), NAMEIROW + 2, NAMEICOL + 17, 3, 0, 1); putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 21, 7); putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount), NAMEIROW + 2, NAMEICOL + 29, 3, 0, 1); #undef nz } int cmdkre(const char *cmd, const char *args) { int retval; if (prefix(cmd, "run")) { retval = 1; copyinfo(&s2, &s1); - switch (devstat_getdevs(NULL, &run)) { + switch (devstat_getdevs(NULL, &run_dev)) { 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); + num_devices = run_dev.dinfo->numdevs; + generation = run_dev.dinfo->generation; + retval = dscmd("refresh", NULL, MAXDRIVES, &cur_dev); 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)) { + switch (devstat_getdevs(NULL, &run_dev)) { 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); + num_devices = run_dev.dinfo->numdevs; + generation = run_dev.dinfo->generation; + retval = dscmd("refresh",NULL, MAXDRIVES, &cur_dev); if (retval == 2) labelkre(); break; default: break; } } return (retval); } - retval = dscmd(cmd, args, MAXDRIVES, &cur); + retval = dscmd(cmd, args, MAXDRIVES, &cur_dev); if (retval == 2) labelkre(); return(retval); } /* calculate number of users on the system */ static int ucount(void) { int nusers = 0; struct utmpx *ut; setutxent(); while ((ut = getutxent()) != NULL) if (ut->ut_type == USER_PROCESS) nusers++; endutxent(); return (nusers); } static float cputime(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 +void putint(int n, int l, int lc, int w) +{ + + do_putuint64(n, l, lc, w, SI); +} + +static void +putuint64(uint64_t n, int l, int lc, int w) +{ + + do_putuint64(n, l, lc, w, IEC); +} + +static void +do_putuint64(uint64_t n, int l, int lc, int w, int div) { int snr; char b[128]; + char buf[128]; move(l, lc); #ifdef DEBUG while (w-- > 0) addch('*'); return; #endif if (n == 0) { while (w-- > 0) addch(' '); return; } - snr = snprintf(b, sizeof(b), "%*d", w, n); - if (snr != w) - snr = snprintf(b, sizeof(b), "%*dk", w - 1, n / 1000); - if (snr != w) - snr = snprintf(b, sizeof(b), "%*dM", w - 1, n / 1000000); + snr = snprintf(b, sizeof(b), "%*ju", w, (uintmax_t)n); + if (snr != w) { + humanize_number(buf, w, n, "", HN_AUTOSCALE, + HN_NOSPACE | HN_DECIMAL | div); + snr = snprintf(b, sizeof(b), "%*s", w, buf); + } if (snr != w) { while (w-- > 0) addch('*'); return; } addstr(b); } -static void +void putfloat(double f, int l, int lc, int w, int d, int nz) { int snr; char b[128]; move(l, lc); #ifdef DEBUG while (--w >= 0) addch('*'); return; #endif if (nz && f == 0.0) { while (--w >= 0) addch(' '); return; } snr = snprintf(b, sizeof(b), "%*.*f", w, d, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0f", w, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0fk", w - 1, f / 1000); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0fM", w - 1, f / 1000000); if (snr != w) { while (--w >= 0) addch('*'); return; } addstr(b); } -static void +void putlongdouble(long double f, int l, int lc, int w, int d, int nz) { int snr; char b[128]; move(l, lc); #ifdef DEBUG while (--w >= 0) addch('*'); return; #endif if (nz && f == 0.0) { while (--w >= 0) addch(' '); return; } snr = snprintf(b, sizeof(b), "%*.*Lf", w, d, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0Lf", w, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0Lfk", w - 1, f / 1000); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0LfM", w - 1, f / 1000000); if (snr != w) { while (--w >= 0) addch('*'); return; } addstr(b); } static void getinfo(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("kern.cp_time", cur_dev.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_io_faults", ls->v_io_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_laundry_count", ls->v_laundry_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("vm.kmem_map_size", ls->v_kmem_map_size); 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; + tmp_dinfo = last_dev.dinfo; + last_dev.dinfo = cur_dev.dinfo; + cur_dev.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; - } + last_dev.snap_time = cur_dev.snap_time; + dsgetinfo(&cur_dev); } static void allocinfo(struct Info *ls) { ls->intrcnt = (long *) calloc(nintr, sizeof(long)); if (ls->intrcnt == NULL) errx(2, "out of memory"); } static void copyinfo(struct Info *from, struct Info *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(int dn, int lc, struct statinfo *now, struct statinfo *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); -} diff --git a/usr.bin/systat/zarc.c b/usr.bin/systat/zarc.c index 2a6606f9d8fb..7b65faf5ec4a 100644 --- a/usr.bin/systat/zarc.c +++ b/usr.bin/systat/zarc.c @@ -1,221 +1,249 @@ /*- - * Copyright (c) 2014 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 2014 - 2017, 2019 Yoshihiro Ota * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include +#include +#include #include "systat.h" #include "extern.h" +#include "devs.h" -struct zfield{ +struct zfield { uint64_t arcstats; uint64_t arcstats_demand_data; uint64_t arcstats_demand_metadata; uint64_t arcstats_prefetch_data; uint64_t arcstats_prefetch_metadata; uint64_t zfetchstats; uint64_t arcstats_l2; uint64_t vdev_cache_stats; }; static struct zarcstats { struct zfield hits; struct zfield misses; } curstat, initstat, oldstat; +struct zarcrates { + struct zfield current; + struct zfield total; +}; + static void getinfo(struct zarcstats *ls); WINDOW * openzarc(void) { - return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); + + return (subwin(stdscr, LINES - 3 - 1, 0, MAINWIN_ROW, 0)); } void closezarc(WINDOW *w) { + if (w == NULL) return; wclear(w); wrefresh(w); delwin(w); } void labelzarc(void) { + int row = 1; + wmove(wnd, 0, 0); wclrtoeol(wnd); - mvwprintw(wnd, 0, 31+1, "%4.4s %7.7s %7.7s %12.12s %12.12s", - "rate", "hits", "misses", "total hits", "total misses"); -#define L(row, str) mvwprintw(wnd, row, 5, str); \ - mvwprintw(wnd, row, 31, ":"); \ - mvwprintw(wnd, row, 31+4, "%%") - L(1, "arcstats"); - L(2, "arcstats.demand_data"); - L(3, "arcstats.demand_metadata"); - L(4, "arcstats.prefetch_data"); - L(5, "arcstats.prefetch_metadata"); - L(6, "zfetchstats"); - L(7, "arcstats.l2"); - L(8, "vdev_cache_stats"); + mvwprintw(wnd, 0, 31+1, "%4.4s %6.6s %6.6s | Total %4.4s %6.6s %6.6s", + "Rate", "Hits", "Misses", "Rate", "Hits", "Misses"); +#define L(str) mvwprintw(wnd, row++, 5, \ + "%-26.26s: %% | %%", #str) + L(arcstats); + L(arcstats.demand_data); + L(arcstats.demand_metadata); + L(arcstats.prefetch_data); + L(arcstats.prefetch_metadata); + L(zfetchstats); + L(arcstats.l2); + L(vdev_cache_stats); #undef L + dslabel(12, 0, 18); } -static int calc(uint64_t hits, uint64_t misses) +static int +calc_rate(uint64_t hits, uint64_t misses) { - if( hits ) - return 100 * hits / ( hits + misses ); + if(hits) + return 100 * hits / (hits + misses); else return 0; } static void -domode(struct zarcstats *delta, struct zarcstats *rate) +domode(struct zarcstats *delta, struct zarcrates *rate) { #define DO(stat) \ delta->hits.stat = (curstat.hits.stat - oldstat.hits.stat); \ delta->misses.stat = (curstat.misses.stat - oldstat.misses.stat); \ - rate->hits.stat = calc(delta->hits.stat, delta->misses.stat) + rate->current.stat = calc_rate(delta->hits.stat, delta->misses.stat); \ + rate->total.stat = calc_rate(curstat.hits.stat, curstat.misses.stat) DO(arcstats); DO(arcstats_demand_data); DO(arcstats_demand_metadata); DO(arcstats_prefetch_data); DO(arcstats_prefetch_metadata); DO(zfetchstats); DO(arcstats_l2); DO(vdev_cache_stats); DO(arcstats); DO(arcstats_demand_data); DO(arcstats_demand_metadata); DO(arcstats_prefetch_data); DO(arcstats_prefetch_metadata); DO(zfetchstats); DO(arcstats_l2); DO(vdev_cache_stats); #undef DO } void showzarc(void) { - struct zarcstats delta, rate; - - memset(&delta, 0, sizeof delta); - memset(&rate, 0, sizeof rate); + int row = 1; + struct zarcstats delta = {}; + struct zarcrates rate = {}; domode(&delta, &rate); -#define DO(stat, row, col, fmt) \ - mvwprintw(wnd, row, col, fmt, stat) -#define R(row, stat) DO(rate.hits.stat, row, 31+1, "%3lu") -#define H(row, stat) DO(delta.hits.stat, row, 31+1+5, "%7lu"); \ - DO(curstat.hits.stat, row, 31+1+5+8+8, "%12lu") -#define M(row, stat) DO(delta.misses.stat, row, 31+1+5+8, "%7lu"); \ - DO(curstat.misses.stat, row, 31+1+5+8+8+13, "%12lu") -#define E(row, stat) R(row, stat); H(row, stat); M(row, stat); - E(1, arcstats); - E(2, arcstats_demand_data); - E(3, arcstats_demand_metadata); - E(4, arcstats_prefetch_data); - E(5, arcstats_prefetch_metadata); - E(6, zfetchstats); - E(7, arcstats_l2); - E(8, vdev_cache_stats); +#define DO(stat, col, width) \ + sysputuint64(wnd, row, col, width, stat, HN_DIVISOR_1000) +#define RATES(stat) mvwprintw(wnd, row, 31+1, "%3"PRIu64, rate.current.stat);\ + mvwprintw(wnd, row, 31+1+5+7+7+8, "%3"PRIu64, rate.total.stat) +#define HITS(stat) DO(delta.hits.stat, 31+1+5, 6); \ + DO(curstat.hits.stat, 31+1+5+7+7+8+5, 6) +#define MISSES(stat) DO(delta.misses.stat, 31+1+5+7, 6); \ + DO(curstat.misses.stat, 31+1+5+7+7+8+5+7, 6) +#define E(stat) RATES(stat); HITS(stat); MISSES(stat); ++row + E(arcstats); + E(arcstats_demand_data); + E(arcstats_demand_metadata); + E(arcstats_prefetch_data); + E(arcstats_prefetch_metadata); + E(zfetchstats); + E(arcstats_l2); + E(vdev_cache_stats); #undef DO #undef E -#undef M -#undef H -#undef R +#undef MISSES +#undef HITS +#undef RATES + dsshow(12, 0, 18, &cur_dev, &last_dev); } int initzarc(void) { + dsinit(12); getinfo(&initstat); curstat = oldstat = initstat; + return 1; } void resetzarc(void) { + initzarc(); } static void getinfo(struct zarcstats *ls) { - size_t size = sizeof( ls->hits.arcstats ); - if ( sysctlbyname("kstat.zfs.misc.arcstats.hits", - &ls->hits.arcstats, &size, NULL, 0 ) != 0 ) + struct devinfo *tmp_dinfo; + + tmp_dinfo = last_dev.dinfo; + last_dev.dinfo = cur_dev.dinfo; + cur_dev.dinfo = tmp_dinfo; + + last_dev.snap_time = cur_dev.snap_time; + dsgetinfo(&cur_dev); + + size_t size = sizeof(ls->hits.arcstats); + if (sysctlbyname("kstat.zfs.misc.arcstats.hits", + &ls->hits.arcstats, &size, NULL, 0) != 0) return; GETSYSCTL("kstat.zfs.misc.arcstats.misses", ls->misses.arcstats); GETSYSCTL("kstat.zfs.misc.arcstats.demand_data_hits", ls->hits.arcstats_demand_data); GETSYSCTL("kstat.zfs.misc.arcstats.demand_data_misses", ls->misses.arcstats_demand_data); GETSYSCTL("kstat.zfs.misc.arcstats.demand_metadata_hits", ls->hits.arcstats_demand_metadata); GETSYSCTL("kstat.zfs.misc.arcstats.demand_metadata_misses", ls->misses.arcstats_demand_metadata); GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_data_hits", ls->hits.arcstats_prefetch_data); GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_data_misses", ls->misses.arcstats_prefetch_data); GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_metadata_hits", ls->hits.arcstats_prefetch_metadata); GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_metadata_misses", ls->misses.arcstats_prefetch_metadata); GETSYSCTL("kstat.zfs.misc.zfetchstats.hits", ls->hits.zfetchstats); GETSYSCTL("kstat.zfs.misc.zfetchstats.misses", ls->misses.zfetchstats); GETSYSCTL("kstat.zfs.misc.arcstats.l2_hits", ls->hits.arcstats_l2); GETSYSCTL("kstat.zfs.misc.arcstats.l2_misses", ls->misses.arcstats_l2); GETSYSCTL("kstat.zfs.misc.vdev_cache_stats.hits", ls->hits.vdev_cache_stats); GETSYSCTL("kstat.zfs.misc.vdev_cache_stats.misses", ls->misses.vdev_cache_stats); } void fetchzarc(void) { + oldstat = curstat; getinfo(&curstat); }