NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/51204: add



The following reply was made to PR bin/51204; it has been noted by GNATS.

From: scole_mail%gmx.com@localhost
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: bin/51204: add
Date: Tue, 31 May 2016 11:24:34 -0400

 Sorry about the subject line, that was supposed to be
 "add ifstat to systat command"
 
 Here is a patch:
 
 --- /dev/null	2016-05-31 11:09:13.000000000 -0400
 +++ convtbl.c	2014-11-11 15:03:22.000000000 -0500
 @@ -0,0 +1,150 @@
 +/*
 + * Copyright (c) 2003, Trent Nelson, <trent%arpa.com@localhost>.
 + * 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/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);
 +}
 --- /dev/null	2016-05-31 11:09:13.000000000 -0400
 +++ convtbl.h	2014-11-11 15:03:22.000000000 -0500
 @@ -0,0 +1,59 @@
 +/*
 + * Copyright (c) 2003, Trent Nelson, <trent%arpa.com@localhost>.
 + * 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_ */
 --- /dev/null	2016-05-31 11:09:13.000000000 -0400
 +++ ifcmds.c	2016-05-31 10:30:20.000000000 -0400
 @@ -0,0 +1,77 @@
 +/*
 + * Copyright (c) 2003, Trent Nelson, <trent%arpa.com@localhost>.
 + * 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/types.h>
 +
 +#include "systat.h"
 +#include "extern.h"
 +#include "convtbl.h"
 +
 +#include <stdlib.h>
 +#include <string.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);
 +}
 --- /dev/null	2016-05-31 11:09:13.000000000 -0400
 +++ ifstat.c	2016-05-31 10:57:57.000000000 -0400
 @@ -0,0 +1,539 @@
 +/*
 + * Copyright (c) 2003, Trent Nelson, <trent%arpa.com@localhost>.
 + * 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/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();
 +}
 Index: Makefile
 ===================================================================
 RCS file: /cvsroot/src/usr.bin/systat/Makefile,v
 retrieving revision 1.38
 diff -b -u -r1.38 Makefile
 --- Makefile	23 Jan 2016 21:22:50 -0000	1.38
 +++ Makefile	31 May 2016 15:09:13 -0000
 @@ -14,7 +14,7 @@
  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
 +	ifcmds.c convtbl.c ifstat.c syscall.c
  DPADD=	${LIBCURSES} ${LIBTERMINFO} ${LIBM} ${LIBKVM}
  LDADD=	-lutil -lcurses -lterminfo -lm -lkvm
  BINGRP=	kmem
 Index: cmds.c
 ===================================================================
 RCS file: /cvsroot/src/usr.bin/systat/cmds.c,v
 retrieving revision 1.28
 diff -b -u -r1.28 cmds.c
 --- cmds.c	4 Nov 2004 07:18:47 -0000	1.28
 +++ cmds.c	31 May 2016 15:09:13 -0000
 @@ -152,3 +152,15 @@
  {
  	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: cmdtab.c
 ===================================================================
 RCS file: /cvsroot/src/usr.bin/systat/cmdtab.c,v
 retrieving revision 1.24
 diff -b -u -r1.24 cmdtab.c
 --- cmdtab.c	6 Jan 2012 14:08:08 -0000	1.24
 +++ cmdtab.c	31 May 2016 15:09:13 -0000
 @@ -69,6 +69,13 @@
  	{ .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 @@
  	{ "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: extern.h
 ===================================================================
 RCS file: /cvsroot/src/usr.bin/systat/extern.h,v
 retrieving revision 1.44
 diff -b -u -r1.44 extern.h
 --- extern.h	23 Aug 2015 18:33:15 -0000	1.44
 +++ extern.h	31 May 2016 15:09:13 -0000
 @@ -75,6 +75,7 @@
  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	 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	 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_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 @@
  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 @@
  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	*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: systat.1
 ===================================================================
 RCS file: /cvsroot/src/usr.bin/systat/systat.1,v
 retrieving revision 1.44
 diff -b -u -r1.44 systat.1
 --- systat.1	12 Mar 2016 02:39:01 -0000	1.44
 +++ systat.1	31 May 2016 15:09:13 -0000
 @@ -73,7 +73,7 @@
  .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 @@
  .Ic all ,
  .Ic bufcache ,
  .Ic df ,
 +.Ic ifstat ,
  .Ic inet.icmp ,
  .Ic inet.ip ,
  .Ic inet.tcp ,
 @@ -226,6 +227,54 @@
  .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
 


Home | Main Index | Thread Index | Old Index