--- /dev/null
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/kbio.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#ifdef USE_X
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+#endif
+
+#include <tlog.h>
+#include <tmalloc.h>
+
+extern char *optarg;
+
+static void
+usage()
+{
+ fputs(
+ "Copyright (c) 2009 Teodor Sigaev <teodor@sigaev.ru>. All rights reserved.\n"
+ "blinker - blink by numlock/scroll leds accordingly with network activity\n"
+ "./blinker\n",
+ stdout
+ );
+ exit(1);
+}
+
+static
+unsigned int
+getifnum(void)
+{
+ u_int data = 0;
+ size_t datalen = 0;
+ static int name[] = {
+ CTL_NET,
+ PF_LINK,
+ NETLINK_GENERIC,
+ IFMIB_SYSTEM,
+ IFMIB_IFCOUNT
+ };
+
+ datalen = sizeof(data);
+ if (sysctl(name, 5, &data, &datalen, NULL, 0) != 0)
+ tlog(TL_CRIT|TL_EXIT,"sysctl failed: %s", strerror(errno));
+
+ return data;
+}
+
+static int
+getifmibdata(int row, struct ifmibdata *data)
+{
+ size_t datalen = 0;
+ static int name[] = {
+ CTL_NET,
+ PF_LINK,
+ NETLINK_GENERIC,
+ IFMIB_IFDATA,
+ 0,
+ IFDATA_GENERAL
+ };
+ datalen = sizeof(*data);
+ name[4] = row;
+
+ if ((sysctl(name, 6, data, &datalen, NULL, 0) != 0) && (errno != ENOENT)) {
+ tlog(TL_WARN,"sysctl failed: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+#define LED_ON 0x01
+#define LED_OFF 0x02
+
+typedef struct Blinker {
+ void (*exec)(struct Blinker *, int, int);
+ int TxLed;
+ int RxLed;
+ int
+ unused1:12,
+ RxOn:2,
+ TxOn:2,
+ unused2:16;
+ void *arg;
+} Blinker;
+
+static void
+execKbd(struct Blinker * blinker, int RxAction, int TxAction) {
+ if ( !(blinker->RxOn == RxAction && blinker->TxOn == TxAction) ) {
+ int flag = 0;
+
+ if (ioctl(0, KDGETLED, &flag) == -1)
+ tlog(TL_WARN,"unable to get led's statuses: %s",
+ strerror(errno));
+
+ if (RxAction)
+ flag |= blinker->RxLed;
+ else
+ flag &= ~blinker->RxLed;
+ if (TxAction)
+ flag |= blinker->TxLed;
+ else
+ flag &= ~blinker->TxLed;
+
+ if (ioctl(0, KDSETLED, &flag) == -1)
+ tlog(TL_WARN,"unable to set NumLock led: %s",
+ strerror(errno));
+
+ blinker->RxOn = RxAction;
+ blinker->TxOn = TxAction;
+ }
+}
+
+#ifdef USE_X
+static void
+execXKbd(struct Blinker * blinker, int RxAction, int TxAction) {
+ static XKeyboardControl value;
+
+ if ( blinker->RxOn != RxAction ) {
+ value.led = blinker->RxLed;
+ value.led_mode = (RxAction) ? LedModeOn : LedModeOff;
+ XChangeKeyboardControl((Display*)blinker->arg, KBLed | KBLedMode, &value);
+ }
+
+ if ( blinker->TxOn != TxAction ) {
+ value.led = blinker->TxLed;
+ value.led_mode = (TxAction) ? LedModeOn : LedModeOff;
+ XChangeKeyboardControl((Display*)blinker->arg, KBLed | KBLedMode, &value);
+ }
+
+ if ( !(blinker->RxOn == RxAction && blinker->TxOn == TxAction) )
+ {
+ XFlush((Display*)blinker->arg);
+ blinker->RxOn = RxAction;
+ blinker->TxOn = TxAction;
+ }
+}
+#endif
+
+typedef struct statData {
+ u_int64_t ip;
+ u_int64_t op;
+} statData;
+
+static int LetWork = 1;
+
+static void
+stopWork(int s) {
+ LetWork = 0;
+}
+
+int
+main(int argc, char *argv[]) {
+ keyboard_info_t info;
+ int i;
+ Blinker blinker;
+ struct ifmibdata data;
+ statData curData = {0,0},
+ oldData = {0,0};
+
+ while( (i=getopt(argc, argv, "d:h"))!=-1) {
+ switch(i) {
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ opentlog(TL_OPEN_STDERR, TL_INFO, NULL);
+ signal(SIGHUP, stopWork);
+ signal(SIGSTOP, stopWork);
+ signal(SIGINT, stopWork);
+
+ memset(&blinker, 0, sizeof(blinker));
+
+ if (ioctl(0, KDGKBINFO, &info) == 0)
+ {
+ blinker.TxLed = LED_CAP;
+ blinker.RxLed = LED_NUM;
+ blinker.exec = execKbd;
+ } else {
+
+ tlog(TL_WARN,"unable to obtain keyboard information: %s%s",
+ strerror(errno),
+#ifdef USE_X
+ (errno == ENOTTY) ? "; Try X-windows interface." :
+#endif
+ "" ); /* ENOTTY */
+#ifdef USE_X
+ {
+ Display *dpy;
+ XkbDescPtr xkb;
+
+ dpy = XOpenDisplay(NULL);
+ if (dpy == NULL)
+ tlog(TL_CRIT|TL_EXIT, "Could not open default display");
+
+ if ( (xkb= XkbGetMap(dpy,0,XkbUseCoreKbd)) == NULL ||
+ XkbGetIndicatorMap(dpy,XkbAllIndicatorsMask,xkb)!=Success ||
+ XkbGetNames(dpy,XkbAllNamesMask,xkb)!=Success)
+ tlog(TL_CRIT|TL_EXIT, "Fail to get indicator's descriptions");
+
+ for (i=0;i<XkbNumIndicators;i++) {
+ if (xkb->indicators->phys_indicators & (1<<i)) {
+ char *name = XGetAtomName(dpy, xkb->names->indicators[i]);
+ XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
+
+ if (name == NULL || *name == '\0')
+ continue;
+
+ if (strcmp(name, "Caps Lock") == 0)
+ blinker.TxLed = i + 1;
+ else if (strcmp(name, "Num Lock") == 0)
+ blinker.RxLed = i + 1;
+ else
+ continue;
+
+ if (map->flags & XkbIM_NoExplicit) {
+ /* allow control */
+ XkbIndicatorMapPtr newmap = (XkbIndicatorMapPtr)tmalloc(sizeof(XkbIndicatorMapRec));
+
+ *newmap = *map;
+ newmap->flags &= ~XkbIM_NoExplicit;
+
+ if (XkbSetNamedIndicator(dpy, xkb->names->indicators[i], False, False, True, newmap) == False)
+ tlog(TL_WARN,"XkbSetNamedIndicator fails");
+ }
+ }
+ }
+
+ if (blinker.RxLed == 0 || blinker.TxLed == 0)
+ tlog(TL_CRIT|TL_EXIT, "Fail to identify leds");
+
+ blinker.arg = dpy;
+ blinker.exec = execXKbd;
+ }
+#endif
+ }
+
+ /*
+ * switch off leds - initial state
+ */
+ blinker.TxOn = blinker.RxOn = 1;
+ blinker.exec(&blinker, 0, 0);
+
+ while(LetWork) {
+ oldData = curData;
+
+ memset(&curData, 0, sizeof(curData));
+ for(i=1;i<=getifnum();i++) {
+ if (getifmibdata(i, &data) != 0)
+ continue;
+ if (data.ifmd_name[0] == 'l' && data.ifmd_name[1] == 'o' )
+ continue;
+
+ curData.ip += data.ifmd_data.ifi_ipackets;
+ curData.op += data.ifmd_data.ifi_opackets;
+ }
+
+ blinker.exec(
+ &blinker,
+ (curData.ip == oldData.ip) ? 0 : 1, /* Tx */
+ (curData.op == oldData.op) ? 0 : 1 /* Rx */
+ );
+
+ usleep(10000);
+ }
+
+ blinker.exec(&blinker, 0, 0);
+#ifdef USE_X
+ if (blinker.arg)
+ XCloseDisplay((Display*)blinker.arg);
+#endif
+ return 0;
+}