sampson@killer.DALLAS.TX.US (Steve Sampson) (01/01/89)
Here's a newer cron that needs to be tested. If the Library routines are broke, change them. (fopen() doesn't create a file when it doesn't exist for append). I'd test it myself but I'm waiting for 1.3, Steve. /* * Create On Utility * * Version 1.04, Public Domain (p) January 1989 * S. Sampson, with ideas from W. Schroeder, and W. Paul * * The cron.c program operates as a daemon, waking up every minute * to execute the CRONTAB table. Logging errors to CRONERR. * The cron table file is left on disk and not moved to RAM, and * the command character to signify a newline '%' is not used. * * Put in Minix /etc/rc as: cron * * Some cron table entry examples: * * Print the date on console every minute: * * * * * * date >/dev/tty0 * * Print the date on console on the hour, every hour: * 0 * * * * date >/dev/tty0 * * Backup the files at 4:30 am every day except Sat and Sun: * 30 4 * * 1-5 /etc/backup /dev/st1 * * Backup the files every other day at 7:30 pm: * 30 19 * * 1,3,5 /etc/backup /dev/st1 */ #include <stdio.h> #include <signal.h> #include <errno.h> #define CRONTAB "/usr/act/crontab" #define CRONERR "/usr/act/cronerr" #define MAXLINE 132 #define SIZE 64 #ifndef TRUE #define FALSE 0 #define TRUE ~FALSE #endif #ifndef NULL #define NULL 0 #endif #define max(x,y) (((y) <= (x)) ? (y) : (x)) struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; char *ctime(); struct tm *localtime(); FILE *fp, *err; int eof; char min[SIZE], hour[SIZE], day[SIZE], month[SIZE], wday[SIZE], command[SIZE]; char *tokv[] = { min, hour, day, month, wday }; main() { void wakeup(), killer(); long tick; if (fork() != 0) _exit(0); signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); /* * fopen() will create the file if it does not exist. * Any other errors will be output to stderr at startup. */ if ((err = fopen(CRONERR, "a")) == (FILE *)NULL) { perror("cron"); exit(1); } setbuf(err, (char *)NULL); /* error I/O is now unbuffered */ close(0); close(1); close(2); /* close all I/O paths */ /* start at the top of the next minute, truncate seconds */ tick = ((time((long *)0) / 60L) + 1L) * 60L; /* here we go... */ for (;;) { /* do this cycle every minute */ if (time((long *)0) >= tick) { wakeup(tick); tick += 60L; } /* kill zombies for one second */ signal(SIGALRM, killer); alarm(1); while (wait((int *)NULL) != -1) ; alarm(0); sleep(max((unsigned)60, (unsigned)(tick - time((long *)0)))); } } /* * Cron does not wait for child to die. Therefore children * become zombies when they complete. In order to clear them * out the parent must execute wait() every now and then. */ void killer() { /* edit the cron.s file and remove the pushin-n-popin */ } void wakeup(tick) long tick; { register struct tm *tm = localtime(&tick); if (access(CRONTAB, 4) == -1) { fprintf(err, "Can't read %s %s", CRONTAB, ctime(&tick)); return; } else fp = fopen(CRONTAB, "r"); eof = FALSE; while (!eof) { if (getline() && match(min,tm->tm_min) && match(hour,tm->tm_hour) && match(day,tm->tm_mday) && match(month,tm->tm_mon) && match(wday,tm->tm_wday)) { /* * Execute command in the shell */ if (fork() == 0) { execl("/bin/sh", "sh", "-c", command, (char *)NULL); fprintf(err, "Can't access /bin/sh %s", ctime(&tick)); fclose(err); fclose(fp); exit(1); } } } fclose(fp); } /* * A line consists of six fields. The first five are: * * minute: 0-59 * hour: 0-23 * day: 1-31 * month: 1-12 * weekday: 0-6 (Sunday = 0) * * The fields are seperated by spaces or tabs, with the * first field left justified (no leading spaces or tabs). * See below for optional field syntax. * * The last field is the command field. This command will * be executed by the shell just as if typed from a console. */ getline() { register char *p; register int i; char buffer[MAXLINE]; extern char *scanner(); if (fgets(buffer, sizeof buffer, fp) == (char *)NULL) { eof = TRUE; return(FALSE); } for (p = buffer, i = 0; i < 5; i++) { if ((p = scanner(tokv[i], p)) == (char *)NULL) return(FALSE); } strcpy(command, p); /* scoop the command */ return(TRUE); } char *scanner(token, offset) register char *token; /* target buffer to receive scanned token */ register char *offset; /* place holder into source buffer */ { while ((*offset != ' ') && (*offset != '\t') && *offset) *token++ = *offset++; /* * Check for possible error condition */ if (!*offset) return ((char *)NULL); *token = '\0'; while ((*offset == ' ') || (*offset == '\t')) offset++; return (offset); } /* * This routine will match the left string with the right number. * * The string can contain the following syntax: * * * This will return TRUE for any number * x,y [,z, ...] This will return TRUE for any number given. * x-y This will return TRUE for any number within * the range of x thru y. */ match(left, right) register char *left; register int right; { register int n; register char c; n = 0; if (!strcmp(left, "*")) return(TRUE); while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0'; switch (c) { case '\0': return (right == n); case ',': if (right == n) return(TRUE); do { n = 0; while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0'; if (right == n) return(TRUE); } while (c == ','); return(FALSE); case '-': if (right < n) return(FALSE); n = 0; while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0'; return(right <= n); } } /* * ctime.c and localtime as posted to comp.os.minix */ int days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char *days[] = { "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed" }; struct tm stm; long s_p_min; long s_p_hour; long s_p_day; long s_p_wday; long s_p_year; char t_buf[26]; char *ctime(pclock) long *pclock; { long tt; s_p_min = 60L; s_p_hour = 60L * 60L; s_p_day = 60L * 60L * 24L; s_p_year = 60L * 60L * 24L * 365L; tt = *pclock; cv_time(tt); sprintf(t_buf, "%s %s %02d %02d:%02d:%02d %04d\n", days[(tt / s_p_day) % 7], months[stm.tm_mon], stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, stm.tm_year); return(t_buf); } struct tm *localtime(pclock) long *pclock; { cv_time(*pclock); return &stm; } cv_time(t) long t; { stm.tm_sec = 0; stm.tm_min = 0; stm.tm_hour = 0; stm.tm_mday = 1; stm.tm_mon = 0; stm.tm_year = 0; stm.tm_wday = 0; stm.tm_yday = 0; stm.tm_isdst= 0; while (t >= s_p_year) { if (((stm.tm_year + 2) % 4) == 0) t -= s_p_day; stm.tm_year += 1; t -= s_p_year; } if (((stm.tm_year + 2) % 4) == 0) days_per_month[1]++; stm.tm_year += 1970; while ( t >= (days_per_month[stm.tm_mon] * s_p_day)) t -= days_per_month[stm.tm_mon++] * s_p_day; while (t >= s_p_day) { t -= s_p_day; stm.tm_mday++; } while (t >= s_p_hour) { t -= s_p_hour; stm.tm_hour++; } while (t >= s_p_min) { t -= s_p_min; stm.tm_min++; } stm.tm_sec = (int)t; } /* EOF */