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