Home | History | Annotate | Line # | Download | only in systat
      1  1.4  christos /*	$NetBSD: ifstat.c,v 1.4 2016/08/05 07:22:17 christos Exp $	*/
      2  1.2     scole 
      3  1.1     scole /*
      4  1.1     scole  * Copyright (c) 2003, Trent Nelson, <trent (at) arpa.com>.
      5  1.1     scole  * All rights reserved.
      6  1.1     scole  *
      7  1.1     scole  * Redistribution and use in source and binary forms, with or without
      8  1.1     scole  * modification, are permitted provided that the following conditions
      9  1.1     scole  * are met:
     10  1.1     scole  * 1. Redistributions of source code must retain the above copyright
     11  1.1     scole  *    notice, this list of conditions and the following disclaimer.
     12  1.1     scole  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1     scole  *    notice, this list of conditions and the following disclaimer in the
     14  1.1     scole  *    documentation and/or other materials provided with the distribution.
     15  1.1     scole  * 3. The name of the author may not be used to endorse or promote products
     16  1.1     scole  *    derived from this software without specific prior written permission.
     17  1.1     scole  *
     18  1.1     scole  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     19  1.1     scole  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  1.1     scole  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  1.1     scole  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  1.1     scole  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  1.1     scole  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24  1.1     scole  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTIFSTAT_ERRUPTION)
     25  1.1     scole  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  1.1     scole  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  1.1     scole  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  1.1     scole  * SUCH DAMAGE.
     29  1.1     scole  *
     30  1.1     scole  * $FreeBSD: releng/10.1/usr.bin/systat/ifstat.c 247037 2013-02-20 14:19:09Z melifaro $
     31  1.1     scole  */
     32  1.1     scole 
     33  1.1     scole #include <sys/cdefs.h>
     34  1.1     scole #ifndef lint
     35  1.4  christos __RCSID("$NetBSD: ifstat.c,v 1.4 2016/08/05 07:22:17 christos Exp $");
     36  1.1     scole #endif /* not lint */
     37  1.1     scole 
     38  1.1     scole #include <sys/types.h>
     39  1.1     scole #include <sys/socket.h>
     40  1.1     scole #include <sys/sysctl.h>
     41  1.1     scole #include <sys/time.h>
     42  1.1     scole #include <net/if.h>
     43  1.1     scole 
     44  1.1     scole #include <ifaddrs.h>
     45  1.1     scole #include <stdlib.h>
     46  1.1     scole #include <string.h>
     47  1.1     scole #include <err.h>
     48  1.1     scole #include <errno.h>
     49  1.1     scole #include <fnmatch.h>
     50  1.1     scole 
     51  1.1     scole #include "systat.h"
     52  1.1     scole #include "extern.h"
     53  1.1     scole #include "convtbl.h"
     54  1.1     scole 
     55  1.1     scole 				/* Column numbers */
     56  1.1     scole 
     57  1.1     scole #define C1	0		/*  0-19 */
     58  1.1     scole #define C2	20		/* 20-39 */
     59  1.1     scole #define C3	40		/* 40-59 */
     60  1.1     scole #define C4	60		/* 60-80 */
     61  1.1     scole #define C5	80		/* Used for label positioning. */
     62  1.1     scole 
     63  1.1     scole static const int col2 = C2;
     64  1.1     scole static const int col3 = C3;
     65  1.1     scole static const int col4 = C4;
     66  1.1     scole 
     67  1.1     scole SLIST_HEAD(, if_stat)		curlist;
     68  1.1     scole 
     69  1.1     scole struct if_stat {
     70  1.1     scole 	SLIST_ENTRY(if_stat)	 link;
     71  1.1     scole   	char	if_name[IF_NAMESIZE];
     72  1.1     scole 	struct  ifdatareq if_mib;
     73  1.1     scole 	struct	timeval tv;
     74  1.1     scole 	struct	timeval tv_lastchanged;
     75  1.1     scole 	u_long	if_in_curtraffic;
     76  1.1     scole 	u_long	if_out_curtraffic;
     77  1.1     scole 	u_long	if_in_traffic_peak;
     78  1.1     scole 	u_long	if_out_traffic_peak;
     79  1.1     scole 	u_long	if_in_curpps;
     80  1.1     scole 	u_long	if_out_curpps;
     81  1.1     scole 	u_long	if_in_pps_peak;
     82  1.1     scole 	u_long	if_out_pps_peak;
     83  1.1     scole 	u_int	if_row;			/* Index into ifmib sysctl */
     84  1.1     scole 	u_int	if_ypos;		/* 0 if not being displayed */
     85  1.1     scole 	u_int	display;
     86  1.1     scole 	u_int	match;
     87  1.1     scole };
     88  1.1     scole 
     89  1.1     scole extern	 int curscale;
     90  1.1     scole extern	 char *matchline;
     91  1.1     scole extern	 int showpps;
     92  1.1     scole extern	 int needsort;
     93  1.1     scole 
     94  1.1     scole static	 int needclear = 0;
     95  1.1     scole 
     96  1.1     scole static	 void  right_align_string(struct if_stat *);
     97  1.1     scole static	 void  getifmibdata(const int, struct ifdatareq *);
     98  1.1     scole static	 void  sort_interface_list(void);
     99  1.1     scole static	 u_int getifnum(void);
    100  1.1     scole 
    101  1.1     scole #define IFSTAT_ERR(n, s)	do {					\
    102  1.1     scole 	putchar('\014');						\
    103  1.1     scole 	closeifstat(wnd);						\
    104  1.1     scole 	err((n), (s));							\
    105  1.1     scole } while (0)
    106  1.1     scole 
    107  1.1     scole #define TOPLINE 5
    108  1.1     scole #define TOPLABEL \
    109  1.1     scole "      Interface           Traffic               Peak                Total"
    110  1.1     scole 
    111  1.1     scole #define STARTING_ROW	(TOPLINE + 1)
    112  1.1     scole #define ROW_SPACING	(3)
    113  1.1     scole 
    114  1.1     scole #define IN_col2		(showpps ? ifp->if_in_curpps : ifp->if_in_curtraffic)
    115  1.1     scole #define OUT_col2	(showpps ? ifp->if_out_curpps : ifp->if_out_curtraffic)
    116  1.1     scole #define IN_col3		(showpps ? \
    117  1.1     scole 		ifp->if_in_pps_peak : ifp->if_in_traffic_peak)
    118  1.1     scole #define OUT_col3	(showpps ? \
    119  1.1     scole 		ifp->if_out_pps_peak : ifp->if_out_traffic_peak)
    120  1.1     scole #define IN_col4		(showpps ?				\
    121  1.1     scole 	ifp->if_mib.ifdr_data.ifi_ipackets : ifp->if_mib.ifdr_data.ifi_ibytes)
    122  1.1     scole #define OUT_col4	(showpps ?					\
    123  1.1     scole 	ifp->if_mib.ifdr_data.ifi_opackets : ifp->if_mib.ifdr_data.ifi_obytes)
    124  1.1     scole 
    125  1.1     scole #define EMPTY_COLUMN 	"                    "
    126  1.1     scole #define CLEAR_COLUMN(y, x)	mvprintw((y), (x), "%20s", EMPTY_COLUMN);
    127  1.1     scole 
    128  1.1     scole #define DOPUTRATE(c, r, d)	do {					\
    129  1.1     scole 	CLEAR_COLUMN(r, c);						\
    130  1.1     scole 	if (showpps) {							\
    131  1.1     scole 		mvprintw(r, (c), "%10.3f %cp%s  ",			\
    132  1.1     scole 			 convert(d##_##c, curscale),			\
    133  1.1     scole 			 *get_string(d##_##c, curscale),		\
    134  1.1     scole 			 "/s");						\
    135  1.1     scole 	}								\
    136  1.1     scole 	else {								\
    137  1.1     scole 		mvprintw(r, (c), "%10.3f %s%s  ",			\
    138  1.1     scole 			 convert(d##_##c, curscale),			\
    139  1.1     scole 			 get_string(d##_##c, curscale),			\
    140  1.1     scole 			 "/s");						\
    141  1.1     scole 	}								\
    142  1.1     scole } while (0)
    143  1.1     scole 
    144  1.1     scole #define DOPUTTOTAL(c, r, d)	do {					\
    145  1.1     scole 	CLEAR_COLUMN((r), (c));						\
    146  1.1     scole 	if (showpps) {							\
    147  1.1     scole 		mvprintw((r), (c), "%12.3f %cp  ",			\
    148  1.1     scole 			 convert(d##_##c, SC_AUTO),			\
    149  1.1     scole 			 *get_string(d##_##c, SC_AUTO));		\
    150  1.1     scole 	}								\
    151  1.1     scole 	else {								\
    152  1.1     scole 		mvprintw((r), (c), "%12.3f %s  ",			\
    153  1.1     scole 			 convert(d##_##c, SC_AUTO),			\
    154  1.1     scole 			 get_string(d##_##c, SC_AUTO));			\
    155  1.1     scole 	}								\
    156  1.1     scole } while (0)
    157  1.1     scole 
    158  1.1     scole #define PUTRATE(c, r)	do {						\
    159  1.1     scole 	DOPUTRATE(c, (r), IN);						\
    160  1.1     scole 	DOPUTRATE(c, (r)+1, OUT);					\
    161  1.1     scole } while (0)
    162  1.1     scole 
    163  1.1     scole #define PUTTOTAL(c, r)	do {						\
    164  1.1     scole 	DOPUTTOTAL(c, (r), IN);						\
    165  1.1     scole 	DOPUTTOTAL(c, (r)+1, OUT);					\
    166  1.1     scole } while (0)
    167  1.1     scole 
    168  1.1     scole #define PUTNAME(p) do {							\
    169  1.1     scole 	mvprintw(p->if_ypos, 0, "%s", p->if_name);			\
    170  1.1     scole 	mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in");		\
    171  1.1     scole 	mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out");	\
    172  1.1     scole } while (0)
    173  1.1     scole 
    174  1.1     scole WINDOW *
    175  1.1     scole openifstat(void)
    176  1.1     scole {
    177  1.1     scole 	return (subwin(stdscr, -1, 0, 5, 0));
    178  1.1     scole }
    179  1.1     scole 
    180  1.1     scole void
    181  1.1     scole closeifstat(WINDOW *w)
    182  1.1     scole {
    183  1.1     scole 	struct if_stat	*node = NULL;
    184  1.1     scole 
    185  1.1     scole 	while (!SLIST_EMPTY(&curlist)) {
    186  1.1     scole 		node = SLIST_FIRST(&curlist);
    187  1.1     scole 		SLIST_REMOVE_HEAD(&curlist, link);
    188  1.1     scole 		free(node);
    189  1.1     scole 	}
    190  1.1     scole 
    191  1.1     scole 	if (w != NULL) {
    192  1.1     scole 		wclear(w);
    193  1.1     scole 		wrefresh(w);
    194  1.1     scole 		delwin(w);
    195  1.1     scole 	}
    196  1.1     scole 
    197  1.1     scole 	return;
    198  1.1     scole }
    199  1.1     scole 
    200  1.1     scole void
    201  1.1     scole labelifstat(void)
    202  1.1     scole {
    203  1.1     scole 
    204  1.1     scole 	wmove(wnd, TOPLINE, 0);
    205  1.1     scole 	wclrtoeol(wnd);
    206  1.1     scole 	mvprintw(TOPLINE, 0, "%s", TOPLABEL);
    207  1.1     scole 
    208  1.1     scole 	return;
    209  1.1     scole }
    210  1.1     scole 
    211  1.1     scole void
    212  1.1     scole showifstat(void)
    213  1.1     scole {
    214  1.1     scole 	struct	if_stat *ifp = NULL;
    215  1.1     scole 
    216  1.1     scole 	SLIST_FOREACH(ifp, &curlist, link) {
    217  1.1     scole 		if (ifp->display == 0 || (ifp->match == 0) ||
    218  1.1     scole 		    ifp->if_ypos > (u_int)(LINES - 3 - 1))
    219  1.1     scole 			continue;
    220  1.1     scole 		PUTNAME(ifp);
    221  1.1     scole 		PUTRATE(col2, ifp->if_ypos);
    222  1.1     scole 		PUTRATE(col3, ifp->if_ypos);
    223  1.1     scole 		PUTTOTAL(col4, ifp->if_ypos);
    224  1.1     scole 	}
    225  1.1     scole 
    226  1.1     scole 	return;
    227  1.1     scole }
    228  1.1     scole 
    229  1.1     scole int
    230  1.1     scole initifstat(void)
    231  1.1     scole {
    232  1.1     scole 	struct   if_stat *p = NULL;
    233  1.1     scole 	u_int	 n = 0, i = 0;
    234  1.1     scole 
    235  1.1     scole 	n = getifnum();
    236  1.1     scole 	if (n <= 0)
    237  1.1     scole 		return (-1);
    238  1.1     scole 
    239  1.1     scole 	SLIST_INIT(&curlist);
    240  1.1     scole 
    241  1.1     scole 	for (i = 0; i < n; i++) {
    242  1.1     scole 		p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
    243  1.1     scole 		if (p == NULL)
    244  1.1     scole 			IFSTAT_ERR(1, "out of memory");
    245  1.1     scole 		SLIST_INSERT_HEAD(&curlist, p, link);
    246  1.1     scole 		p->if_row = i+1;
    247  1.1     scole 		getifmibdata(p->if_row, &p->if_mib);
    248  1.1     scole 		right_align_string(p);
    249  1.1     scole 		p->match = 1;
    250  1.1     scole 
    251  1.1     scole 		/*
    252  1.1     scole 		 * Initially, we only display interfaces that have
    253  1.1     scole 		 * received some traffic.
    254  1.1     scole 		 */
    255  1.1     scole 		if (p->if_mib.ifdr_data.ifi_ibytes != 0)
    256  1.1     scole 			p->display = 1;
    257  1.1     scole 	}
    258  1.1     scole 
    259  1.1     scole 	sort_interface_list();
    260  1.1     scole 
    261  1.1     scole 	return (1);
    262  1.1     scole }
    263  1.1     scole 
    264  1.1     scole void
    265  1.1     scole fetchifstat(void)
    266  1.1     scole {
    267  1.1     scole 	struct	if_stat *ifp = NULL;
    268  1.1     scole 	struct	timeval tv, new_tv, old_tv;
    269  1.1     scole 	double	elapsed = 0.0;
    270  1.1     scole 	u_int	new_inb, new_outb, old_inb, old_outb = 0;
    271  1.1     scole 	u_int	new_inp, new_outp, old_inp, old_outp = 0;
    272  1.1     scole 
    273  1.1     scole 	SLIST_FOREACH(ifp, &curlist, link) {
    274  1.1     scole 		/*
    275  1.1     scole 		 * Grab a copy of the old input/output values before we
    276  1.1     scole 		 * call getifmibdata().
    277  1.1     scole 		 */
    278  1.1     scole 		old_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
    279  1.1     scole 		old_outb = ifp->if_mib.ifdr_data.ifi_obytes;
    280  1.1     scole 		old_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
    281  1.1     scole 		old_outp = ifp->if_mib.ifdr_data.ifi_opackets;
    282  1.1     scole 		TIMESPEC_TO_TIMEVAL(&ifp->tv_lastchanged, &ifp->if_mib.ifdr_data.ifi_lastchange);
    283  1.1     scole 
    284  1.1     scole 		(void)gettimeofday(&new_tv, NULL);
    285  1.1     scole 		(void)getifmibdata(ifp->if_row, &ifp->if_mib);
    286  1.1     scole 
    287  1.1     scole 		new_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
    288  1.1     scole 		new_outb = ifp->if_mib.ifdr_data.ifi_obytes;
    289  1.1     scole 		new_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
    290  1.1     scole 		new_outp = ifp->if_mib.ifdr_data.ifi_opackets;
    291  1.1     scole 
    292  1.1     scole 		/* Display interface if it's received some traffic. */
    293  1.1     scole 		if (new_inb > 0 && old_inb == 0) {
    294  1.1     scole 			ifp->display = 1;
    295  1.1     scole 			needsort = 1;
    296  1.1     scole 		}
    297  1.1     scole 
    298  1.1     scole 		/*
    299  1.1     scole 		 * The rest is pretty trivial.  Calculate the new values
    300  1.1     scole 		 * for our current traffic rates, and while we're there,
    301  1.1     scole 		 * see if we have new peak rates.
    302  1.1     scole 		 */
    303  1.1     scole 		old_tv = ifp->tv;
    304  1.1     scole 		timersub(&new_tv, &old_tv, &tv);
    305  1.1     scole 		elapsed = tv.tv_sec + (tv.tv_usec * 1e-6);
    306  1.1     scole 
    307  1.1     scole 		ifp->if_in_curtraffic = new_inb - old_inb;
    308  1.1     scole 		ifp->if_out_curtraffic = new_outb - old_outb;
    309  1.1     scole 
    310  1.1     scole 		ifp->if_in_curpps = new_inp - old_inp;
    311  1.1     scole 		ifp->if_out_curpps = new_outp - old_outp;
    312  1.1     scole 
    313  1.1     scole 		/*
    314  1.1     scole 		 * Rather than divide by the time specified on the comm-
    315  1.1     scole 		 * and line, we divide by ``elapsed'' as this is likely
    316  1.1     scole 		 * to be more accurate.
    317  1.1     scole 		 */
    318  1.1     scole 		ifp->if_in_curtraffic /= elapsed;
    319  1.1     scole 		ifp->if_out_curtraffic /= elapsed;
    320  1.1     scole 		ifp->if_in_curpps /= elapsed;
    321  1.1     scole 		ifp->if_out_curpps /= elapsed;
    322  1.1     scole 
    323  1.1     scole 		if (ifp->if_in_curtraffic > ifp->if_in_traffic_peak)
    324  1.1     scole 			ifp->if_in_traffic_peak = ifp->if_in_curtraffic;
    325  1.1     scole 
    326  1.1     scole 		if (ifp->if_out_curtraffic > ifp->if_out_traffic_peak)
    327  1.1     scole 			ifp->if_out_traffic_peak = ifp->if_out_curtraffic;
    328  1.1     scole 
    329  1.1     scole 		if (ifp->if_in_curpps > ifp->if_in_pps_peak)
    330  1.1     scole 			ifp->if_in_pps_peak = ifp->if_in_curpps;
    331  1.1     scole 
    332  1.1     scole 		if (ifp->if_out_curpps > ifp->if_out_pps_peak)
    333  1.1     scole 			ifp->if_out_pps_peak = ifp->if_out_curpps;
    334  1.1     scole 
    335  1.1     scole 		ifp->tv.tv_sec = new_tv.tv_sec;
    336  1.1     scole 		ifp->tv.tv_usec = new_tv.tv_usec;
    337  1.1     scole 
    338  1.1     scole 	}
    339  1.1     scole 
    340  1.1     scole 	if (needsort)
    341  1.1     scole 		sort_interface_list();
    342  1.1     scole 
    343  1.1     scole 	return;
    344  1.1     scole }
    345  1.1     scole 
    346  1.1     scole /*
    347  1.1     scole  * We want to right justify our interface names against the first column
    348  1.1     scole  * (first sixteen or so characters), so we need to do some alignment.
    349  1.1     scole  */
    350  1.1     scole static void
    351  1.1     scole right_align_string(struct if_stat *ifp)
    352  1.1     scole {
    353  1.3  jakllsch 	if (ifp == NULL || ifp->if_mib.ifdr_name[0] == '\0')
    354  1.1     scole 		return;
    355  1.1     scole 
    356  1.4  christos 	snprintf(ifp->if_name, IF_NAMESIZE, "%*s", IF_NAMESIZE - 1,
    357  1.4  christos 	    ifp->if_mib.ifdr_name);
    358  1.1     scole }
    359  1.1     scole 
    360  1.1     scole static int
    361  1.1     scole check_match(const char *ifname)
    362  1.1     scole {
    363  1.1     scole 	char *p = matchline, *c, t;
    364  1.1     scole 	int match = 0, mlen;
    365  1.1     scole 
    366  1.1     scole 	if (matchline == NULL)
    367  1.1     scole 		return (0);
    368  1.1     scole 
    369  1.1     scole 	/* Strip leading whitespaces */
    370  1.1     scole 	while (*p == ' ')
    371  1.1     scole 		p ++;
    372  1.1     scole 
    373  1.1     scole 	c = p;
    374  1.1     scole 	while ((mlen = strcspn(c, " ;,")) != 0) {
    375  1.1     scole 		p = c + mlen;
    376  1.1     scole 		t = *p;
    377  1.1     scole 		if (p - c > 0) {
    378  1.1     scole 			*p = '\0';
    379  1.1     scole 			if (fnmatch(c, ifname, FNM_CASEFOLD) == 0) {
    380  1.1     scole 				*p = t;
    381  1.1     scole 				return (1);
    382  1.1     scole 			}
    383  1.1     scole 			*p = t;
    384  1.1     scole 			c = p + strspn(p, " ;,");
    385  1.1     scole 		}
    386  1.1     scole 		else {
    387  1.1     scole 			c = p + strspn(p, " ;,");
    388  1.1     scole 		}
    389  1.1     scole 	}
    390  1.1     scole 
    391  1.1     scole 	return (match);
    392  1.1     scole }
    393  1.1     scole 
    394  1.1     scole /*
    395  1.1     scole  * This function iterates through our list of interfaces, identifying
    396  1.1     scole  * those that are to be displayed (ifp->display = 1).  For each interf-
    397  1.1     scole  * rface that we're displaying, we generate an appropriate position for
    398  1.1     scole  * it on the screen (ifp->if_ypos).
    399  1.1     scole  *
    400  1.1     scole  * This function is called any time a change is made to an interface's
    401  1.1     scole  * ``display'' state.
    402  1.1     scole  */
    403  1.1     scole void
    404  1.1     scole sort_interface_list(void)
    405  1.1     scole {
    406  1.1     scole 	struct	if_stat	*ifp = NULL;
    407  1.1     scole 	u_int	y = STARTING_ROW;
    408  1.1     scole 
    409  1.1     scole 	SLIST_FOREACH(ifp, &curlist, link) {
    410  1.1     scole 		if (matchline && !check_match(ifp->if_mib.ifdr_name))
    411  1.1     scole 			ifp->match = 0;
    412  1.1     scole 		else
    413  1.1     scole 			ifp->match = 1;
    414  1.1     scole 		if (ifp->display && ifp->match) {
    415  1.1     scole 			ifp->if_ypos = y;
    416  1.1     scole 			y += ROW_SPACING;
    417  1.1     scole 		}
    418  1.1     scole 	}
    419  1.1     scole 
    420  1.1     scole 	needsort = 0;
    421  1.1     scole 	needclear = 1;
    422  1.1     scole }
    423  1.1     scole 
    424  1.1     scole static
    425  1.1     scole unsigned int
    426  1.1     scole getifnum(void)
    427  1.1     scole {
    428  1.1     scole 	struct ifaddrs *ifaddrs = NULL;
    429  1.1     scole 	struct ifaddrs *ifa = NULL;
    430  1.1     scole 	int num = 0;
    431  1.1     scole 
    432  1.1     scole 	if (getifaddrs(&ifaddrs) == 0) {
    433  1.1     scole 	  for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
    434  1.1     scole 	    if (ifa->ifa_addr &&
    435  1.1     scole 		ifa->ifa_addr->sa_family == AF_LINK)
    436  1.1     scole 	      num++;
    437  1.1     scole 	  }
    438  1.1     scole 
    439  1.1     scole 	  freeifaddrs(ifaddrs);
    440  1.1     scole 	}
    441  1.1     scole 
    442  1.1     scole 	return num;
    443  1.1     scole }
    444  1.1     scole 
    445  1.1     scole static void
    446  1.1     scole getifmibdata(int row, struct ifdatareq *data)
    447  1.1     scole {
    448  1.1     scole 	struct ifaddrs *ifaddrs = NULL;
    449  1.1     scole 	struct ifaddrs *ifa = NULL;
    450  1.1     scole 	int found = 0;
    451  1.1     scole 	int num = 0;
    452  1.1     scole 
    453  1.1     scole 	if (getifaddrs(&ifaddrs) != 0) {
    454  1.1     scole 	  IFSTAT_ERR(2, "getifmibdata() error getting interface data");
    455  1.1     scole 	  return;
    456  1.1     scole 	}
    457  1.1     scole 
    458  1.1     scole 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
    459  1.1     scole 	  if (ifa->ifa_addr &&
    460  1.1     scole 	      ifa->ifa_addr->sa_family == AF_LINK) {
    461  1.1     scole 	    num++;
    462  1.1     scole 
    463  1.1     scole 	    /*
    464  1.1     scole 	     * expecting rows to start with 1 not 0,
    465  1.1     scole 	     * see freebsd "man ifmib"
    466  1.1     scole 	     */
    467  1.1     scole 	    if (num == row) {
    468  1.1     scole 	      found = 1;
    469  1.1     scole 	      data->ifdr_data = *(struct if_data *)ifa->ifa_data;
    470  1.1     scole 	      strncpy(data->ifdr_name, ifa->ifa_name, IF_NAMESIZE);
    471  1.1     scole 	      break;
    472  1.1     scole 	    }
    473  1.1     scole 	  }
    474  1.1     scole 	}
    475  1.1     scole 
    476  1.1     scole 	freeifaddrs(ifaddrs);
    477  1.1     scole 
    478  1.1     scole 	if (!found) {
    479  1.1     scole 	  IFSTAT_ERR(2, "getifmibdata() error finding row");
    480  1.1     scole 	}
    481  1.1     scole }
    482  1.1     scole 
    483  1.1     scole int
    484  1.1     scole cmdifstat(const char *cmd, const char *args)
    485  1.1     scole {
    486  1.1     scole 	int	retval = 0;
    487  1.1     scole 
    488  1.1     scole 	retval = ifcmd(cmd, args);
    489  1.1     scole 	/* ifcmd() returns 1 on success */
    490  1.1     scole 	if (retval == 1) {
    491  1.1     scole 		showifstat();
    492  1.1     scole 		refresh();
    493  1.1     scole 		if (needclear) {
    494  1.1     scole 			werase(wnd);
    495  1.1     scole 			labelifstat();
    496  1.1     scole 			needclear = 0;
    497  1.1     scole 		}
    498  1.1     scole 	}
    499  1.1     scole 
    500  1.1     scole 	return (retval);
    501  1.1     scole }
    502  1.1     scole 
    503  1.1     scole void
    504  1.1     scole ifstat_scale(char* args)
    505  1.1     scole {
    506  1.1     scole 	cmdifstat("scale", args ? args : "");
    507  1.1     scole }
    508  1.1     scole 
    509  1.1     scole void
    510  1.1     scole ifstat_pps(char* args)
    511  1.1     scole {
    512  1.1     scole 	cmdifstat("pps", "");
    513  1.1     scole }
    514  1.1     scole 
    515  1.1     scole void
    516  1.1     scole ifstat_match(char* args)
    517  1.1     scole {
    518  1.1     scole 	cmdifstat("match", args ? args : "");
    519  1.1     scole 
    520  1.1     scole 	/*
    521  1.1     scole 	 * force erase after match command because it is possible for
    522  1.1     scole 	 * another command to be sent in the interval before the window
    523  1.1     scole 	 * finishes redrawing completely.  That stale data remains in window
    524  1.1     scole 	 * and never gets overwritten because there are fewer interfaces
    525  1.1     scole 	 * being drawn on screen.  Only an issue for match command because
    526  1.1     scole 	 * pps and scale don't change the number of interfaces being drawn.
    527  1.1     scole 	 */
    528  1.1     scole 	werase(wnd);
    529  1.1     scole 	labelifstat();
    530  1.1     scole }
    531