commit fece505991314d54fa4ed5279e8057940a70c0ce
Author: sin <sin@2f30.org>
Date: Thu, 11 Feb 2016 17:30:45 +0000
Initial commit
Diffstat:
A | Makefile | | | 29 | +++++++++++++++++++++++++++++ |
A | arg.h | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | sbm.1 | | | 23 | +++++++++++++++++++++++ |
A | sbm.c | | | 185 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 302 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,29 @@
+VERSION = 0.1
+
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/man
+
+CFLAGS = -Wall
+
+OBJ = sbm.o
+BIN = sbm
+
+all: $(BIN)
+
+$(BIN): $(OBJ)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(OBJ) $(LDFLAGS)
+
+sbm.o: arg.h
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
+ mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+ cp -f $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1
+
+uninstall:
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
+ rm -f $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1
+
+clean:
+ rm -f $(BIN) $(OBJ)
diff --git a/arg.h b/arg.h
@@ -0,0 +1,65 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define LNGARG() &argv[0][0]
+
+#endif
diff --git a/sbm.1 b/sbm.1
@@ -0,0 +1,23 @@
+.Dd Feb 11, 2016
+.Dt SBM 1
+.Os
+.Sh NAME
+.Nm sbm
+.Nd simple bandwidth monitor
+.Sh SYNOPSIS
+.Nm sbm
+.Op Fl i Ar interface
+.Op Fl d Ar delay
+.Sh DESCRIPTION
+.Nm
+is a simple bandwidth monitor for OpenBSD.
+.Sh OPTIONS
+.Bl -tag -width "-i interface"
+.It Fl i Ar interface
+Monitor the selected interface. If not provided, the first
+enumerated interface will be used.
+.It Fl d Ar delay
+Specify the sampling delay in milliseconds. Defaults to 1 second.
+.El
+.Sh AUTHORS
+.An Dimitris Papastamos Aq Mt sin@2f30.org
diff --git a/sbm.c b/sbm.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016 Dimitris Papastamos <sin@2f30.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <ifaddrs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arg.h"
+
+char *argv0;
+
+void
+scan(char *ifname)
+{
+ struct ifaddrs *ifas, *ifa;
+ int found = 0;
+
+ if (getifaddrs(&ifas) == -1)
+ err(1, "getifaddrs");
+ if (*ifname) {
+ for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
+ if (!strncmp(ifname, ifa->ifa_name, IFNAMSIZ)) {
+ found = 1;
+ break;
+ }
+ }
+ } else {
+ for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_flags & IFF_LOOPBACK)
+ continue;
+ if (ifa->ifa_flags & IFF_RUNNING) {
+ if (ifa->ifa_flags & IFF_UP) {
+ strlcpy(ifname, ifa->ifa_name, IFNAMSIZ);
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+ freeifaddrs(ifas);
+ if (!found)
+ errx(1, "no usable interface found");
+}
+
+void
+sample(char *ifname, unsigned long long *rx, unsigned long long *tx)
+{
+ int mib[6];
+ char *buf, *next;
+ size_t size;
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl = NULL;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0)
+ errx(1, "sysctl failed");
+ buf = malloc(size);
+ if (!buf)
+ err(1, "malloc");
+ if (sysctl(mib, 6, buf, &size, NULL, 0) < 0)
+ errx(1, "sysctl failed");
+ for (next = buf; next < buf + size; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_NEWADDR) {
+ if (ifm->ifm_flags & IFF_UP) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+ if (strncmp(sdl->sdl_data, ifname, sdl->sdl_nlen) != 0)
+ continue;
+ *rx = ifm->ifm_data.ifi_ibytes;
+ *tx = ifm->ifm_data.ifi_obytes;
+ break;
+ }
+ }
+ }
+ free(buf);
+ if (!sdl)
+ errx(1, "interface %s cannot be sampled", ifname);
+}
+
+void
+scale(char **suffix, unsigned long long *bits)
+{
+ static char *suffixes[] = { "bps", "Kbps", "Mbps" };
+
+ *suffix = suffixes[0];
+ if (*bits >= 1000 && *bits < 1000 * 1000) {
+ *suffix = suffixes[1];
+ *bits /= 1000;
+ } else if (*bits >= 1000 * 1000) {
+ *suffix = suffixes[2];
+ *bits /= 1000 * 1000;
+ }
+}
+
+void
+print(char *ifname, unsigned long long rxbits, unsigned long long txbits)
+{
+ char *rxsuffix, *txsuffix;
+
+ scale(&rxsuffix, &rxbits);
+ scale(&txsuffix, &txbits);
+ printf("%s: down %lld %s, up %lld %s\n",
+ ifname, rxbits, rxsuffix, txbits, txsuffix);
+}
+
+void
+loop(char *ifname, long long delay)
+{
+ unsigned long long oldrxbytes, rxbytes;
+ unsigned long long oldtxbytes, txbytes;
+
+ sample(ifname, &oldrxbytes, &oldtxbytes);
+ for (;;) {
+ sample(ifname, &rxbytes, &txbytes);
+ print(ifname,
+ (rxbytes - oldrxbytes) * 8,
+ (txbytes - oldtxbytes) * 8);
+ oldrxbytes = rxbytes;
+ oldtxbytes = txbytes;
+ usleep(delay * 1000);
+ }
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-i interface] [-d delay]\n", argv0);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char ifname[IFNAMSIZ] = "", *arg;
+ const char *errstr;
+ long long delay = 1000;
+
+ ARGBEGIN {
+ case 'i':
+ strlcpy(ifname, EARGF(usage()), sizeof(ifname));
+ break;
+ case 'd':
+ arg = EARGF(usage());
+ delay = strtonum(arg, 100, 60000, &errstr);
+ if (errstr)
+ errx(1, "%s: %s", arg, errstr);
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ scan(ifname);
+ loop(ifname, delay);
+ return 0;
+}