#if 0 set -x gcc -W -Wall -O6 -s -o `basename $0 .c` $0 $* exit $? #endif #include #include #include #include #include #include #include #include #include #include #include enum states { unknown, sleeping, standby, active }; const char *state_names[] = { "unknown", "sleeping", "standby", "active/idle" }; #ifndef HDIO_DRIVE_CMD #define HDIO_DRIVE_CMD 0x031f #endif #ifndef WIN_CHECKPOWERMODE1 #define WIN_CHECKPOWERMODE1 0xE5 #endif #ifndef WIN_CHECKPOWERMODE2 #define WIN_CHECKPOWERMODE2 0x98 #endif enum states get_state (int fd) { unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0}; enum states state; if (ioctl(fd, HDIO_DRIVE_CMD, &args) && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */ && ioctl(fd, HDIO_DRIVE_CMD, &args)) { if (errno != EIO || args[0] != 0 || args[1] != 0) state = unknown; else state = sleeping; } else { state = (args[2] == 255) ? active : standby; } return state; } int main (int argc, char **argv) { int *fds; enum states *st; char *buf, *tmpbuf; size_t buf_len = 10000; /* Just the initial buf len. */ size_t tmpbuf_len = 100; int numfd = argc-1; int fd; const char *prog; if ((prog = strrchr (argv[0], '/'))) prog++; else prog = argv[0]; openlog (prog, LOG_PID, LOG_USER); if (numfd <= 0) { fprintf (stderr, "Usage: %s /dev/hda /dev/hdb ..\n", prog); fprintf (stderr, "The first device is assumed to be syslog device\n" "and syslog is only written if that drive is spinning.\n"); exit (EX_USAGE); } fds = (int *)malloc (sizeof (int) * numfd); assert (fds); st = (enum states *)malloc (sizeof (enum states) * numfd); assert (st); buf = (char *)malloc(buf_len); assert (buf); buf[0] = '\0'; for (fd = 0; fd < numfd; fd++) { st[fd] = unknown; fds[fd] = open (argv [1+fd], O_RDONLY|O_NONBLOCK); if (0 > fds[fd]) { perror (argv [1+fd]); exit (EX_IOERR); } if (strlen (argv [1+fd]) > tmpbuf_len) tmpbuf_len = strlen (argv [1+fd]); } tmpbuf_len += 100; /* Enough for the sprintf below. */ tmpbuf = (char *)malloc(tmpbuf_len); assert (tmpbuf); for (;;) { for (fd = 0; fd < numfd; fd++) { enum states newst = get_state (fds[fd]); if (newst != st[fd]) { struct tm *t; time_t now; time (&now); t = localtime (&now); sprintf (tmpbuf, "%d-%02d-%02d %02d:%02d:%02d %s: " "old state: %s, new state: %s.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, argv[1+fd], state_names[st[fd]], state_names[newst]); if (buf_len < strlen (buf) + strlen (tmpbuf)) { buf_len = strlen (buf) + strlen (tmpbuf); buf = (char *)realloc (buf, buf_len); } strcat (buf, tmpbuf); st[fd] = newst; } } if (buf[0] && active == st[0]) { char *s = buf; char *t; while ((t = strtok (s, "\n"))) { syslog (LOG_INFO, "%s", t); s = NULL; } buf[0] = '\0'; } sleep (1); } /* not reached */ return 0; }