/*
flasher.c - Copyright (C) 2002 Murray Nesbitt (websrc@nesbitt.ca)
This program is protected and licensed under the following terms and
conditions: 1) it may not be redistributed in binary form without the
explicit permission of the author; 2) when redistributed in source
form, in whole or in part, this complete copyright statement must
remain intact.
*/
#include "flasher.h"
/* One of these per LED. */
static struct LED {
int led;
int flash_state;
int num_files;
struct file *files;
} LED[3];
#define FLASH_ANY (LED[0].flash_state || LED[1].flash_state || \
LED[2].flash_state)
char *progname;
static int preferred_sleep_time = SLEEP;
void usage(void)
{
printf("Usage: %s [-k tty] [-u #] -{c|n|s} file1:...:fileN -{c|n|s} file1:...\n",
progname);
exit(EXIT_FAILURE);
}
/* Monitors writes and reads to the files, and takes care of
flashing the LEDs. */
void *monitor(void) {
int i, j;
struct stat buf;
struct LED *this;
int current_sleep_time = preferred_sleep_time;
while(1) {
sleep(current_sleep_time);
for (i = 0; i < 3; i++) {
this = &LED[i];
for (j = 0; j < this->num_files; j++) {
if (stat(this->files[j].path, &buf) == -1)
/* File still doesn't exist, but user has been warned. */
continue;
if (buf.st_mtime > this->files[j].time) {
/* File has been changed since we last looked. */
this->files[j].time = buf.st_mtime;
this->files[j].writes++;
this->flash_state++;
current_sleep_time = FLASH_SLEEP;
}
else if (buf.st_atime > this->files[j].time &&
this->flash_state) {
/* File has been read since we last looked. */
this->files[j].time = buf.st_atime;
this->flash_state -= this->files[j].writes;
this->files[j].writes = 0;
if (!FLASH_ANY) {
/* All files read -- back to regular sleep interval. */
current_sleep_time = preferred_sleep_time;
}
}
}
}
if (!FLASH_ANY)
continue;
for (i = 0; i < 3; i++) {
this = &LED[i];
for (j = 0; j < this->flash_state; j++) {
usleep(FLASH_DELAY);
LEDstate(this->led, LED_ON);
usleep(FLASH_ONTIME);
LEDstate(this->led, LED_OFF);
}
}
}
}
/* Associates one or more (colon-separated) filenames with a
particular LED. */
void setup_LED(int led, char *filenames)
{
char *file;
int num_files = 0;
struct stat buf;
struct LED *this;
int leds[] = { LED_CAP, LED_NUM, LED_SCR };
this = &LED[led];
this->led = leds[led];
if (((file = strtok(filenames, ":")) == NULL) || !filenames) {
usage(); /* exits */
}
/* Allocate storage for the first file. */
if ((this->files = malloc(sizeof(struct file))) == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
do {
file = absolute_path(file);
if (stat(file, &buf) == -1) {
if (errno == ENOENT) {
/* If the file doesn't yet exist, that's OK, but warn. */
fprintf(stderr, "%s: warning: %s does not exist.\n",
progname, file);
buf.st_mtime = 0;
}
else {
perror(file);
exit(EXIT_FAILURE);
}
}
if (num_files && (this->files = realloc(this->files,
(num_files + 1) * sizeof(struct file))) == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
this->num_files++;
this->files[num_files].path = file;
this->files[num_files].time = buf.st_mtime;
this->files[num_files].writes = 0;
num_files++;
} while ((file = strtok(NULL, ":")) != NULL);
}
int main(int argc, char **argv)
{
int i = 1;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s: must be run as root.\n", progname);
exit(EXIT_FAILURE);
}
/* Ensure we aren't already running. */
check_lock();
/* option handling */
while (argv[i] && argv[i][0] == '-') {
switch(argv[i][1]) {
case 'c':
if (LED[0].led)
usage(); /* exits */
setup_LED(0, argv[++i]);
break;
case 'k':
open_console(argv[++i]);
break;
case 'n':
if (LED[1].led)
usage(); /* exits */
setup_LED(1, argv[++i]);
break;
case 's':
if (LED[2].led)
usage(); /* exits */
setup_LED(2, argv[++i]);
break;
case 'u':
if ((preferred_sleep_time = atoi(argv[++i])) == 0)
usage(); /* exits */
break;
default:
usage(); /* exits */
}
i++;
}
/* Nothing to do. */
if (!(LED[0].led || LED[1].led || LED[2].led)) {
usage(); /* exits */
}
if (!console_opened())
open_console(NULL);
/* Initialize signal handlers for removing the lock file
and restoring LED states at exit. */
set_sig_handlers();
/* Become a daemon, and create our lock file. */
daemonize();
monitor();
return 0; /* not reached. */
}
syntax highlighted by Code2HTML, v. 0.9.1