Module Name:    src
Committed By:   scole
Date:           Tue Aug  2 15:56:09 UTC 2016

Modified Files:
        src/usr.bin/systat: Makefile cmds.c cmdtab.c extern.h systat.1
Added Files:
        src/usr.bin/systat: convtbl.c convtbl.h ifcmds.c ifstat.c

Log Message:
PR bin/51204

Add ifstat command to systat.

Imported from FreeBSD


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.39 src/usr.bin/systat/Makefile
cvs rdiff -u -r1.28 -r1.29 src/usr.bin/systat/cmds.c
cvs rdiff -u -r1.24 -r1.25 src/usr.bin/systat/cmdtab.c
cvs rdiff -u -r0 -r1.1 src/usr.bin/systat/convtbl.c \
    src/usr.bin/systat/convtbl.h src/usr.bin/systat/ifcmds.c \
    src/usr.bin/systat/ifstat.c
cvs rdiff -u -r1.44 -r1.45 src/usr.bin/systat/extern.h \
    src/usr.bin/systat/systat.1

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/systat/Makefile
diff -u src/usr.bin/systat/Makefile:1.38 src/usr.bin/systat/Makefile:1.39
--- src/usr.bin/systat/Makefile:1.38	Sat Jan 23 21:22:50 2016
+++ src/usr.bin/systat/Makefile	Tue Aug  2 15:56:09 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.38 2016/01/23 21:22:50 christos Exp $
+#	$NetBSD: Makefile,v 1.39 2016/08/02 15:56:09 scole Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/6/93
 
 .include <bsd.own.mk>
@@ -11,10 +11,10 @@ PROG=	systat
 CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/vmstat -DSUPPORT_UTMP -DSUPPORT_UTMPX \
 	-I${NETBSDSRCDIR}/usr.bin/who -D_KMEMUSER
 CWARNFLAGS+=    -Wno-format-y2k
-SRCS=	bufcache.c cmds.c cmdtab.c disks.c df.c drvstats.c fetch.c \
-	globalcmds.c icmp.c iostat.c ip.c keyboard.c main.c mbufs.c \
-	netcmds.c netstat.c pigs.c ps.c swap.c tcp.c vmstat.c utmpentry.c \
-	syscall.c
+SRCS=	bufcache.c cmds.c cmdtab.c convtbl.c disks.c df.c drvstats.c \
+	fetch.c globalcmds.c icmp.c ifcmds.c ifstat.c iostat.c ip.c \
+	keyboard.c main.c mbufs.c netcmds.c netstat.c pigs.c ps.c swap.c \
+	tcp.c vmstat.c utmpentry.c syscall.c
 DPADD=	${LIBCURSES} ${LIBTERMINFO} ${LIBM} ${LIBKVM}
 LDADD=	-lutil -lcurses -lterminfo -lm -lkvm
 BINGRP=	kmem

Index: src/usr.bin/systat/cmds.c
diff -u src/usr.bin/systat/cmds.c:1.28 src/usr.bin/systat/cmds.c:1.29
--- src/usr.bin/systat/cmds.c:1.28	Thu Nov  4 07:18:47 2004
+++ src/usr.bin/systat/cmds.c	Tue Aug  2 15:56:09 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cmds.c,v 1.28 2004/11/04 07:18:47 dsl Exp $	*/
+/*	$NetBSD: cmds.c,v 1.29 2016/08/02 15:56:09 scole Exp $	*/
 
 /*-
  * Copyright (c) 1980, 1992, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)cmds.c	8.2 (Berkeley) 4/29/95";
 #endif
-__RCSID("$NetBSD: cmds.c,v 1.28 2004/11/04 07:18:47 dsl Exp $");
+__RCSID("$NetBSD: cmds.c,v 1.29 2016/08/02 15:56:09 scole Exp $");
 #endif /* not lint */
 
 #include <ctype.h>
@@ -152,3 +152,15 @@ status(void)
 {
 	error("Showing %s, refresh every %d seconds.", curmode->c_name, naptime);
 }
+
+int
+prefix(const char *s1, const char *s2)
+{
+
+	while (*s1 == *s2) {
+		if (*s1 == '\0')
+			return (1);
+		s1++, s2++;
+	}
+	return (*s1 == '\0');
+}

Index: src/usr.bin/systat/cmdtab.c
diff -u src/usr.bin/systat/cmdtab.c:1.24 src/usr.bin/systat/cmdtab.c:1.25
--- src/usr.bin/systat/cmdtab.c:1.24	Fri Jan  6 14:08:08 2012
+++ src/usr.bin/systat/cmdtab.c	Tue Aug  2 15:56:09 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cmdtab.c,v 1.24 2012/01/06 14:08:08 drochner Exp $	*/
+/*	$NetBSD: cmdtab.c,v 1.25 2016/08/02 15:56:09 scole Exp $	*/
 
 /*-
  * Copyright (c) 1980, 1992, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)cmdtab.c	8.1 (Berkeley) 6/6/93";
 #endif
-__RCSID("$NetBSD: cmdtab.c,v 1.24 2012/01/06 14:08:08 drochner Exp $");
+__RCSID("$NetBSD: cmdtab.c,v 1.25 2016/08/02 15:56:09 scole Exp $");
 #endif /* not lint */
 
 #include "systat.h"
@@ -69,6 +69,13 @@ struct command	icmp_commands[] = {
 	{ .c_name = NULL }
 };
 
+struct command ifstat_commands[] = {
+	{ "scale",	ifstat_scale,	"modify scale of display"},
+	{ "pps",	ifstat_pps, 	"toggle packets per second display"},
+	{ "match",	ifstat_match,   "display matching interfaces"},
+	{ .c_name = NULL }
+};
+
 struct command	iostat_commands[] = {
 	{ "bars",	iostat_bars,	"show io stats as a bar graph"},
 	{ "numbers",	iostat_numbers,	"show io stats numerically"},
@@ -159,6 +166,9 @@ struct mode modes[] = {
 	{ "df",         showdf,  	fetchdf,	labeldf,
 	  initdf,	opendf,		closedf,	df_commands,
 	  CF_LOADAV },
+	{ "ifstat",	showifstat,	fetchifstat,	labelifstat,
+	  initifstat,	openifstat,	closeifstat,	ifstat_commands,
+	  CF_LOADAV },
 	{ "inet.icmp",	showicmp,	fetchicmp,	labelicmp,
 	  initicmp,	openicmp,	closeicmp,	icmp_commands,
 	  CF_LOADAV },

Index: src/usr.bin/systat/extern.h
diff -u src/usr.bin/systat/extern.h:1.44 src/usr.bin/systat/extern.h:1.45
--- src/usr.bin/systat/extern.h:1.44	Sun Aug 23 18:33:15 2015
+++ src/usr.bin/systat/extern.h	Tue Aug  2 15:56:09 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: extern.h,v 1.44 2015/08/23 18:33:15 mrg Exp $	*/
+/*	$NetBSD: extern.h,v 1.45 2016/08/02 15:56:09 scole Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -75,6 +75,7 @@ int	 checkport6(struct in6pcb *);
 void	 closebufcache(WINDOW *);
 void	 closedf(WINDOW *);
 void	 closeicmp(WINDOW *);
+void	 closeifstat(WINDOW *);
 void	 closeiostat(WINDOW *);
 void	 closeip(WINDOW *);
 void	 closevmstat(WINDOW *);
@@ -84,6 +85,7 @@ void	 closenetstat(WINDOW *);
 void	 closepigs(WINDOW *);
 void	 closeswap(WINDOW *);
 void	 closetcp(WINDOW *);
+int	 cmdifstat(const char *, const char *);
 void	 command(char *);
 void	 df_all(char *);
 void	 df_some(char *);
@@ -97,6 +99,7 @@ void	 clearerror(void);
 void	 fetchbufcache(void);
 void	 fetchdf(void);
 void	 fetchicmp(void);
+void	 fetchifstat(void);
 void	 fetchiostat(void);
 void	 fetchip(void);
 void	 fetchvmstat(void);
@@ -116,9 +119,14 @@ void	 icmp_boot(char *);
 void	 icmp_run(char *);
 void	 icmp_time(char *);
 void	 icmp_zero(char *);
+int	 ifcmd(const char *cmd, const char *args);
+void	 ifstat_match(char*);
+void	 ifstat_pps(char*);
+void	 ifstat_scale(char*);
 int	 initbufcache(void);
 int	 initdf(void);
 int	 initicmp(void);
+int	 initifstat(void);
 int	 initiostat(void);
 int	 initip(void);
 int	 initvmstat(void);
@@ -142,6 +150,7 @@ ssize_t	 kvm_ckread(const void *, void *
 void	 labelbufcache(void);
 void	 labeldf(void);
 void	 labelicmp(void);
+void	 labelifstat(void);
 void	 labeliostat(void);
 void	 labelip(void);
 void	 labelvmstat(void);
@@ -167,6 +176,7 @@ void	 nlisterr(struct nlist []) __dead;
 WINDOW	*openbufcache(void);
 WINDOW	*opendf(void);
 WINDOW	*openicmp(void);
+WINDOW	*openifstat(void);
 WINDOW	*openiostat(void);
 WINDOW	*openip(void);
 WINDOW	*openvmstat(void);
@@ -176,11 +186,13 @@ WINDOW	*opennetstat(void);
 WINDOW	*openpigs(void);
 WINDOW	*openswap(void);
 WINDOW	*opentcp(void);
+int	 prefix(const char *, const char *);
 void	 ps_user(char *);
 void	 redraw(void);
 void	 showbufcache(void);
 void	 showdf(void);
 void	 showicmp(void);
+void	 showifstat(void);
 void	 showiostat(void);
 void	 showip(void);
 void	 showvmstat(void);
Index: src/usr.bin/systat/systat.1
diff -u src/usr.bin/systat/systat.1:1.44 src/usr.bin/systat/systat.1:1.45
--- src/usr.bin/systat/systat.1:1.44	Sat Mar 12 02:39:01 2016
+++ src/usr.bin/systat/systat.1	Tue Aug  2 15:56:09 2016
@@ -1,4 +1,4 @@
-.\"	$NetBSD: systat.1,v 1.44 2016/03/12 02:39:01 dholland Exp $
+.\"	$NetBSD: systat.1,v 1.45 2016/08/02 15:56:09 scole Exp $
 .\"
 .\" Copyright (c) 1985, 1990, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -73,7 +73,7 @@ statistics (a la
 .Xr iostat 8 ) ,
 virtual memory statistics (a la
 .Xr vmstat 1 ) ,
-network ``mbuf'' utilization, and network connections (a la
+network ``mbuf'' utilization, network 'ifstat' traffic, and network connections (a la
 .Xr netstat 1 ) .
 .Pp
 Input is interpreted at two different levels.
@@ -115,6 +115,7 @@ argument expects to be one of:
 .Ic all ,
 .Ic bufcache ,
 .Ic df ,
+.Ic ifstat ,
 .Ic inet.icmp ,
 .Ic inet.ip ,
 .Ic inet.tcp ,
@@ -226,6 +227,54 @@ kernfs, procfs and null-mounts.
 .It Cm some
 Suppress information about procfs, kernfs and null-mounts (default).
 .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 re0, bge1
+.Pp
+This will display re0 and bge1 interfaces.
+.Pp
+.Dl match re*, bge*, lo0
+.Pp
+This will display all
+.Ic re
+interfaces, all
+.Ic bge
+interfaces and the loopback interface.
+.El
+.Pp
 .It Ic inet.icmp
 Display ICMP statistics.
 .It Ic inet.ip

Added files:

Index: src/usr.bin/systat/convtbl.c
diff -u /dev/null src/usr.bin/systat/convtbl.c:1.1
--- /dev/null	Tue Aug  2 15:56:09 2016
+++ src/usr.bin/systat/convtbl.c	Tue Aug  2 15:56:09 2016
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <tr...@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: releng/10.1/usr.bin/systat/convtbl.c 175387 2008-01-16 19:27:43Z delphij $
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: convtbl.c,v 1.1 2016/08/02 15:56:09 scole Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "convtbl.h"
+
+#define BIT		(8)
+#define BITS		(1)
+#define KILOBIT		(1000LL)
+#define MEGABIT		(KILOBIT * 1000)
+#define GIGABIT		(MEGABIT * 1000)
+#define TERABIT		(GIGABIT * 1000)
+
+#define BYTE		(1)
+#define BYTES		(1)
+#define KILOBYTE	(1024LL)
+#define MEGABYTE	(KILOBYTE * 1024)
+#define GIGABYTE	(MEGABYTE * 1024)
+#define TERABYTE	(GIGABYTE * 1024)
+
+struct convtbl {
+	uintmax_t	 mul;
+	uintmax_t	 scale;
+	const char	*str;
+	const char	*name;
+};
+
+static struct convtbl convtbl[] = {
+	/* mul, scale, str, name */
+	[SC_BYTE] =	{ BYTE, BYTES, "B", "byte" },
+	[SC_KILOBYTE] =	{ BYTE, KILOBYTE, "KB", "kbyte" },
+	[SC_MEGABYTE] =	{ BYTE, MEGABYTE, "MB", "mbyte" },
+	[SC_GIGABYTE] =	{ BYTE, GIGABYTE, "GB", "gbyte" },
+	[SC_TERABYTE] =	{ BYTE, TERABYTE, "TB", "tbyte" },
+
+	[SC_BIT] =	{ BIT, BITS, "b", "bit" },
+	[SC_KILOBIT] =	{ BIT, KILOBIT, "Kb", "kbit" },
+	[SC_MEGABIT] =	{ BIT, MEGABIT, "Mb", "mbit" },
+	[SC_GIGABIT] =	{ BIT, GIGABIT, "Gb", "gbit" },
+	[SC_TERABIT] =	{ BIT, TERABIT, "Tb", "tbit" },
+
+	[SC_AUTO] =	{ 0, 0, "", "auto" }
+};
+
+static
+struct convtbl *
+get_tbl_ptr(const uintmax_t size, const int scale)
+{
+	uintmax_t	 tmp;
+	int		 idx;
+
+	/* If our index is out of range, default to auto-scaling. */
+	idx = scale < SC_AUTO ? scale : SC_AUTO;
+
+	if (idx == SC_AUTO)
+		/*
+		 * Simple but elegant algorithm.  Count how many times
+		 * we can shift our size value right by a factor of ten,
+		 * incrementing an index each time.  We then use the
+		 * index as the array index into the conversion table.
+		 */
+		for (tmp = size, idx = SC_KILOBYTE;
+		     tmp >= MEGABYTE && idx < SC_BIT - 1;
+		     tmp >>= 10, idx++);
+
+	return (&convtbl[idx]);
+}
+
+double
+convert(const uintmax_t size, const int scale)
+{
+	struct convtbl	*tp;
+
+	tp = get_tbl_ptr(size, scale);
+	return ((double)size * tp->mul / tp->scale);
+
+}
+
+const char *
+get_string(const uintmax_t size, const int scale)
+{
+	struct convtbl	*tp;
+
+	tp = get_tbl_ptr(size, scale);
+	return (tp->str);
+}
+
+int
+get_scale(const char *name)
+{
+	int i;
+
+	for (i = 0; i <= SC_AUTO; i++)
+		if (strcmp(convtbl[i].name, name) == 0)
+			return (i);
+	return (-1);
+}
+
+const char *
+get_helplist(void)
+{
+	int i;
+	size_t len;
+	static char *buf;
+
+	if (buf == NULL) {
+		len = 0;
+		for (i = 0; i <= SC_AUTO; i++)
+			len += strlen(convtbl[i].name) + 2;
+		if ((buf = malloc(len)) != NULL) {
+			buf[0] = '\0';
+			for (i = 0; i <= SC_AUTO; i++) {
+				strcat(buf, convtbl[i].name);
+				if (i < SC_AUTO)
+					strcat(buf, ", ");
+			}
+		} else
+			return ("");
+	}
+	return (buf);
+}
Index: src/usr.bin/systat/convtbl.h
diff -u /dev/null src/usr.bin/systat/convtbl.h:1.1
--- /dev/null	Tue Aug  2 15:56:09 2016
+++ src/usr.bin/systat/convtbl.h	Tue Aug  2 15:56:09 2016
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <tr...@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: releng/10.1/usr.bin/systat/convtbl.h 164675 2006-11-27 16:33:44Z yar $
+ */
+
+#ifndef _CONVTBL_H_
+#define _CONVTBL_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/*
+ * Keep the order in the enum.
+ */
+enum scale {
+	SC_BYTE,
+	SC_KILOBYTE,
+	SC_MEGABYTE,
+	SC_GIGABYTE,
+	SC_TERABYTE,
+	SC_BIT,
+	SC_KILOBIT,
+	SC_MEGABIT,
+	SC_GIGABIT,
+	SC_TERABIT,
+	SC_AUTO		/* KEEP THIS LAST */
+};
+
+extern	double		 convert(const uintmax_t, const int);
+extern	const char	*get_helplist(void);
+extern	int		 get_scale(const char *);
+extern	const char	*get_string(const uintmax_t, const int);
+
+#endif		/* ! _CONVTBL_H_ */
Index: src/usr.bin/systat/ifcmds.c
diff -u /dev/null src/usr.bin/systat/ifcmds.c:1.1
--- /dev/null	Tue Aug  2 15:56:09 2016
+++ src/usr.bin/systat/ifcmds.c	Tue Aug  2 15:56:09 2016
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <tr...@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: releng/10.1/usr.bin/systat/ifcmds.c 247037 2013-02-20 14:19:09Z melifaro $
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ifcmds.c,v 1.1 2016/08/02 15:56:09 scole Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+#include "convtbl.h"
+
+
+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;
+
+	return (1);
+}
Index: src/usr.bin/systat/ifstat.c
diff -u /dev/null src/usr.bin/systat/ifstat.c:1.1
--- /dev/null	Tue Aug  2 15:56:09 2016
+++ src/usr.bin/systat/ifstat.c	Tue Aug  2 15:56:09 2016
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2003, Trent Nelson, <tr...@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: releng/10.1/usr.bin/systat/ifstat.c 247037 2013-02-20 14:19:09Z melifaro $
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ifstat.c,v 1.1 2016/08/02 15:56:09 scole Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#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;
+
+struct if_stat {
+	SLIST_ENTRY(if_stat)	 link;
+  	char	if_name[IF_NAMESIZE];
+	struct  ifdatareq 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_long	if_in_curpps;
+	u_long	if_out_curpps;
+	u_long	if_in_pps_peak;
+	u_long	if_out_pps_peak;
+	u_int	if_row;			/* Index into ifmib sysctl */
+	u_int	if_ypos;		/* 0 if not being displayed */
+	u_int	display;
+	u_int	match;
+};
+
+extern	 int curscale;
+extern	 char *matchline;
+extern	 int showpps;
+extern	 int needsort;
+
+static	 int needclear = 0;
+
+static	 void  right_align_string(struct if_stat *);
+static	 void  getifmibdata(const int, struct ifdatareq *);
+static	 void  sort_interface_list(void);
+static	 u_int getifnum(void);
+
+#define IFSTAT_ERR(n, s)	do {					\
+	putchar('\014');						\
+	closeifstat(wnd);						\
+	err((n), (s));							\
+} while (0)
+
+#define TOPLINE 5
+#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.ifdr_data.ifi_ipackets : ifp->if_mib.ifdr_data.ifi_ibytes)
+#define OUT_col4	(showpps ?					\
+	ifp->if_mib.ifdr_data.ifi_opackets : ifp->if_mib.ifdr_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, 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, -1, 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 || (ifp->match == 0) ||
+		    ifp->if_ypos > (u_int)(LINES - 3 - 1))
+			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 *)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);
+		p->match = 1;
+
+		/*
+		 * Initially, we only display interfaces that have
+		 * received some traffic.
+		 */
+		if (p->if_mib.ifdr_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	new_inp, new_outp, old_inp, old_outp = 0;
+
+	SLIST_FOREACH(ifp, &curlist, link) {
+		/*
+		 * Grab a copy of the old input/output values before we
+		 * call getifmibdata().
+		 */
+		old_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
+		old_outb = ifp->if_mib.ifdr_data.ifi_obytes;
+		old_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
+		old_outp = ifp->if_mib.ifdr_data.ifi_opackets;
+		TIMESPEC_TO_TIMEVAL(&ifp->tv_lastchanged, &ifp->if_mib.ifdr_data.ifi_lastchange);
+
+		(void)gettimeofday(&new_tv, NULL);
+		(void)getifmibdata(ifp->if_row, &ifp->if_mib);
+
+		new_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
+		new_outb = ifp->if_mib.ifdr_data.ifi_obytes;
+		new_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
+		new_outp = ifp->if_mib.ifdr_data.ifi_opackets;
+
+		/* Display interface if it's received some traffic. */
+		if (new_inb > 0 && old_inb == 0) {
+			ifp->display = 1;
+			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.
+ */
+static void
+right_align_string(struct if_stat *ifp)
+{
+	int	 str_len = 0, pad_len = 0;
+	char	*newstr = NULL, *ptr = NULL;
+
+	if (ifp == NULL || ifp->if_mib.ifdr_name == NULL)
+		return;
+	else {
+		/* string length + '\0' */
+		str_len = strlen(ifp->if_mib.ifdr_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.ifdr_name,
+			      str_len);
+	}
+
+	return;
+}
+
+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 = STARTING_ROW;
+	
+	SLIST_FOREACH(ifp, &curlist, link) {
+		if (matchline && !check_match(ifp->if_mib.ifdr_name))
+			ifp->match = 0;
+		else
+			ifp->match = 1;
+		if (ifp->display && ifp->match) {
+			ifp->if_ypos = y;
+			y += ROW_SPACING;
+		}
+	}
+	
+	needsort = 0;
+	needclear = 1;
+}
+
+static
+unsigned int
+getifnum(void)
+{
+	struct ifaddrs *ifaddrs = NULL;
+	struct ifaddrs *ifa = NULL;
+	int num = 0;
+
+	if (getifaddrs(&ifaddrs) == 0) {
+	  for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+	    if (ifa->ifa_addr &&
+		ifa->ifa_addr->sa_family == AF_LINK)
+	      num++;
+	  }
+  
+	  freeifaddrs(ifaddrs);
+	}
+
+	return num;
+}
+
+static void
+getifmibdata(int row, struct ifdatareq *data)
+{
+	struct ifaddrs *ifaddrs = NULL;
+	struct ifaddrs *ifa = NULL;
+	int found = 0;
+	int num = 0;
+
+	if (getifaddrs(&ifaddrs) != 0) {
+	  IFSTAT_ERR(2, "getifmibdata() error getting interface data");
+	  return;
+	}
+
+	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+	  if (ifa->ifa_addr &&
+	      ifa->ifa_addr->sa_family == AF_LINK) {
+	    num++;
+
+	    /*
+	     * expecting rows to start with 1 not 0, 
+	     * see freebsd "man ifmib"
+	     */
+	    if (num == row) {
+	      found = 1;
+	      data->ifdr_data = *(struct if_data *)ifa->ifa_data;
+	      strncpy(data->ifdr_name, ifa->ifa_name, IF_NAMESIZE);
+	      break;
+	    }
+	  }
+	}
+
+	freeifaddrs(ifaddrs);
+
+	if (!found) {
+	  IFSTAT_ERR(2, "getifmibdata() error finding row");
+	}
+}
+
+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();
+		if (needclear) {
+			werase(wnd);
+			labelifstat();
+			needclear = 0;
+		}
+	}
+
+	return (retval);
+}
+
+void
+ifstat_scale(char* args)
+{
+	cmdifstat("scale", args ? args : "");
+}
+
+void
+ifstat_pps(char* args)
+{
+	cmdifstat("pps", "");
+}
+
+void
+ifstat_match(char* args)
+{
+	cmdifstat("match", args ? args : "");
+
+	/*
+	 * force erase after match command because it is possible for
+	 * another command to be sent in the interval before the window
+	 * finishes redrawing completely.  That stale data remains in window
+	 * and never gets overwritten because there are fewer interfaces
+	 * being drawn on screen.  Only an issue for match command because
+	 * pps and scale don't change the number of interfaces being drawn.
+	 */
+	werase(wnd);
+	labelifstat();
+}

Reply via email to