/* $Id$ */ /* * Copyright (c) 2006 Dimitri Sokolyuk * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include struct data { SIMPLEQ_ENTRY(data) link; char name[IFNAMSIZ]; u_int flags; struct if_data data; struct if_data odata; WINDOW *win; WINDOW *info, *infobox; WINDOW *plot, *plotbox; int plotwidth; int plotheight; u_int (*cur)[2]; u_int max[2]; u_int maxboth; } *datap; SIMPLEQ_HEAD(, data) head; int hascolors; extern int LINES, COLS; int dieflag = 0; void initscreen(int); void display(void); void updatedata(int, int); int findif(int, int, char **); int readdata(int, char *, void *); void mvwprintw2(WINDOW *, int, int, char *, double); void die(int); __dead void usage(void); int main(int argc, char **argv) { int sock; int num; int ch; int del = 2; while ((ch = getopt(argc, argv, "s:h")) != -1) { switch (ch) { case 's': del = atoi(optarg); break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; signal(SIGINT, die); sock = socket(AF_INET, SOCK_DGRAM, 0); num = findif(sock, argc, argv); if (num == 0) usage(); initscreen(num); curs_set(0); while (!dieflag) { updatedata(sock, del); display(); doupdate(); sleep(del); } close(sock); curs_set(1); endwin(); return 0; } void initscreen(int n) { int winh; int i = 0; #define INFOW 16 #define PLOTW (COLS - INFOW) initscr(); if ((hascolors = has_colors())) start_color(); init_pair(1, COLOR_GREEN, COLOR_BLACK); init_pair(2, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_BLACK, COLOR_GREEN); init_pair(4, COLOR_BLACK, COLOR_RED); init_pair(5, COLOR_BLACK, COLOR_YELLOW); winh = LINES / n; SIMPLEQ_FOREACH(datap, &head, link) { datap->win = newwin(winh, COLS, (i++) * LINES / n, 0); datap->infobox = derwin(datap->win, winh, INFOW, 0, 0); box(datap->infobox, 0, 0); mvwprintw(datap->infobox, 0, 1, "[%s]", datap->name); datap->info = derwin(datap->win, winh - 2, INFOW - 2, 1, 1); datap->plotbox = derwin(datap->win, winh, PLOTW, 0, INFOW); box(datap->plotbox, 0, 0); wmove(datap->plotbox, 0, 1); waddch(datap->plotbox, '['); wattron(datap->plotbox, COLOR_PAIR(1)); waddstr(datap->plotbox, "dn"); wattroff(datap->plotbox, COLOR_PAIR(1)); waddch(datap->plotbox, '/'); wattron(datap->plotbox, COLOR_PAIR(2)); waddstr(datap->plotbox, "up"); wattroff(datap->plotbox, COLOR_PAIR(2)); waddch(datap->plotbox, ']'); datap->plot = derwin(datap->win, winh - 2, PLOTW - 2, 1, INFOW + 1); datap->plotwidth = PLOTW - 2; datap->plotheight = LINES / n - 2; datap->cur = calloc(datap->plotheight, sizeof(*datap->cur)); wnoutrefresh(datap->win); } } void mvwprintw2(WINDOW *w, int a, int b, char *c, double n) { int i; mvwprintw(w, a, b, "%s", c); for (i = 0; n > 1024; ++i, n /= 1024) ; wprintw(w, "%8.2f%c", n, " kMG"[i]); } void display(void) { int i, lenin, lenout, pos; int symin, symout; SIMPLEQ_FOREACH(datap, &head, link) { mvwprintw2(datap->info, 0, 0, "dn ", (*datap->cur)[0]); mvwprintw2(datap->info, 1, 0, "dnmax", datap->max[0]); mvwprintw2(datap->info, 2, 0, "up ", (*datap->cur)[1]); mvwprintw2(datap->info, 3, 0, "upmax", datap->max[1]); wnoutrefresh(datap->info); symin = hascolors ? ' ' : 'I'; symout = hascolors ? ' ' : 'O'; werase(datap->plot); for (i = 0; i < datap->plotheight; i++) { lenin = datap->maxboth == 0 ? 0 : datap->cur[i][0] * datap->plotwidth / datap->maxboth; lenout = datap->maxboth == 0 ? 0 : datap->cur[i][1] * datap->plotwidth / datap->maxboth; pos = datap->plotheight - i - 1; if (lenin > lenout) { wattron(datap->plot, COLOR_PAIR(3)); mvwhline(datap->plot, pos, 0, symin, lenin); wattroff(datap->plot, COLOR_PAIR(3)); wattron(datap->plot, COLOR_PAIR(4)); mvwhline(datap->plot, pos, 0, symout, lenout); wattroff(datap->plot, COLOR_PAIR(4)); } else if (lenin < lenout) { /* ACS_BLOCK */ wattron(datap->plot, COLOR_PAIR(4)); mvwhline(datap->plot, pos, 0, symout, lenout); wattroff(datap->plot, COLOR_PAIR(4)); wattron(datap->plot, COLOR_PAIR(3)); mvwhline(datap->plot, pos, 0, symin, lenin); wattroff(datap->plot, COLOR_PAIR(3)); } else { wattron(datap->plot, COLOR_PAIR(5)); mvwhline(datap->plot, pos, 0, symin, lenin); wattroff(datap->plot, COLOR_PAIR(5)); } } wnoutrefresh(datap->plot); } } void updatedata(int sock, int del) { int i; SIMPLEQ_FOREACH(datap, &head, link) { memmove(&datap->odata, &datap->data, sizeof(datap->odata)); readdata(sock, datap->name, &datap->data); memmove(datap->cur[1], datap->cur[0], sizeof(*datap->cur) * (datap->plotheight - 1)); (*datap->cur)[0] = (datap->data.ifi_ibytes - datap->odata.ifi_ibytes) / del; (*datap->cur)[1] = (datap->data.ifi_obytes - datap->odata.ifi_obytes) / del; memset(datap->max, 0, sizeof(datap->max)); datap->maxboth = 0; for (i = 0; i < datap->plotheight; i++) { if (datap->cur[i][0] > datap->max[0]) datap->max[0] = datap->cur[i][0]; if (datap->cur[i][1] > datap->max[1]) datap->max[1] = datap->cur[i][1]; if (datap->cur[i][0] > datap->maxboth) datap->maxboth = datap->cur[i][0]; if (datap->cur[i][1] > datap->maxboth) datap->maxboth = datap->cur[i][1]; } } } int findif(int sock, int argc, char **argv) { struct ifaddrs *ifap, *ifa; char *oname = NULL; int ret = 0; int i, flag = 0; SIMPLEQ_INIT(&head); getifaddrs(&ifap); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { struct if_data ifd; if ((oname != NULL && strcmp(oname, ifa->ifa_name) == 0) || !(ifa->ifa_flags & IFF_UP) || ifa->ifa_flags & IFF_LOOPBACK) continue; for (i = 0; i < argc; i++) { if (strcmp(argv[i], ifa->ifa_name) == 0) flag = 1; } if (argc > 0 && flag == 0) continue; flag = 0; oname = ifa->ifa_name; if (readdata(sock, ifa->ifa_name, &ifd) == -1 || ifd.ifi_type == IFT_PFLOG) continue; datap = malloc(sizeof(struct data)); datap->flags = ifa->ifa_flags; strlcpy(datap->name, ifa->ifa_name, sizeof(datap->name)); memcpy(&datap->data, &ifd, sizeof(datap->data)); SIMPLEQ_INSERT_TAIL(&head, datap, link); ++ret; } freeifaddrs(ifap); return ret; } int readdata(int sock, char *name, void *data) { struct ifreq ifr; strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_data = data; return ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr); } void die(int ignored) { (void)ignored; dieflag = 1; } __dead void usage(void) { extern char *__progname; (void)fprintf(stderr, "usage: %s [-s time] [if ...]\n", __progname); exit(-1); }