sampson@killer.UUCP (Steve Sampson) (02/15/88)
Here's a cron that's been tested with minix version 1.1. It uses some code that was posted recently. Make sure you deal with permissions on the files. /* * cron.c * * CReate On Utility, Minix Version 1.0 * Public Domain (p) February 1988 by S. R. Sampson * * This program operates as a daemon, waking up every minute * to execute the CRONTAB table. Logging errors to CRONERR. * * Put in Minix rc as: /etc/cron & * * Some notes are included below concerning the cron table * file format. In this version the cron table file is left * on disk and not moved to core, and the command character * to signify a newline '%' is not used. * * Some cron table entry examples: * * Print the date on console every minute: * * * * * * /usr/bin/date >/dev/tty0 * * Print the date on console on the hour, every hour: * 0 * * * * /usr/bin/date >/dev/tty0 * * Backup the files at 4:30 am every day except Sat and Sun: * 30 4 * * 1-5 /etc/backup /dev/fd1 * * Backup the files every other day at 7:30 pm: * 30 19 * * 1,3,5 /etc/backup /dev/fd1 */ #include <stdio.h> #include <signal.h> #include <errno.h> #define CRONTAB "/act/crontab" #define CRONERR "/act/cronerr" #define MAXLINE 132 #define SIZE 64 #define TRUE 1 #define FALSE 0 #define void int extern int errno; 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; }; int eof; char min[SIZE], hour[SIZE], day[SIZE], month[SIZE], wday[SIZE], command[SIZE]; char *tokv[] = { min, hour, day, month, wday }; FILE *fd, *err; /* * This is the basics, ready for bells and whistles */ main() { void wakeup(), killer(); /* * 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 */ for (;;) { signal(SIGALRM, wakeup); alarm(59); pause(); /* check for work every minute */ signal(SIGALRM, killer); alarm(1); wait((int *)NULL); /* clean up zombie children */ } } /* * Cron does not wait() for child to die. Therefore children * become zombies when they complete. In order to clear out the * "floating dead babies" the parent must execute wait() every * now and then. (Thanks to Fred Buck for enlightenment * See Doctor Dobbs #126 April 87, p. 152) */ void killer() { /* edit the cron.s file and remove the garbage! */ } void wakeup() { register struct tm *tm; long cur_time; extern struct tm *localtime(); extern char *ctime(); time(&cur_time); /* get the current time */ tm = localtime(&cur_time); /* break it down */ if (access(CRONTAB, 1) == -1) { fprintf(err,"%s has no read permission %s",CRONTAB,ctime(&cur_time)); return; } else fd = 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", "/bin/sh", "-c", command, 0); fprintf(err,"Can't access shell %s", ctime(&cur_time)); fclose(err); fclose(fd); exit(1); } } } fclose(fd); } /* * 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, fd) == (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); } } /* * Time Routines * * ctime() and localtime() */ 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(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 */