PR bin/51204

Add ifstat command to systat.

Imported from FreeBSD
This commit is contained in:
scole 2016-08-02 15:56:09 +00:00
parent 523cea2878
commit bd7662dc4d
9 changed files with 938 additions and 12 deletions

View File

@ -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

View File

@ -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');
}

View File

@ -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 },

157
usr.bin/systat/convtbl.c Normal file
View File

@ -0,0 +1,157 @@
/*
* 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: 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);
}

59
usr.bin/systat/convtbl.h Normal file
View File

@ -0,0 +1,59 @@
/*
* 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: 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_ */

View File

@ -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 *, size_t, const char *);
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);

83
usr.bin/systat/ifcmds.c Normal file
View File

@ -0,0 +1,83 @@
/*
* 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: 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);
}

544
usr.bin/systat/ifstat.c Normal file
View File

@ -0,0 +1,544 @@
/*
* 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: 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();
}

View File

@ -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