summaryrefslogtreecommitdiffstats
path: root/usr.bin/systat
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-01-04 22:07:24 +0000
committerphk <phk@FreeBSD.org>2003-01-04 22:07:24 +0000
commitfdbb382f1cbb42ab486d1f7812f0f78c0317b799 (patch)
tree5e9c2b34c41b9ea1f013d008a54a312bd6abf5ff /usr.bin/systat
parent4a03bcc47da1950a8d976e9bc194f23717c1075f (diff)
downloadFreeBSD-src-fdbb382f1cbb42ab486d1f7812f0f78c0317b799.zip
FreeBSD-src-fdbb382f1cbb42ab486d1f7812f0f78c0317b799.tar.gz
Add "ifstat" display:
ifstat Display the network traffic going through active interfaces on the system. Idle interfaces will not be displayed until they receive some traffic. For each interface being displayed, the current, peak and total statistics are displayed for incoming and outgoing traffic. By default, the ifstat display will automatically scale the units being used so that they are in a human-read- able format. The scaling units used for the current and peak traffic columns can be altered by the scale command. Submitted by: Trent Nelson <trent@arpa.com>
Diffstat (limited to 'usr.bin/systat')
-rw-r--r--usr.bin/systat/Makefile2
-rw-r--r--usr.bin/systat/cmdtab.c3
-rw-r--r--usr.bin/systat/convtbl.c98
-rw-r--r--usr.bin/systat/convtbl.h132
-rw-r--r--usr.bin/systat/extern.h9
-rw-r--r--usr.bin/systat/ifcmds.c95
-rw-r--r--usr.bin/systat/ifstat.c425
-rw-r--r--usr.bin/systat/systat.123
8 files changed, 785 insertions, 2 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
index 80f7bc3..5a0a05e 100644
--- a/usr.bin/systat/Makefile
+++ b/usr.bin/systat/Makefile
@@ -4,7 +4,7 @@
PROG= systat
SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \
mbufs.c netcmds.c netstat.c pigs.c swap.c icmp.c mode.c ip.c tcp.c \
- vmstat.c
+ vmstat.c convtbl.c ifcmds.c ifstat.c
DPADD= ${LIBCURSES} ${LIBM} ${LIBKVM} ${LIBDEVSTAT}
LDADD= -lcurses -lm -lkvm -ldevstat
diff --git a/usr.bin/systat/cmdtab.c b/usr.bin/systat/cmdtab.c
index 63685e0..bb17455 100644
--- a/usr.bin/systat/cmdtab.c
+++ b/usr.bin/systat/cmdtab.c
@@ -71,6 +71,9 @@ struct cmdtab cmdtab[] = {
{ "tcp", showtcp, fetchtcp, labeltcp,
inittcp, opentcp, closetcp, cmdmode,
resettcp, 0 },
+ { "ifstat", showifstat, fetchifstat, labelifstat,
+ initifstat, openifstat, closeifstat, cmdifstat,
+ 0, CF_LOADAV },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0 }
};
struct cmdtab *curcmd = &cmdtab[0];
diff --git a/usr.bin/systat/convtbl.c b/usr.bin/systat/convtbl.c
new file mode 100644
index 0000000..fe3cd24
--- /dev/null
+++ b/usr.bin/systat/convtbl.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include "convtbl.h"
+
+struct convtbl convtbl[] = {
+ /* mul, scale, str */
+ { BYTE, BYTES, "bytes" }, /* SC_BYTE (0) */
+ { BYTE, KILO, "KB" }, /* SC_KILOBYTE (1) */
+ { BYTE, MEGA, "MB" }, /* SC_MEGABYTE (2) */
+ { BYTE, GIGA, "GB" }, /* SC_GIGABYTE (3) */
+
+ { BIT, BITS, "b" }, /* SC_BITS (4) */
+ { BIT, KILO, "Kb" }, /* SC_KILOBITS (5) */
+ { BIT, MEGA, "Mb" }, /* SC_MEGABITS (6) */
+ { BIT, GIGA, "Gb" }, /* SC_GIGABITS (7) */
+
+ { 0, 0, "" } /* SC_AUTO (8) */
+
+};
+
+
+static __inline__
+struct convtbl *
+get_tbl_ptr(const u_long size, const u_int scale)
+{
+ struct convtbl *tbl_ptr = NULL;
+ u_long tmp = 0;
+ u_int index = scale;
+
+ /* If our index is out of range, default to auto-scaling. */
+ if (index > SC_AUTO)
+ index = SC_AUTO;
+
+ if (index == SC_AUTO)
+ /*
+ * Simple but elegant algorithm. Count how many times
+ * we can shift our size value right by a factor of ten,
+ * incrementing an index each time. We then use the
+ * index as the array index into the conversion table.
+ */
+ for (tmp = size, index = SC_KILOBYTE;
+ tmp >= MEGA && index <= SC_GIGABYTE;
+ tmp >>= 10, index++);
+
+ tbl_ptr = &convtbl[index];
+ return tbl_ptr;
+}
+
+double
+convert(const u_long size, const u_int scale)
+{
+ struct convtbl *tp = NULL;
+
+ tp = get_tbl_ptr(size, scale);
+
+ return ((double)size * tp->mul / tp->scale);
+
+}
+
+char *
+get_string(const u_long size, const u_int scale)
+{
+ struct convtbl *tp = NULL;
+
+ tp = get_tbl_ptr(size, scale);
+
+ return tp->str;
+}
diff --git a/usr.bin/systat/convtbl.h b/usr.bin/systat/convtbl.h
new file mode 100644
index 0000000..f1ad744
--- /dev/null
+++ b/usr.bin/systat/convtbl.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CONVTBL_H_
+#define _CONVTBL_H_
+
+#include <sys/types.h>
+
+#define BITS (1)
+#define BYTES (1)
+#define KILO (1024)
+#define MEGA (KILO * 1024)
+#define GIGA (MEGA * 1024)
+
+#define SC_BYTE (0)
+#define SC_KILOBYTE (1)
+#define SC_MEGABYTE (2)
+#define SC_GIGABYTE (3)
+#define SC_BIT (4)
+#define SC_KILOBIT (5)
+#define SC_MEGABIT (6)
+#define SC_GIGABIT (7)
+#define SC_AUTO (8)
+
+#define BIT (8)
+#define BYTE (1)
+
+struct convtbl {
+ u_int mul;
+ u_int scale;
+ char *str;
+};
+
+extern struct convtbl convtbl[];
+
+extern double convert(const u_long, const u_int);
+extern char *get_string(const u_long, const u_int);
+
+#endif /* ! _CONVTBL_H_ */
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef _CONVTBL_H_
+#define _CONVTBL_H_
+
+#include <sys/types.h>
+
+#define BITS (1)
+#define BYTES (1)
+#define KILO (1024)
+#define MEGA (KILO * 1024)
+#define GIGA (MEGA * 1024)
+
+#define SC_BYTE (0)
+#define SC_KILOBYTE (1)
+#define SC_MEGABYTE (2)
+#define SC_GIGABYTE (3)
+#define SC_BIT (4)
+#define SC_KILOBIT (5)
+#define SC_MEGABIT (6)
+#define SC_GIGABIT (7)
+#define SC_AUTO (8)
+
+#define BIT (8)
+#define BYTE (1)
+
+struct convtbl {
+ u_int mul;
+ u_int scale;
+ char *str;
+};
+
+extern struct convtbl convtbl[];
+
+extern double convert(const u_long, const u_int);
+extern char *get_string(const u_long, const u_int);
+
+#endif /* ! _CONVTBL_H_ */
diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h
index 3c924bb..48993d9 100644
--- a/usr.bin/systat/extern.h
+++ b/usr.bin/systat/extern.h
@@ -72,8 +72,9 @@ extern struct nlist namelist[];
int checkhost(struct inpcb *);
int checkport(struct inpcb *);
-void closeiostat(WINDOW *);
void closeicmp(WINDOW *);
+void closeifstat(WINDOW *);
+void closeiostat(WINDOW *);
void closeip(WINDOW *);
void closekre(WINDOW *);
void closembufs(WINDOW *);
@@ -81,6 +82,7 @@ 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 *);
@@ -92,6 +94,7 @@ int dkinit(void);
int dkcmd(char *, char *);
void error(const char *fmt, ...) __printflike(1, 2);
void fetchicmp(void);
+void fetchifstat(void);
void fetchip(void);
void fetchiostat(void);
void fetchkre(void);
@@ -102,6 +105,7 @@ void fetchswap(void);
void fetchtcp(void);
void getsysctl(const char *, void *, size_t);
int initicmp(void);
+int initifstat(void);
int initip(void);
int initiostat(void);
int initkre(void);
@@ -113,6 +117,7 @@ int inittcp(void);
int keyboard(void);
int kvm_ckread(void *, void *, int);
void labelicmp(void);
+void labelifstat(void);
void labelip(void);
void labeliostat(void);
void labelkre(void);
@@ -126,6 +131,7 @@ void load(void);
int netcmd(const char *, const char *);
void nlisterr(struct nlist []);
WINDOW *openicmp(void);
+WINDOW *openifstat(void);
WINDOW *openip(void);
WINDOW *openiostat(void);
WINDOW *openkre(void);
@@ -139,6 +145,7 @@ void reseticmp(void);
void resetip(void);
void resettcp(void);
void showicmp(void);
+void showifstat(void);
void showip(void);
void showiostat(void);
void showkre(void);
diff --git a/usr.bin/systat/ifcmds.c b/usr.bin/systat/ifcmds.c
new file mode 100644
index 0000000..49f215f
--- /dev/null
+++ b/usr.bin/systat/ifcmds.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h> /* For IFT_ETHER */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <float.h>
+#include <err.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+#include "convtbl.h"
+
+int curscale = SC_AUTO;
+
+static int selectscale(const char *);
+
+int
+ifcmd(const char *cmd, const char *args)
+{
+ if (prefix((char *)cmd, (char *)"scale")) {
+ if (*args != '\0' && selectscale(args) != -1)
+ ;
+ else {
+ move(CMDLINE, 0);
+ clrtoeol();
+ addstr("what scale? kbit, kbyte, mbit, mbyte, " \
+ "gbit, gbyte, auto");
+ }
+ }
+ return 1;
+}
+
+static int
+selectscale(const char *args)
+{
+ int retval = 0;
+
+#define streq(a,b) (strcmp(a,b) == 0)
+ if (streq(args, "default") || streq(args, "auto"))
+ curscale = SC_AUTO;
+ else if (streq(args, "kbit"))
+ curscale = SC_KILOBIT;
+ else if (streq(args, "kbyte"))
+ curscale = SC_KILOBYTE;
+ else if (streq(args, "mbit"))
+ curscale = SC_MEGABIT;
+ else if (streq(args, "mbyte"))
+ curscale = SC_MEGABYTE;
+ else if (streq(args, "gbit"))
+ curscale = SC_GIGABIT;
+ else if (streq(args, "gbyte"))
+ curscale = SC_GIGABYTE;
+ else
+ retval = -1;
+
+ return retval;
+}
diff --git a/usr.bin/systat/ifstat.c b/usr.bin/systat/ifstat.c
new file mode 100644
index 0000000..2235e25
--- /dev/null
+++ b/usr.bin/systat/ifstat.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTIFSTAT_ERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h> /* For IFT_ETHER */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <float.h>
+#include <err.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "mode.h"
+#include "convtbl.h"
+
+ /* Column numbers */
+
+#define C1 0 /* 0-19 */
+#define C2 20 /* 20-39 */
+#define C3 40 /* 40-59 */
+#define C4 60 /* 60-80 */
+#define C5 80 /* Used for label positioning. */
+
+static int col0 = 0;
+static int col1 = C1;
+static int col2 = C2;
+static int col3 = C3;
+static int col4 = C4;
+static int col5 = C5;
+
+
+SLIST_HEAD(, if_stat) curlist;
+SLIST_HEAD(, if_stat_disp) displist;
+
+struct if_stat {
+ SLIST_ENTRY(if_stat) link;
+ char if_name[IF_NAMESIZE];
+ struct ifmibdata if_mib;
+ struct timeval tv;
+ struct timeval tv_lastchanged;
+ u_long if_in_curtraffic;
+ u_long if_out_curtraffic;
+ u_long if_in_traffic_peak;
+ u_long if_out_traffic_peak;
+ u_int if_row; /* Index into ifmib sysctl */
+ u_int if_ypos; /* 0 if not being displayed */
+ u_int display;
+};
+
+extern u_int curscale;
+
+static void right_align_string(const struct if_stat *);
+static void getifmibdata(const int, struct ifmibdata *);
+static void sort_interface_list(void);
+static u_int getifnum(void);
+
+#define IFSTAT_ERR(n, s) do { \
+ putchar(' '); \
+ closeifstat(wnd); \
+ err((n), (s)); \
+} while (0)
+
+#define STARTING_ROW (8)
+#define ROW_SPACING (3)
+
+#define TOPLINE 5
+#define TOPLABEL \
+" Interface Traffic Peak Total"
+
+#define CLEAR_LINE(y, x) do { \
+ wmove(wnd, y, x); \
+ wclrtoeol(wnd); \
+} while (0)
+
+#define IN_col2 (ifp->if_in_curtraffic)
+#define OUT_col2 (ifp->if_out_curtraffic)
+#define IN_col3 (ifp->if_in_traffic_peak)
+#define OUT_col3 (ifp->if_out_traffic_peak)
+#define IN_col4 (ifp->if_mib.ifmd_data.ifi_ibytes)
+#define OUT_col4 (ifp->if_mib.ifmd_data.ifi_obytes)
+
+#define EMPTY_COLUMN " "
+#define CLEAR_COLUMN(y, x) mvprintw((y), (x), "%20s", EMPTY_COLUMN);
+
+#define DOPUTRATE(c, r, d) do { \
+ CLEAR_COLUMN(r, c); \
+ mvprintw(r, (c), "%10.3f %s%s ", \
+ convert(d##_##c, curscale), \
+ get_string(d##_##c, curscale), \
+ "/s"); \
+} while (0)
+
+#define DOPUTTOTAL(c, r, d) do { \
+ CLEAR_COLUMN((r), (c)); \
+ mvprintw((r), (c), "%12.3f %s ", \
+ convert(d##_##c, SC_AUTO), \
+ get_string(d##_##c, SC_AUTO)); \
+} while (0)
+
+#define PUTRATE(c, r) do { \
+ DOPUTRATE(c, (r), IN); \
+ DOPUTRATE(c, (r)+1, OUT); \
+} while (0)
+
+#define PUTTOTAL(c, r) do { \
+ DOPUTTOTAL(c, (r), IN); \
+ DOPUTTOTAL(c, (r)+1, OUT); \
+} while (0)
+
+#define PUTNAME(p) do { \
+ mvprintw(p->if_ypos, 0, "%s", p->if_name); \
+ mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in"); \
+ mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out"); \
+} while (0)
+
+
+WINDOW *
+openifstat(void)
+{
+ return (subwin(stdscr, LINES-1-5, 0, 5, 0));
+}
+
+void
+closeifstat(WINDOW *w)
+{
+ struct if_stat *node = NULL;
+
+ while (!SLIST_EMPTY(&curlist)) {
+ node = SLIST_FIRST(&curlist);
+ SLIST_REMOVE_HEAD(&curlist, link);
+ free(node);
+ }
+
+ if (w != NULL) {
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+ }
+
+ return;
+}
+
+
+void
+labelifstat(void)
+{
+
+ wmove(wnd, TOPLINE, 0);
+ wclrtoeol(wnd);
+ mvprintw(TOPLINE, 0, "%s", TOPLABEL);
+
+ return;
+}
+
+void
+showifstat(void)
+{
+ struct if_stat *ifp = NULL;
+ SLIST_FOREACH(ifp, &curlist, link) {
+ if (ifp->display == 0)
+ continue;
+ PUTNAME(ifp);
+ PUTRATE(col2, ifp->if_ypos);
+ PUTRATE(col3, ifp->if_ypos);
+ PUTTOTAL(col4, ifp->if_ypos);
+ }
+
+ return;
+}
+
+int
+initifstat(void)
+{
+ struct if_stat *p = NULL;
+ u_int n = 0, i = 0;
+
+ n = getifnum();
+ if (n <= 0)
+ return -1;
+
+ SLIST_INIT(&curlist);
+
+ for (i = 0; i < n; i++) {
+ p = (struct if_stat *)malloc(sizeof(struct if_stat));
+ if (p == NULL)
+ IFSTAT_ERR(1, "out of memory");
+ memset((void *)p, 0, sizeof(struct if_stat));
+ SLIST_INSERT_HEAD(&curlist, p, link);
+ p->if_row = i+1;
+ getifmibdata(p->if_row, &p->if_mib);
+ right_align_string(p);
+
+ /*
+ * Initially, we only display interfaces that have
+ * received some traffic.
+ */
+ if (p->if_mib.ifmd_data.ifi_ibytes != 0)
+ p->display = 1;
+ }
+
+ sort_interface_list();
+
+ return 1;
+}
+
+void
+fetchifstat(void)
+{
+ struct if_stat *ifp = NULL;
+ struct timeval tv, new_tv, old_tv;
+ double elapsed = 0.0;
+ u_int new_inb, new_outb, old_inb, old_outb = 0;
+ u_int error = 0;
+ u_int we_need_to_sort_interface_list = 0;
+
+ SLIST_FOREACH(ifp, &curlist, link) {
+ /*
+ * Grab a copy of the old input/output values before we
+ * call getifmibdata().
+ */
+ old_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
+ old_outb = ifp->if_mib.ifmd_data.ifi_obytes;
+ ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange;
+
+ error = gettimeofday(&new_tv, (struct timezone *)0);
+ if (error)
+ IFSTAT_ERR(2, "error getting time of day");
+ (void)getifmibdata(ifp->if_row, &ifp->if_mib);
+
+
+ new_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
+ new_outb = ifp->if_mib.ifmd_data.ifi_obytes;
+
+ /* Display interface if it's received some traffic. */
+ if (new_inb > 0 && old_inb == 0) {
+ ifp->display = 1;
+ we_need_to_sort_interface_list++;
+ }
+
+ /*
+ * The rest is pretty trivial. Calculate the new values
+ * for our current traffic rates, and while we're there,
+ * see if we have new peak rates.
+ */
+ old_tv = ifp->tv;
+ timersub(&new_tv, &old_tv, &tv);
+ elapsed = tv.tv_sec + (tv.tv_usec * 1e-6);
+
+ ifp->if_in_curtraffic = new_inb - old_inb;
+ ifp->if_out_curtraffic = new_outb - old_outb;
+
+ /*
+ * Rather than divide by the time specified on the comm-
+ * and line, we divide by ``elapsed'' as this is likely
+ * to be more accurate.
+ */
+ ifp->if_in_curtraffic /= elapsed;
+ ifp->if_out_curtraffic /= elapsed;
+
+ if (ifp->if_in_curtraffic > ifp->if_in_traffic_peak)
+ ifp->if_in_traffic_peak = ifp->if_in_curtraffic;
+
+ if (ifp->if_out_curtraffic > ifp->if_out_traffic_peak)
+ ifp->if_out_traffic_peak = ifp->if_out_curtraffic;
+
+ ifp->tv.tv_sec = new_tv.tv_sec;
+ ifp->tv.tv_usec = new_tv.tv_usec;
+
+ }
+
+ if (we_need_to_sort_interface_list)
+ sort_interface_list();
+
+ return;
+}
+
+/*
+ * We want to right justify our interface names against the first column
+ * (first sixteen or so characters), so we need to do some alignment.
+ */
+static void
+right_align_string(const struct if_stat *ifp)
+{
+ int str_len = 0, pad_len = 0;
+ char *newstr = NULL, *ptr = NULL;
+
+ if (ifp == NULL || ifp->if_mib.ifmd_name == NULL)
+ return;
+ else {
+ /* string length + '\0' */
+ str_len = strlen(ifp->if_mib.ifmd_name)+1;
+ pad_len = IF_NAMESIZE-(str_len);
+
+ newstr = (char *)ifp->if_name;
+ ptr = newstr + pad_len;
+ (void)memset((void *)newstr, (int)' ', IF_NAMESIZE);
+ (void)strncpy(ptr, (const char *)&ifp->if_mib.ifmd_name,
+ str_len);
+ }
+
+ return;
+}
+
+/*
+ * This function iterates through our list of interfaces, identifying
+ * those that are to be displayed (ifp->display = 1). For each interf-
+ * rface that we're displaying, we generate an appropriate position for
+ * it on the screen (ifp->if_ypos).
+ *
+ * This function is called any time a change is made to an interface's
+ * ``display'' state.
+ */
+void
+sort_interface_list(void)
+{
+ struct if_stat *ifp = NULL;
+ u_int y = 0;
+
+ y = STARTING_ROW;
+ SLIST_FOREACH(ifp, &curlist, link) {
+ if (ifp->display) {
+ ifp->if_ypos = y;
+ y += ROW_SPACING;
+ }
+ }
+}
+
+static
+unsigned int
+getifnum(void)
+{
+ int error = 0;
+ u_int data = 0;
+ size_t datalen = 0;
+ static int name[] = { CTL_NET,
+ PF_LINK,
+ NETLINK_GENERIC,
+ IFMIB_SYSTEM,
+ IFMIB_IFCOUNT };
+
+ datalen = sizeof(data);
+ error = sysctl(name,
+ 5,
+ (void *)&data,
+ (size_t *)&datalen,
+ (void *)NULL,
+ (size_t)0);
+ if (error)
+ IFSTAT_ERR(1, "sysctl error");
+ return data;
+}
+
+static void
+getifmibdata(int row, struct ifmibdata *data)
+{
+ int error = 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;
+
+ error = sysctl(name,
+ 6,
+ (void *)data,
+ (size_t *)&datalen,
+ (void *)NULL,
+ (size_t)0);
+ if (error)
+ IFSTAT_ERR(2, "sysctl error getting interface data");
+}
+
+int
+cmdifstat(const char *cmd, const char *args)
+{
+ int retval = 0;
+
+ retval = ifcmd(cmd, args);
+ /* ifcmd() returns 1 on success */
+ if (retval == 1) {
+ showifstat();
+ refresh();
+ }
+
+ return retval;
+}
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
index b45adc3..d276e58 100644
--- a/usr.bin/systat/systat.1
+++ b/usr.bin/systat/systat.1
@@ -88,6 +88,7 @@ flag expects
.Ar display
to be one of:
.Ic icmp ,
+.Ic ifstat ,
.Ic iostat ,
.Ic ip ,
.Ic mbufs ,
@@ -432,6 +433,28 @@ then only the requested information will be displayed.
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.
+.Pp
+.Bl -tag -width Ar -compact
+.It Cm scale Op Ar units
+Modify the scale used to display the current and peak traffic over all
+interfaces. The following units are recognised: kbit, kbyte, mbit,
+mbyte, gbit, gbyte and auto.
+.El
.El
.Pp
Commands to switch between displays may be abbreviated to the
OpenPOWER on IntegriCloud