cron: add cron
authorAlan Cox <alan@linux.intel.com>
Wed, 25 Oct 2017 14:57:17 +0000 (15:57 +0100)
committerAlan Cox <alan@linux.intel.com>
Wed, 25 Oct 2017 14:57:17 +0000 (15:57 +0100)
Applications/MWC/cmd/Makefile.68000
Applications/MWC/cmd/Makefile.6809
Applications/MWC/cmd/Makefile.z80
Applications/MWC/cmd/cron.c [new file with mode: 0644]

index fdf638b..68aef93 100644 (file)
@@ -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)
 
index b17966b..a7b8c0f 100644 (file)
@@ -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)
 
index 13480a3..ed0965d 100644 (file)
@@ -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 (file)
index 0000000..8709927
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/wait.h>
+
+#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();
+       }
+}
+