|
|
1.1 ! root 1: /* ! 2: * Cron. Execute commands stored in /usr/lib/crontab at preset times. ! 3: * It sets its uid and gid to those of daemon, if possible. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <time.h> ! 8: #include <signal.h> ! 9: #include <errno.h> ! 10: #include <ctype.h> ! 11: #include <pwd.h> ! 12: ! 13: #define TRUE (0 == 0) ! 14: #define FALSE (0 != 0) ! 15: ! 16: /* ! 17: * Time field types. ! 18: */ ! 19: #define MIN 0 ! 20: #define HOUR 1 ! 21: #define MDAY 2 ! 22: #define MON 3 ! 23: #define WDAY 4 ! 24: ! 25: /* ! 26: * (Finite) States in valid(). ! 27: */ ! 28: #define START 0 ! 29: #define INT 1 ! 30: #define INTDASH 2 ! 31: #define RANGE 3 ! 32: #define STR 4 ! 33: #define STRPLUS 5 ! 34: #define ERR 6 ! 35: #define END 7 ! 36: #define GLOB ('*') ! 37: ! 38: /* ! 39: * Tokens returned by gettoken(). Tokens are integers. EOF is also a token. ! 40: * INT, STR and GLOB above are also tokens. ! 41: */ ! 42: #define DASH ('-') ! 43: #define COMMA (',') ! 44: #define WS (' ') ! 45: #define PERCENT (-2) ! 46: #define NEWLINE (-3) ! 47: ! 48: struct tm *tm; ! 49: long clock; ! 50: int tmfield[5]; ! 51: FILE *f; ! 52: extern int errno; ! 53: ! 54: int ugtokflag = FALSE; ! 55: int ugtoken; ! 56: int ufetflag = FALSE; ! 57: int ufetval; ! 58: ! 59: char *tokbuf; ! 60: int buflen = 512; ! 61: char crontab[] = "/usr/lib/crontab"; ! 62: ! 63: ! 64: main() ! 65: { ! 66: int n; ! 67: sigsetup(); ! 68: ! 69: todaemon(); ! 70: tokbuf = malloc(buflen); ! 71: chdir("/bin"); ! 72: time(&clock); ! 73: tm = localtime(&clock); ! 74: alarm(61 - tm->tm_sec); ! 75: ! 76: for (;;) { ! 77: /* Put the time values into tmfield[] for easy reference. ! 78: * localtime() gives tm_mon in the range 0-11, tm_wday, 0-6 ! 79: * (0=sunday). These are adjusted for cron's syntax. ! 80: */ ! 81: tmfield[MIN] = tm->tm_min; ! 82: tmfield[HOUR] = tm->tm_hour; ! 83: tmfield[MDAY] = tm->tm_mday; ! 84: tmfield[MON] = tm->tm_mon + 1; ! 85: tmfield[WDAY] = tm->tm_wday; ! 86: ! 87: if ((f = fopen(crontab, "r")) != NULL) { ! 88: while (tex() != EOF) ! 89: ; ! 90: fclose(f); ! 91: } ! 92: while (wait(&n) != -1) ! 93: ; ! 94: if (errno == ECHILD) ! 95: pause(); ! 96: } ! 97: } ! 98: ! 99: /* ! 100: * Test and Execute: tests a crontab entry against the time fields in `tm' to ! 101: * see if it should be executed, if so it executes. f is left pointing to the ! 102: * next entry (line). Returns EOF when encountered, something else otherwise. ! 103: */ ! 104: tex() ! 105: { ! 106: register int fieldnum; ! 107: ! 108: for (fieldnum = MIN; fieldnum <= WDAY; ++fieldnum) ! 109: if (!valid(fieldnum)) ! 110: return (skip_it()); ! 111: return (do_it()); ! 112: } ! 113: ! 114: /* ! 115: * Valid(fieldnum) parses the next time field from the current line in crontab ! 116: * and checks whether tmfield[fieldnum] satisfies the constraints of that time ! 117: * field. Returns TRUE if so, FALSE if not. Leaves f at the next field. ! 118: * Detects syntax errors in the time fields. ! 119: */ ! 120: valid(fieldnum) ! 121: int fieldnum; ! 122: { ! 123: register int t; ! 124: register int ival; ! 125: register int state = START; ! 126: int ival2; ! 127: int tm_val = tmfield[fieldnum]; ! 128: ! 129: if (fieldnum == MIN) { ! 130: while ((t = gettoken()) == WS || t == NEWLINE) ! 131: ; ! 132: ungettoken(t); ! 133: } ! 134: ! 135: for (;;) { ! 136: t = gettoken(); ! 137: switch (state) { ! 138: case START: ! 139: switch (t) { ! 140: case INT: ! 141: if (strlen(tokbuf) <= 2) { ! 142: ival = atoi(tokbuf); ! 143: state = INT; ! 144: } ! 145: else ! 146: state = ERR; ! 147: break; ! 148: case GLOB: ! 149: state = GLOB; ! 150: break; ! 151: case WS: ! 152: state = END; ! 153: break; ! 154: default: ! 155: state = ERR; ! 156: break; ! 157: } ! 158: break; ! 159: case INT: ! 160: if (t == COMMA || t == WS) { ! 161: if (ival == tm_val) { ! 162: while (t != WS) ! 163: t = gettoken(); ! 164: return (TRUE); ! 165: } ! 166: state = (t == WS) ? END : START; ! 167: } ! 168: else if (t == DASH) ! 169: state = INTDASH; ! 170: else ! 171: state = ERR; ! 172: break; ! 173: case INTDASH: ! 174: if (t == INT && strlen(tokbuf) <= 2) { ! 175: ival2 = atoi(tokbuf); ! 176: state = RANGE; ! 177: } ! 178: else ! 179: state = ERR; ! 180: break; ! 181: case RANGE: ! 182: if (t == COMMA || t == WS) { ! 183: if (ival <= tm_val && tm_val <= ival2) { ! 184: while (t != WS) ! 185: t = gettoken(); ! 186: return (TRUE); ! 187: } ! 188: state = (t == WS) ? END : START; ! 189: } ! 190: else ! 191: state = ERR; ! 192: break; ! 193: case GLOB: ! 194: if (t == COMMA || t == WS) { ! 195: while (t != WS) ! 196: t = gettoken(); ! 197: return (TRUE); ! 198: } ! 199: else ! 200: state = ERR; ! 201: break; ! 202: } /* End switch on state */ ! 203: ! 204: if (state == END) ! 205: return (FALSE); ! 206: if (state == ERR) { ! 207: ungettoken(t); ! 208: ungettoken(skip_it()); ! 209: return (FALSE); ! 210: } ! 211: } ! 212: } ! 213: ! 214: ! 215: ungettoken(t) ! 216: int t; ! 217: { ! 218: ugtokflag = TRUE; ! 219: ugtoken = t; ! 220: } ! 221: ! 222: gettoken() ! 223: { ! 224: register int c; ! 225: register char *sp = tokbuf; ! 226: register char *mark; ! 227: int posn; ! 228: ! 229: if (ugtokflag) { ! 230: ugtokflag = FALSE; ! 231: return (ugtoken); ! 232: } ! 233: ! 234: switch (c = fetch()) { ! 235: case NEWLINE: ! 236: case EOF: ! 237: case PERCENT: ! 238: return (c); ! 239: case ' ': ! 240: case '\t': ! 241: while ((c = fetch()) == ' ' || c == '\t') ! 242: ; ! 243: unfetch(c); ! 244: return (WS); ! 245: case '-': ! 246: return (DASH); ! 247: case ',': ! 248: return (COMMA); ! 249: case '*': ! 250: return (GLOB); ! 251: } ! 252: ! 253: ! 254: /* ! 255: * Case of INT. Place ascii digit string into tokbuf. ! 256: */ ! 257: if (isdigit(c)) { ! 258: *sp++ = c; ! 259: while (isdigit(c = fetch())) ! 260: *sp++ = c; ! 261: unfetch(c); ! 262: *sp = '\0'; ! 263: return (INT); ! 264: } ! 265: ! 266: /* ! 267: * The only remaining possibility is the token STR or STRPLUS. ! 268: */ ! 269: *sp++ = c; ! 270: mark = tokbuf + buflen - 2; ! 271: while ((c = fetch()) != EOF && c != NEWLINE && c != PERCENT) { ! 272: if (sp == mark) { ! 273: posn = sp - tokbuf; ! 274: tokbuf = realloc(tokbuf, (buflen += 128)); ! 275: sp = tokbuf + posn; ! 276: mark = sp + buflen; ! 277: } ! 278: *sp++ = c; ! 279: } ! 280: *sp = '\0'; ! 281: if (c == PERCENT) ! 282: return (STRPLUS); ! 283: unfetch(c); ! 284: return (STR); ! 285: } ! 286: ! 287: ! 288: unfetch(c) ! 289: int c; ! 290: { ! 291: ufetval = c; ! 292: ufetflag = TRUE; ! 293: } ! 294: ! 295: fetch() ! 296: { ! 297: register int c; ! 298: register int c2; ! 299: ! 300: if (ufetflag) { ! 301: ufetflag = FALSE; ! 302: return (ufetval); ! 303: } ! 304: ! 305: for (;;) ! 306: switch (c = getc(f)) { ! 307: case '%': ! 308: return (PERCENT); ! 309: case '\n': ! 310: return (NEWLINE); ! 311: case '\\': ! 312: if ((c2 = getc(f)) == '%') ! 313: return ('%'); ! 314: else if (c2 == '\n') ! 315: continue; ! 316: else { ! 317: ungetc(c2, f); ! 318: return ('\\'); ! 319: } ! 320: default: ! 321: return (c); ! 322: } ! 323: } ! 324: ! 325: ! 326: skip_it() ! 327: { ! 328: register int t; ! 329: ! 330: while ((t = gettoken()) != EOF && t != NEWLINE) ! 331: ; ! 332: return (t); ! 333: } ! 334: ! 335: do_it() ! 336: { ! 337: register int c; ! 338: register FILE *fp; ! 339: ! 340: if ((c = gettoken()) != STR && c != STRPLUS) { ! 341: ungettoken(c); ! 342: return (skip_it()); ! 343: } ! 344: if ((fp = popen(tokbuf, "w")) == NULL) { ! 345: fprintf(stderr, "Cron:\tCould not popen: %s\n\t\ ! 346: errno = %d: %s.\n", tokbuf, errno, perror()); ! 347: return (skip_it()); ! 348: } ! 349: if (c == STR) { ! 350: fclose(fp); ! 351: return (gettoken()); ! 352: } ! 353: while ((c = fetch()) != NEWLINE && c != EOF) ! 354: if (c == PERCENT) ! 355: putc('\n', fp); ! 356: else ! 357: putc(c, fp); ! 358: putc('\n', fp); ! 359: fclose(fp); ! 360: return(c); ! 361: } ! 362: ! 363: sigsetup() ! 364: { ! 365: int catchalarm(); ! 366: ! 367: signal(SIGHUP, SIG_IGN); ! 368: signal(SIGINT, SIG_IGN); ! 369: signal(SIGPIPE, SIG_IGN); ! 370: signal(SIGALRM, catchalarm); ! 371: } ! 372: ! 373: catchalarm() ! 374: { ! 375: signal(SIGALRM, catchalarm); ! 376: time(&clock); ! 377: tm = localtime(&clock); ! 378: alarm(61 - tm->tm_sec); ! 379: } ! 380: ! 381: todaemon() ! 382: { ! 383: register struct passwd *pwp; ! 384: struct passwd *getpwnam(); ! 385: ! 386: pwp = getpwnam("daemon"); ! 387: endpwent(); ! 388: if (pwp == NULL) ! 389: return; ! 390: setgid(pwp->pw_gid); ! 391: setuid(pwp->pw_uid); ! 392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.