From: Alan Cox Date: Wed, 25 Oct 2017 14:57:17 +0000 (+0100) Subject: cron: add cron X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=f995fc476d263b723f8f27f76713c940f65e3f82;p=FUZIX.git cron: add cron --- diff --git a/Applications/MWC/cmd/Makefile.68000 b/Applications/MWC/cmd/Makefile.68000 index fdf638bf..68aef931 100644 --- a/Applications/MWC/cmd/Makefile.68000 +++ b/Applications/MWC/cmd/Makefile.68000 @@ -14,7 +14,7 @@ CRT0NS = ../../../Library/libs/crt0nostdio_68000.o ELF2FUZIX = elf2flt .SUFFIXES: .c .o -SRCS = ac.c almanac.c at.c calendar.c col.c deroff.c expr.c find.c m4.c moo.c pr.c tar.c test.c ttt.c units.c +SRCS = ac.c almanac.c at.c calendar.c col.c cron.c deroff.c expr.c find.c m4.c moo.c pr.c tar.c test.c ttt.c units.c OBJS = $(SRCS:.c=.o) diff --git a/Applications/MWC/cmd/Makefile.6809 b/Applications/MWC/cmd/Makefile.6809 index b17966b6..a7b8c0f8 100644 --- a/Applications/MWC/cmd/Makefile.6809 +++ b/Applications/MWC/cmd/Makefile.6809 @@ -14,7 +14,7 @@ CRT0 = ../../../Library/libs/crt0_6809.o .SUFFIXES: .c .o -SRCS = ac.c almanac.c at.c calendar.c col.c deroff.c expr.c find.c m4.c moo.c pr.c tar.c test.c ttt.c units.c +SRCS = ac.c almanac.c at.c calendar.c col.c cron.c deroff.c expr.c find.c m4.c moo.c pr.c tar.c test.c ttt.c units.c OBJS = $(SRCS:.c=.o) diff --git a/Applications/MWC/cmd/Makefile.z80 b/Applications/MWC/cmd/Makefile.z80 index 13480a3a..ed0965d0 100644 --- a/Applications/MWC/cmd/Makefile.z80 +++ b/Applications/MWC/cmd/Makefile.z80 @@ -13,7 +13,7 @@ PROGLOAD=`(cat ../../Kernel/platform/config.h; echo PROGLOAD) | cpp -E | tail -n SRCSNS = expr.c test.c -SRCS = ac.c almanac.c at.c col.c deroff.c find.c moo.c pr.c tar.c ttt.c units.c +SRCS = ac.c almanac.c at.c col.c cron.c deroff.c find.c moo.c pr.c tar.c ttt.c units.c SRCSBAD = calendar.c m4.c diff --git a/Applications/MWC/cmd/cron.c b/Applications/MWC/cmd/cron.c new file mode 100644 index 00000000..87099270 --- /dev/null +++ b/Applications/MWC/cmd/cron.c @@ -0,0 +1,396 @@ +/* + * Cron. Execute commands stored in /usr/lib/crontab at preset times. + * It sets its uid and gid to those of daemon, if possible. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRUE (0 == 0) +#define FALSE (0 != 0) + +/* + * Time field types. + */ +#define MIN 0 +#define HOUR 1 +#define MDAY 2 +#define MON 3 +#define WDAY 4 + +/* + * (Finite) States in valid(). + */ +#define START 0 +#define INT 1 +#define INTDASH 2 +#define RANGE 3 +#define STR 4 +#define STRPLUS 5 +#define ERR 6 +#define END 7 +#define GLOB ('*') + +/* + * Tokens returned by gettoken(). Tokens are integers. EOF is also a token. + * INT, STR and GLOB above are also tokens. + */ +#define DASH ('-') +#define COMMA (',') +#define WS (' ') +#define PERCENT (-2) +#define NEWLINE (-3) + +struct tm *tm; +time_t clockv; +int tmfield[5]; +FILE *f; + +int ugtokflag = FALSE; +int ugtoken; +int ufetflag = FALSE; +int ufetval; + +char *tokbuf; +int buflen = 512; +char crontab[] = "/usr/lib/crontab"; + +void oom(void) +{ + write(2, "Out of memory.\n", 15); + exit(255); +} + + +void unfetch(int c) +{ + ufetval = c; + ufetflag = TRUE; +} + +int fetch(void) +{ + register int c; + register int c2; + + if (ufetflag) { + ufetflag = FALSE; + return (ufetval); + } + + for (;;) + switch (c = getc(f)) { + case '%': + return (PERCENT); + case '\n': + return (NEWLINE); + case '\\': + if ((c2 = getc(f)) == '%') + return ('%'); + else if (c2 == '\n') + continue; + else { + ungetc(c2, f); + return ('\\'); + } + default: + return (c); + } +} + + +void ungettoken(int t) +{ + ugtokflag = TRUE; + ugtoken = t; +} + +int gettoken(void) +{ + register int c; + register char *sp = tokbuf; + register char *mark; + int posn; + + if (ugtokflag) { + ugtokflag = FALSE; + return (ugtoken); + } + + switch (c = fetch()) { + case NEWLINE: + case EOF: + case PERCENT: + return (c); + case ' ': + case '\t': + while ((c = fetch()) == ' ' || c == '\t') + ; + unfetch(c); + return (WS); + case '-': + return (DASH); + case ',': + return (COMMA); + case '*': + return (GLOB); + } + + + /* + * Case of INT. Place ascii digit string into tokbuf. + */ + if (isdigit(c)) { + *sp++ = c; + while (isdigit(c = fetch())) + *sp++ = c; + unfetch(c); + *sp = '\0'; + return (INT); + } + + /* + * The only remaining possibility is the token STR or STRPLUS. + */ + *sp++ = c; + mark = tokbuf + buflen - 2; + while ((c = fetch()) != EOF && c != NEWLINE && c != PERCENT) { + if (sp == mark) { + posn = sp - tokbuf; + tokbuf = realloc(tokbuf, (buflen += 128)); + if (tokbuf == NULL) + oom(); + sp = tokbuf + posn; + mark = sp + buflen; + } + *sp++ = c; + } + *sp = '\0'; + if (c == PERCENT) + return (STRPLUS); + unfetch(c); + return (STR); +} + +int skip_it(void) +{ + register int t; + + while ((t = gettoken()) != EOF && t != NEWLINE) + ; + return (t); +} + +int do_it(void) +{ + register int c; + register FILE *fp; + + if ((c = gettoken()) != STR && c != STRPLUS) { + ungettoken(c); + return (skip_it()); + } + if ((fp = popen(tokbuf, "w")) == NULL) { + fprintf(stderr, "Cron:\tCould not popen: %s\n", tokbuf); + perror("popen"); + return (skip_it()); + } + if (c == STR) { + fclose(fp); + return (gettoken()); + } + while ((c = fetch()) != NEWLINE && c != EOF) + if (c == PERCENT) + putc('\n', fp); + else + putc(c, fp); + putc('\n', fp); + fclose(fp); + return(c); +} + +/* + * Valid(fieldnum) parses the next time field from the current line in crontab + * and checks whether tmfield[fieldnum] satisfies the constraints of that time + * field. Returns TRUE if so, FALSE if not. Leaves f at the next field. + * Detects syntax errors in the time fields. + */ +int valid(int fieldnum) +{ + register int t; + register int ival; + register int state = START; + int ival2; + int tm_val = tmfield[fieldnum]; + + if (fieldnum == MIN) { + while ((t = gettoken()) == WS || t == NEWLINE) + ; + ungettoken(t); + } + + for (;;) { + t = gettoken(); + switch (state) { + case START: + switch (t) { + case INT: + if (strlen(tokbuf) <= 2) { + ival = atoi(tokbuf); + state = INT; + } + else + state = ERR; + break; + case GLOB: + state = GLOB; + break; + case WS: + state = END; + break; + default: + state = ERR; + break; + } + break; + case INT: + if (t == COMMA || t == WS) { + if (ival == tm_val) { + while (t != WS) + t = gettoken(); + return (TRUE); + } + state = (t == WS) ? END : START; + } + else if (t == DASH) + state = INTDASH; + else + state = ERR; + break; + case INTDASH: + if (t == INT && strlen(tokbuf) <= 2) { + ival2 = atoi(tokbuf); + state = RANGE; + } + else + state = ERR; + break; + case RANGE: + if (t == COMMA || t == WS) { + if (ival <= tm_val && tm_val <= ival2) { + while (t != WS) + t = gettoken(); + return (TRUE); + } + state = (t == WS) ? END : START; + } + else + state = ERR; + break; + case GLOB: + if (t == COMMA || t == WS) { + while (t != WS) + t = gettoken(); + return (TRUE); + } + else + state = ERR; + break; + } /* End switch on state */ + + if (state == END) + return (FALSE); + if (state == ERR) { + ungettoken(t); + ungettoken(skip_it()); + return (FALSE); + } + } +} + +/* + * Test and Execute: tests a crontab entry against the time fields in `tm' to + * see if it should be executed, if so it executes. f is left pointing to the + * next entry (line). Returns EOF when encountered, something else otherwise. + */ +int tex(void) +{ + register int fieldnum; + + for (fieldnum = MIN; fieldnum <= WDAY; ++fieldnum) + if (!valid(fieldnum)) + return (skip_it()); + return (do_it()); +} + +void catchalarm(int sig) +{ + signal(SIGALRM, catchalarm); + time(&clockv); + tm = localtime(&clockv); + alarm(61 - tm->tm_sec); +} + +void sigsetup(void) +{ + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, catchalarm); +} + +void todaemon(void) +{ + struct passwd *pwp; + + pwp = getpwnam("daemon"); + endpwent(); + if (pwp == NULL || setgid(pwp->pw_gid) || setuid(pwp->pw_uid)) + exit(1); +} + +int main(int argc, char *argv[]) +{ + int n; + sigsetup(); + + todaemon(); + tokbuf = malloc(buflen); + if (tokbuf == NULL) + oom(); + chdir("/bin"); + time(&clockv); + tm = localtime(&clockv); + alarm(61 - tm->tm_sec); + + for (;;) { + /* Put the time values into tmfield[] for easy reference. + * localtime() gives tm_mon in the range 0-11, tm_wday, 0-6 + * (0=sunday). These are adjusted for cron's syntax. + */ + tmfield[MIN] = tm->tm_min; + tmfield[HOUR] = tm->tm_hour; + tmfield[MDAY] = tm->tm_mday; + tmfield[MON] = tm->tm_mon + 1; + tmfield[WDAY] = tm->tm_wday; + + if ((f = fopen(crontab, "r")) != NULL) { + while (tex() != EOF) + ; + fclose(f); + } + while (wait(&n) != -1) + ; + if (errno == ECHILD) + pause(); + } +} +