Path: utzoo!mnetor!uunet!steinmetz!ge-dab!codas!killer!sampson From: sampson@killer.UUCP (Steve Sampson) Newsgroups: comp.sources.wanted Subject: Re: cron/at and uucp in minix Message-ID: <3182@killer.UUCP> Date: 1 Feb 88 22:04:25 GMT Organization: The Unix(R) Connection, Dallas, Texas Lines: 274 Keywords: Here's a simple cron [] Concerning cron, I sent a copy to iscuva!ricks of my simple cron, but I don't think he ever ported it to minix. I know this ain't the place for sources but if I put it in comp.os.minix someone will start complaining that it don't work. It's short, lacks bells and whistles, and ain't ported: /* * cron.c * * Public Domain (p) No Rights Reserved * * This program operates as a daemon, waking up every minute * to execute the CRONTAB table. Logging errors to CRONERR. * * Put in UniFLEX 68020 startup as: 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: * * * * * * date >/dev/tty00 * * Print the date on console on the hour, every hour: * 0 * * * * date >/dev/tty00 * * Backup the files at 4:30 am every day except Sat and Sun: * 30 4 * * 1-5 backup /dev/st0 / +BdNqV=CronBackup * * Backup the files every other day at 7:30 pm: * 30 19 * * 1,3,5 backup /dev/st0 / +BdNqV=CronBackup * */ #include #include #include #include #include #define CRONTAB "/act/crontab" #define CRONERR "/act/cronerr" #define MAXLINE 132 #define SIZE 64 #ifndef _READ #define _READ 1 #endif extern int errno; 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 * */ void 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() { } void wakeup() { register struct tm *tm; struct tm *localtime(); char *ctime(); long cur_time; time(&cur_time); /* get the current time */ tm = localtime(&cur_time); /* break it down */ if (access(CRONTAB, _READ) == -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/shell", "shell", "+bcx", 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. */ int getline() { register char *p; register int i; char buffer[MAXLINE], *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. */ int 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); } } /* EOF */ ------------------- S. R. Sampson, Nicaragua Freedom Air, ihnp4!killer!sampson "We help you find your God" -------------------