Hi all, I have been using a small accessory application for dwm for a long time, that I called dwmclock. What it did for the longest time was format the load averages and the current time into a string, then set that as X11 root window name (dwm would thus display it in the bar window).
Today, I decided to change it into something more useful (I know the flashplayer is stressing my CPU, so I don't need an application to tell me). Also I thought utilization of the network is a more useful information than utilization of my CPU, especially in this current time of traffic shaping and other such nonsense. Long story short, I wrote a dwmclock, that also displays the current default interface's first letter (usually sufficient, as most people have only at most one network card of each type in their machines), as well as download and upload speeds. Currently it only works on linux, though, as it reads the /proc and /sys interfaces (and that also means it's subject to breakage on kernel upgrade. Sigh.) As usual, criticisms and improvement suggestions are welcome. I already know of one problem: I'm reading the interface statistics, which count every received byte, even if it's from a broadcast message on a protocol we don't care about or the like. I have no idea how to only count IP traffic, however. Also, I guess instead of my single second difference I should be using something like a moving average, to smoothe out the curve. Oh well, food for thought and later improvement. Ciao, Markus
#include <X11/Xlib.h> #include <X11/Xatom.h> #include <time.h> #include <locale.h> #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdint.h> #include <inttypes.h> #include <math.h> #define IFNAMSIZ 16 static const char* determine_def_if(void) { FILE *f; const char* ret = 0; static char buf[IFNAMSIZ]; char filebuf[256]; f = fopen("/proc/net/route", "r"); if (f) { while (fgets(filebuf, sizeof filebuf, f)) { char *tab = strchr(filebuf, '\t'); if (tab && !strncmp(tab + 1, "00000000", 8)) { memcpy(buf, filebuf, tab - filebuf); buf[tab - filebuf] = 0; ret = buf; break; } } fclose(f); } return ret; } static uint64_t readfile(const char* filename) { FILE* f; uint64_t ret = 0, tmp; f = fopen(filename, "r"); if (f) { if (fscanf(f, "%"SCNu64, &tmp) == 1) ret = tmp; fclose(f); } return ret; } static uint64_t get_rx_bytes(const char* interface) { char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; strcpy(fnbuf, "/sys/class/net/"); strcat(fnbuf, interface); strcat(fnbuf, "/statistics/rx_bytes"); return readfile(fnbuf); } static uint64_t get_tx_bytes(const char* interface) { char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; strcpy(fnbuf, "/sys/class/net/"); strcat(fnbuf, interface); strcat(fnbuf, "/statistics/tx_bytes"); return readfile(fnbuf); } static int get_suff(uint64_t x) { int r = -1 + !x; while (x) { r++; x >>= 10; } return r; } int main(void) { Display *dpy; Window root; int loadfd; setlocale(LC_ALL, ""); dpy = XOpenDisplay(0); if (dpy) { struct timespec tm, s; ssize_t rv; char oldif[IFNAMSIZ] = {0}; uint64_t rxb, txb; static const char suffixes[] = " KMGT"; // let's stay real here root = XDefaultRootWindow(dpy); clock_gettime(CLOCK_REALTIME, &tm); s.tv_sec = 0; s.tv_nsec = 1000000000 - tm.tv_nsec; do rv = nanosleep(&s, &s); while (rv == -1 && s.tv_nsec); for (;;) { char buf[100]; // estimate const char *thisif = determine_def_if(); uint64_t currxb, curtxb; int idx; int i; if (thisif) { if (strcmp(thisif, oldif)) { strcpy(oldif, thisif); rxb = txb = 0; } i = 0; buf[i++] = oldif[0]; buf[i++] = ' '; buf[i++] = 'v'; currxb = get_rx_bytes(oldif); curtxb = get_tx_bytes(oldif); idx = get_suff(currxb - rxb); i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(currxb - rxb) / pow(1024, idx), suffixes[idx]); rxb = currxb; buf[i++] = ' '; buf[i++] = '^'; idx = get_suff(curtxb - txb); i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(curtxb - txb) / pow(1024, idx), suffixes[idx]); txb = curtxb; } else buf[i++] = 'n'; buf[i++] = ' '; buf[i++] = '|'; buf[i++] = ' '; time_t t; size_t l; t = time(0); l = strftime(buf + i, sizeof buf - i, "%c", localtime(&t)); XStoreName(dpy, root, buf); XSync(dpy, False); sleep(1); } } }