/* * heartbeat++.c -- flash a Lock LED (keyboard) in an hearthbeat fashion, usually without options. * * * The flash code is from the book LNUX DEVICE DRIVER (O'Reilly). * Works even with USB-Keyboards and also with PS/2-Keyboards (even with both at the same time, but * keyboard detection is made only for PS/2). * * 2005: Changed to 50 % dute-cute and 1/2 Hz at a relative loadaverage (load / cpus (cores)) of 0, 1 Hz at 1, etc.. * * 2007: Added Keylogger detection via controll port reading, because ioctls, udevmonitor --env * and reading in /proc are not sufficient. * + 2008: Added higher time resolution of ns because with a dozen of Cherry, Logitech, Microsoft and noname keyboards + and dozens of thousends of hours usage i have seen no false alarm but with a Steelseries 7G i get about two false + alarms per day, when the load average is about 10. The steelseries keyboard is sleeping about half a second. * Also added loop counter. * * TODO: Signal-Handler, version number, Extension for USB keyboards (maybe udevmonitor --env, input-tools (http://dl.bytesex.org/cvs-snapshots/) or input-layers (http://linuxconsole.sourceforge.net/)), hwinfo ... * * * Dr. Rolf Freitag 2007, 2008, * Example usage with two lines in /etc/inittab, after compiling, e. g. wia gcc -O3 -o heartbeat heartbeat++.c and copying via cp -i heartbeat++ /sbin/ : # keyboard led heartbeat++ 13:S12345:respawn:/usr/bin/nice -n+19 /sbin/heartbeat++ --- Citation from the flash code source license: This source code can be redistributed in source or binary form so long as an acknowledgment appears in derived source files. The citation should list that the code comes from "Linux Device Drivers" by Alessandro Rubini, published by O'Reilly & Associates. This code is under copyright and cannot be included in any other book, publication, or educational product without permission from O'Reilly & Associates. No warranty is attached; we cannot take responsibility for errors or fitness for use. Enjoy /alessandro */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* or */ #include // version #define VERSION 1.4 // release date #define DATE 2008-08-23 int main (int argc, char **argv) { char led; int chosenled = 1; /* default: scroll lock */ // char hearth[] = { 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; char hearth[] = { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; // heartbeat pattern int udelay = 200000; // 1/5 s default delay int load = 0, i_cpus = 0, j = 0, line_counter = 0, i_ac = 0; char *prgname = argv[0]; FILE *f = NULL; char ca_in_line[123 + 1] = { 0 }; uint8_t b_status = 0, b_old_status = 0; // Keyboard status: Start with present keyboard (no timeout flag set). uint64_t u64_lc = 0; // loop counter if (argc > 1 && isdigit (argv[1][0])) { /* the time delay */ udelay = 1000 * atoi (argv[1]); if (udelay < 1000) (void)fprintf (stderr, "%s: delay too short\n", prgname); else { argv++; argc--; } } nice (19); /* in case it succeeds... */ iopl (3); /* allows access to all I/O-Ports, ioperm doesen't work above the 0x3ff-Limit e. g. at PCI-Cards */ // estimate number of cpus/cores f = fopen ("/proc/cpuinfo", "r"); for (line_counter = 0; (line_counter < 123456) and (NULL != fgets (ca_in_line, 123, f)); line_counter++) { i_ac = sscanf (ca_in_line, "processor : %d", &j); if (1 == i_ac) i_cpus = j + 1; // numbering starts with 0 for first cpu, so the number is +1 } if (i_cpus < 1) i_cpus = 1; (void)fclose (f); udelay *= 100; /* prepare for a later division */ if (argc > 1 && strnlen (argv[1], 123) == 1) { argv++, argc--; if (tolower (argv[0][0]) == 's') chosenled = 1; /* scroll lock */ else if (tolower (argv[0][0]) == 'n') chosenled = 2; /* num lock */ else if (tolower (argv[0][0]) == 'c') chosenled = 4; /* caps lock */ else { fprintf (stderr, "%s: unknown led '%s'\n", prgname, argv[1]); argc++; } } if (argc > 1) { (void)fprintf (stderr, "%s: usage \"%s [delay ms] [ n | c | s ]\"\n", prgname, prgname); exit (1); } // ok, now do your loop for (u64_lc=0;;u64_lc++) { int consolefd = open ("/dev/tty0", O_RDONLY); int i = 0; f = fopen ("/proc/loadavg", "r"); if (f) { fscanf (f, "%d.%d", &load, &i); fclose (f); } else { load = i = 0; } // scale load by number of cpus/cores load /= i_cpus; // divider (inverse frequence multiplier) for the heartbeat load = 100 + load * 100 + i; for (i = 0; i < sizeof (hearth) / sizeof (hearth[0]); i++) { if (ioctl (consolefd, KDGETLED, &led) || ioctl (consolefd, KDSETLED, (led & ~chosenled) | chosenled * hearth[i])) { (void)fprintf (stderr, "%s: ioctl(): %s\n", prgname, strerror (errno)); exit (-2); } usleep (udelay / load); // check if the keyboard is present: Look for the timeout flag 0x40 at port 0x64 b_status = inb (0x64); // printf("%x\n", b_status); // for debugging // filter the timeout flag 0x40 (BIT6) b_status and_eq 0x40; if (b_status) { // usually \a does not work; it's only a one-line try (void)printf ("\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a"); // beep via the speaker (install beep first) (void)system ("/usr/bin/beep -l 123"); // beep via the (first) soundcard (void)system ("cat /boot/grub/menu.lst > /dev/dsp"); } if (b_status != b_old_status) // status change: Send Mail { b_old_status = b_status; // store the status if (b_status) // keyboard hangup { (void)system ("date --rfc-3339=ns | mail -s \"The Keyboard has been removed!\" root@localhost"); (void)system ("echo -n \"-\" >> /root/heartbeat++.log; date --rfc-3339=ns >> /root/heartbeat++.log"); (void)printf ("Keyboard status change: The (PS/2) Keyboard has been removed! loop counter %llu\n", u64_lc); } else // keyboard has gone online { (void)system ("date --rfc-3339=ns | mail -s \"The Keyboard removal has been ended!\" root@localhost"); // (void)system ("mail -s \"The Keyboard removal has been ended!\" root@localhost > /root/heartbeat++.log; date --rfc-3339=ns >> /root/heartbeat++.log"); (void)printf ("Keyboard status change: The (PS/2) Keyboard removal has been ended! loop counter %llu\n", u64_lc); } } } i = close (consolefd); } iopl (0); /* release region */ exit (0); /* never happen */ } // main