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 */