#include #include #include #include #include #include #include #include #include #include char *pidfile; char *get_cronolog(void) { int len = 0; char *path, *tmp = NULL; struct stat st; path = strtok(getenv("PATH"), ":"); while(path != NULL) { len = (strlen(path) + strlen("/cronolog") + 1); tmp = (char *)malloc(len); snprintf(tmp, len, "%s%s", path, "/cronolog"); if(stat(tmp, &st) == -1) { if(errno == ENOENT) { free(tmp); path = strtok(NULL, ":"); continue; } fprintf(stderr, "stat(): Error: %s\n", strerror(errno)); free(tmp); return NULL; } if(st.st_mode & S_IFREG) return tmp; else { free(tmp); return NULL; } } if(tmp != NULL) free(tmp); return NULL; } void die(int sig) { /* kill off children */ kill(0, SIGTERM); /* remove pid file, quit */ unlink(pidfile); exit(0); } struct sigaction sigdie = { .sa_handler = die }; int main(int argc, char *argv[]) { time_t t = 0; pid_t pid = 0; int fd, pidfd, pidlen = 16; char *fifo, *log, *cronolog, pidstr[16]; if (argc != 4) { fprintf(stderr, "Usage: %s /path/to/pidfile /path/to/fifo" " /path/to/logs/%%Y%%m%%d.log\n", argv[0]); exit(1); } pidfile = argv[1]; fifo = argv[2]; log = argv[3]; cronolog = get_cronolog(); if(cronolog == NULL) { fprintf(stderr, "cronolog not found in PATH\n"); exit(1); } /* Test for fifo access, leave open for use */ /* O_NONBLOCK allows us to fork into the background */ fd = open(fifo, O_RDONLY|O_NONBLOCK); if (fd == -1) { fprintf(stderr, "Cannot open fifo %s: %s\n", fifo, strerror(errno)); free(cronolog); exit(1); } pid = fork(); if (pid == 0) { /* CHILD 0 */ /* Record pid to pidfile */ pidfd = open(pidfile, O_WRONLY|O_CREAT|O_EXCL, 0644); if (pidfd == -1) { fprintf(stderr, "Cannot create and open pid file %s: %s\n", pidfile, strerror(errno)); free(cronolog); exit(1); } else { pidlen = snprintf(pidstr, pidlen, "%d\n", getpid()); if(write(pidfd, pidstr, pidlen) == -1) { fprintf(stderr, "Cannot write pid file %s: %s\n", pidfile, strerror(errno)); free(cronolog); exit(1); } close(pidfd); } /* close shell output */ close(0); close(1); close(2); /* set a process group for easy cleanup */ setpgrp(); sigaction(SIGTERM, &sigdie, NULL); /* keep the cronolog process open */ while (1) { t = time(NULL); pid = fork(); if (pid == 0) { /* CHILD 1 */ /* replace stdin with fifo */ dup2(fd, 0); /* unset O_NONBLOCK */ fcntl(0, F_SETFL, 0); /* exec cronolog */ execl(cronolog, cronolog, log, (char *) 0); /* filure! give up on life */ free(cronolog); exit(1); } else { /* PARENT 1 */ /* watch child 1 */ waitpid(pid, NULL, 0); if (time(NULL) - t < 2) { /* restarting too fast, wait 10 seconds */ sleep(10); } } } } /* PARENT 0 exits */ close(fd); free(cronolog); return 0; } /* vim: set ts=4 sw=4 tw=80: */