|
|
1.1 ! root 1: /* ! 2: * The information contained herein is a trade secret of Mark Williams ! 3: * Company, and is confidential information. It is provided under a ! 4: * license agreement, and may be copied or disclosed only under the ! 5: * terms of that agreement. Any reproduction or disclosure of this ! 6: * material without the express written authorization of Mark Williams ! 7: * Company or persuant to the license agreement is unlawful. ! 8: * ! 9: * An unpublished work by Mark Williams Company, Chicago. ! 10: * All rights reserved. ! 11: */ ! 12: ! 13: /* cron.c ! 14: * ! 15: * Execute commands stored in /usr/lib/crontab if it exist (3.2.0 compatibility) ! 16: * as daemon. ! 17: * Otherwise execute crontabs from /usr/spool/cron/crontabs. ! 18: * It sets uid and gid to user which crontab is going to be executed. ! 19: * ! 20: * $ 12-10-1991 vlad (Vladimir Smelyansky) ! 21: * ! 22: */ ! 23: #include <stdio.h> ! 24: #include <time.h> ! 25: #include <signal.h> ! 26: #include <sys/msig.h> ! 27: #include <errno.h> ! 28: #include <ctype.h> ! 29: #include <pwd.h> ! 30: #include <sys/types.h> ! 31: #include <dirent.h> ! 32: #include "cron.h" ! 33: ! 34: /* ! 35: * Time field types. ! 36: */ ! 37: #define MIN 0 ! 38: #define HOUR 1 ! 39: #define MDAY 2 ! 40: #define MON 3 ! 41: #define WDAY 4 ! 42: ! 43: /* ! 44: * (Finite) States in valid(). ! 45: */ ! 46: #define START 0 ! 47: #define INT 1 ! 48: #define INTDASH 2 ! 49: #define RANGE 3 ! 50: #define STR 4 ! 51: #define STRPLUS 5 ! 52: #define ERR 6 ! 53: #define END 7 ! 54: #define GLOB ('*') ! 55: ! 56: /* ! 57: * Tokens returned by gettoken(). Tokens are integers. EOF is also a token. ! 58: * INT, STR and GLOB above are also tokens. ! 59: */ ! 60: #define DASH ('-') ! 61: #define COMMA (',') ! 62: #define WS (' ') ! 63: #define PERCENT (-2) ! 64: #define NEWLINE (-3) ! 65: ! 66: extern DIR *opendir(); ! 67: extern struct dirent *readdir(); ! 68: extern char *realloc(); ! 69: ! 70: extern int set_uid(); /* Set UID */ ! 71: extern FILE *fpOpenTable(); /* Open crintable */ ! 72: extern int lock(); /* Write a lock file */ ! 73: extern FILE *cronpipe(); /* Popen for cron */ ! 74: ! 75: extern void mail_entry(); /* Send mail to user if command failed */ ! 76: extern child_id *add_entry(), /* Add an new entry to a link list */ ! 77: *find_entry(), /* Find an entry in the link list */ ! 78: *del_entry(); /* Remove an entry from the link list */ ! 79: ! 80: int ifmail(); ! 81: ! 82: child_id *current; /* Pointer to the current structure */ ! 83: char acRealUser[MAX_UNAME]; /* Real user name */ ! 84: ! 85: int mailFlag = TRUE; ! 86: int flag320 = FALSE; ! 87: ! 88: struct tm *tm; ! 89: time_t clock; ! 90: int tmfield[5]; ! 91: FILE *f; ! 92: extern int errno; ! 93: ! 94: int ugtokflag = FALSE; ! 95: int ugtoken; ! 96: int ufetflag = FALSE; ! 97: int ufetval; ! 98: int set_uid_flag = FALSE; ! 99: ! 100: char *tokbuf; ! 101: int buflen = MAX_STR_LEN; ! 102: char crontab[] = "/usr/lib/crontab"; ! 103: DIR *dirp = NULL; ! 104: struct dirent *dp; ! 105: ! 106: main() ! 107: { ! 108: int n; ! 109: int child_pid; ! 110: ! 111: sigsetup(); ! 112: ! 113: tokbuf = malloc(buflen); ! 114: /* Check if crond chould be into cron 320 mode */ ! 115: if ((f = fopen(crontab, "r")) != NULL) { ! 116: fclose(f); ! 117: chdir("/bin"); /* Under 3.2.0 cron started from /bin. */ ! 118: flag320 = TRUE; ! 119: } ! 120: ! 121: if (flag320 == FALSE) { ! 122: /* Check if cron was fired. Do it only for SV cron. */ ! 123: if (lock(F_LOCK) == FALSE) { ! 124: fprintf(stderr, "crond: locked.\n"); ! 125: exit(1); ! 126: } ! 127: /* Open dirp only once */ ! 128: /*if ((dirp = opendir(D_SPOOL)) == NULL) { ! 129: fprintf(stderr, ! 130: "crond: cannot open directory %s.\n", D_SPOOL); ! 131: exit(1); ! 132: }*/ ! 133: } ! 134: ! 135: #if !DEBUG ! 136: /* Disassociate from controling terminal and process ! 137: * group. Close all open files. ! 138: */ ! 139: bedaemon(); ! 140: #endif ! 141: ! 142: time(&clock); ! 143: tm = localtime(&clock); ! 144: alarm(61 - tm->tm_sec); ! 145: ! 146: Dprint("Time is %s\n", ctime(&clock)); ! 147: for (;;) { ! 148: system("echo Debug1 >/dev/console"); ! 149: /* Put the time values into tmfield[] for easy reference. ! 150: * localtime() gives tm_mon in the range 0-11, tm_wday, 0-6 ! 151: * (0=sunday). These are adjusted for cron's syntax. ! 152: */ ! 153: tmfield[MIN] = tm->tm_min; ! 154: tmfield[HOUR] = tm->tm_hour; ! 155: tmfield[MDAY] = tm->tm_mday; ! 156: tmfield[MON] = tm->tm_mon + 1; ! 157: tmfield[WDAY] = tm->tm_wday; ! 158: ! 159: if (flag320 == TRUE) { /* Run 320 mode */ ! 160: system("echo Debug1 286>/dev/console"); ! 161: if ((f = fopen(crontab, "r")) != NULL) { ! 162: Dprint("File pointer is 0x%x\n", f); ! 163: strcpy(acRealUser, DAEMON); ! 164: while (tex() != EOF) ! 165: ; ! 166: fclose(f); ! 167: while (wait(&n) != -1) ! 168: ; ! 169: if (errno == ECHILD) ! 170: pause(); ! 171: } else ! 172: fprintf(stderr, "crond: cannot open %s\n", ! 173: crontab); ! 174: } else { /* Run SV mode */ ! 175: system("echo Debug1 386>/dev/console"); ! 176: /* Open dirp only once */ ! 177: if (dirp != NULL) ! 178: if ((dirp = opendir(D_SPOOL)) == NULL) { ! 179: fprintf(stderr, ! 180: "crond: cannot open directory %s.\n", D_SPOOL); ! 181: exit(1); ! 182: } ! 183: ! 184: while ((dp = readdir(dirp)) != NULL) { ! 185: char Dbuf[80]; ! 186: ! 187: /* Skip '.' and '..' */ ! 188: if (!strcmp(dp->d_name, ".") || ! 189: !strcmp(dp->d_name, "..")) ! 190: continue; ! 191: ! 192: strcpy(acRealUser, dp->d_name); ! 193: Dprint("User name is %s\n", acRealUser); ! 194: set_uid_flag = FALSE; ! 195: ! 196: if ((f = fpOpenTable("r")) == NULL) { ! 197: fprintf(stderr, ! 198: "crond: cannot open table '%s'\n", ! 199: acRealUser); ! 200: sprintf(Dbuf,"crond: cannot open table" ! 201: " '%s'\n", acRealUser); ! 202: /*exit(1);*/ ! 203: } ! 204: system("echo Debug >/dev/console"); ! 205: sprintf(Dbuf, "echo %s > /dev/console", dp->d_name); ! 206: system(Dbuf); ! 207: while (tex() != EOF) ! 208: ; ! 209: fclose(f); ! 210: } /* while readdir */ ! 211: system("echo Debug after while >/dev/console"); ! 212: rewinddir(dirp); ! 213: /* Wait for the children */ ! 214: while ((child_pid = wait(&n)) != -1) { ! 215: static child_id *pstDone; ! 216: ! 217: Dprint("\nmain: child id %d",child_pid); ! 218: Dprint("\treturn is %d\n", n); ! 219: pstDone = find_entry(child_pid); ! 220: if (n && ifmail(pstDone)) ! 221: mail_entry(pstDone); ! 222: ! 223: current = del_entry(pstDone); ! 224: } /* while wait */ ! 225: if (errno == ECHILD) ! 226: pause(); ! 227: ! 228: } /* if 320 */ ! 229: } /* for */ ! 230: } /* main */ ! 231: ! 232: /* ! 233: * Check do user want to have a mail messages. ! 234: */ ! 235: int ifmail(entry) ! 236: child_id *entry; ! 237: { ! 238: char *cBuf; ! 239: int fd; /* Descriptor of lock file */ ! 240: ! 241: if ((cBuf = malloc(sizeof(D_MAIN) + strlen(entry->name) + 1)) == NULL) { ! 242: fprintf(stderr, "crond: out of memory\n"); ! 243: return(0); ! 244: } ! 245: sprintf(cBuf, "%s/%s", D_MAIN, entry->name); ! 246: if ((fd = open(cBuf, 0)) == -1) ! 247: return(1); ! 248: close(fd); ! 249: return(0); ! 250: } ! 251: ! 252: /* ! 253: * Test and Execute: tests a crontab entry against the time fields in `tm' to ! 254: * see if it should be executed, if so it executes. f is left pointing to the ! 255: * next entry (line). Returns EOF when encountered, something else otherwise. ! 256: */ ! 257: tex() ! 258: { ! 259: register int fieldnum; ! 260: ! 261: for (fieldnum = MIN; fieldnum <= WDAY; ++fieldnum) ! 262: if (!valid(fieldnum)) ! 263: return (skip_it()); ! 264: return (do_it()); ! 265: } ! 266: ! 267: /* ! 268: * Valid(fieldnum) parses the next time field from the current line in crontab ! 269: * and checks whether tmfield[fieldnum] satisfies the constraints of that time ! 270: * field. Returns TRUE if so, FALSE if not. Leaves f at the next field. ! 271: * Detects syntax errors in the time fields. ! 272: */ ! 273: valid(fieldnum) ! 274: int fieldnum; ! 275: { ! 276: register int t; ! 277: register int ival; ! 278: register int state = START; ! 279: int ival2; ! 280: int tm_val = tmfield[fieldnum]; ! 281: ! 282: if (fieldnum == MIN) { ! 283: while ((t = gettoken()) == WS || t == NEWLINE) ! 284: ; ! 285: ungettoken(t); ! 286: } ! 287: ! 288: for (;;) { ! 289: t = gettoken(); ! 290: switch (state) { ! 291: case START: ! 292: switch (t) { ! 293: case INT: ! 294: if (strlen(tokbuf) <= 2) { ! 295: ival = atoi(tokbuf); ! 296: state = INT; ! 297: } ! 298: else ! 299: state = ERR; ! 300: break; ! 301: case GLOB: ! 302: state = GLOB; ! 303: break; ! 304: case WS: ! 305: state = END; ! 306: break; ! 307: default: ! 308: state = ERR; ! 309: break; ! 310: } ! 311: break; ! 312: case INT: ! 313: if (t == COMMA || t == WS) { ! 314: if (ival == tm_val) { ! 315: while (t != WS) ! 316: t = gettoken(); ! 317: return (TRUE); ! 318: } ! 319: state = (t == WS) ? END : START; ! 320: } ! 321: else if (t == DASH) ! 322: state = INTDASH; ! 323: else ! 324: state = ERR; ! 325: break; ! 326: case INTDASH: ! 327: if (t == INT && strlen(tokbuf) <= 2) { ! 328: ival2 = atoi(tokbuf); ! 329: state = RANGE; ! 330: } ! 331: else ! 332: state = ERR; ! 333: break; ! 334: case RANGE: ! 335: if (t == COMMA || t == WS) { ! 336: if (ival <= tm_val && tm_val <= ival2) { ! 337: while (t != WS) ! 338: t = gettoken(); ! 339: return (TRUE); ! 340: } ! 341: state = (t == WS) ? END : START; ! 342: } ! 343: else ! 344: state = ERR; ! 345: break; ! 346: case GLOB: ! 347: if (t == COMMA || t == WS) { ! 348: while (t != WS) ! 349: t = gettoken(); ! 350: return (TRUE); ! 351: } ! 352: else ! 353: state = ERR; ! 354: break; ! 355: } /* End switch on state */ ! 356: ! 357: if (state == END) ! 358: return (FALSE); ! 359: if (state == ERR) { ! 360: ungettoken(t); ! 361: ungettoken(skip_it()); ! 362: return (FALSE); ! 363: } ! 364: } ! 365: } ! 366: ! 367: ! 368: ungettoken(t) ! 369: int t; ! 370: { ! 371: ugtokflag = TRUE; ! 372: ugtoken = t; ! 373: } ! 374: ! 375: gettoken() ! 376: { ! 377: register int c; ! 378: register char *sp = tokbuf; ! 379: register char *mark; ! 380: int posn; ! 381: ! 382: if (ugtokflag) { ! 383: ugtokflag = FALSE; ! 384: return (ugtoken); ! 385: } ! 386: ! 387: switch (c = fetch()) { ! 388: case NEWLINE: ! 389: case EOF: ! 390: case PERCENT: ! 391: return (c); ! 392: case ' ': ! 393: case '\t': ! 394: while ((c = fetch()) == ' ' || c == '\t') ! 395: ; ! 396: unfetch(c); ! 397: return (WS); ! 398: case '-': ! 399: return (DASH); ! 400: case ',': ! 401: return (COMMA); ! 402: case '*': ! 403: return (GLOB); ! 404: } ! 405: ! 406: ! 407: /* ! 408: * Case of INT. Place ascii digit string into tokbuf. ! 409: */ ! 410: if (isdigit(c)) { ! 411: *sp++ = c; ! 412: while (isdigit(c = fetch())) ! 413: *sp++ = c; ! 414: unfetch(c); ! 415: *sp = '\0'; ! 416: return (INT); ! 417: } ! 418: ! 419: /* ! 420: * The only remaining possibility is the token STR or STRPLUS. ! 421: */ ! 422: *sp++ = c; ! 423: mark = tokbuf + buflen - 2; ! 424: while ((c = fetch()) != EOF && c != NEWLINE && c != PERCENT) { ! 425: if (sp == mark) { ! 426: posn = sp - tokbuf; ! 427: tokbuf = realloc(tokbuf, (buflen += 128)); ! 428: sp = tokbuf + posn; ! 429: mark = sp + buflen; ! 430: } ! 431: *sp++ = c; ! 432: } ! 433: *sp = '\0'; ! 434: if (c == PERCENT) ! 435: return (STRPLUS); ! 436: unfetch(c); ! 437: return (STR); ! 438: } ! 439: ! 440: ! 441: unfetch(c) ! 442: int c; ! 443: { ! 444: ufetval = c; ! 445: ufetflag = TRUE; ! 446: } ! 447: ! 448: fetch() ! 449: { ! 450: register int c; ! 451: register int c2; ! 452: ! 453: if (ufetflag) { ! 454: ufetflag = FALSE; ! 455: return (ufetval); ! 456: } ! 457: ! 458: for (;;) ! 459: switch (c = getc(f)) { ! 460: case '%': ! 461: return (PERCENT); ! 462: case '\n': ! 463: return (NEWLINE); ! 464: case '\\': ! 465: if ((c2 = getc(f)) == '%') ! 466: return ('%'); ! 467: else if (c2 == '\n') ! 468: continue; ! 469: else { ! 470: ungetc(c2, f); ! 471: return ('\\'); ! 472: } ! 473: default: ! 474: return (c); ! 475: } ! 476: } ! 477: ! 478: ! 479: skip_it() ! 480: { ! 481: register int t; ! 482: ! 483: while ((t = gettoken()) != EOF && t != NEWLINE) ! 484: ; ! 485: return (t); ! 486: } ! 487: ! 488: do_it() ! 489: { ! 490: register int c; ! 491: register FILE *fp; ! 492: ! 493: if ((c = gettoken()) != STR && c != STRPLUS) { ! 494: ungettoken(c); ! 495: return (skip_it()); ! 496: } ! 497: ! 498: Dprint("Tokken is %s\n", tokbuf); ! 499: ! 500: if ((fp = cronpipe(tokbuf, "w")) == NULL) { ! 501: fprintf(stderr, "crond:\tCould not popen: %s\n\t\ ! 502: errno = %d: %s.\n", tokbuf, errno, perror()); ! 503: return (skip_it()); ! 504: } ! 505: ! 506: if (c == STR) { ! 507: fclose(fp); ! 508: return (gettoken()); ! 509: } ! 510: while ((c = fetch()) != NEWLINE && c != EOF) ! 511: if (c == PERCENT) ! 512: putc('\n', fp); ! 513: else ! 514: putc(c, fp); ! 515: putc('\n', fp); ! 516: fclose(fp); ! 517: return(c); ! 518: } ! 519: ! 520: /* ! 521: * We have to catch all signals. ! 522: * Ignore signals INT, HUP, & PIPE. ! 523: * Reset time on ALRM. ! 524: * Remove lock file and take default action on the rest of them. ! 525: */ ! 526: sigsetup() ! 527: { ! 528: register int i; ! 529: int catchalarm(); /* Catch alarm signal */ ! 530: int catchsignals(); /* Catch all signals */ ! 531: ! 532: for (i = 1; i < NSIG; i++) ! 533: signal(i, catchsignals); ! 534: ! 535: signal(SIGINT, SIG_IGN); ! 536: signal(SIGHUP, SIG_IGN); ! 537: signal(SIGPIPE, SIG_IGN); ! 538: signal(SIGALRM, catchalarm); ! 539: } ! 540: ! 541: /* ! 542: * Remove lock file. Restore default action. Send the catched signal to itself. ! 543: */ ! 544: int catchsignals(sig) ! 545: int sig; ! 546: { ! 547: unlink(F_LOCK); /* Remove lock FIFO. Do not care if unlink */ ! 548: /* failed (case cron 3.2.0) */ ! 549: Dprint("Remove lock file %s\n", F_LOCK); ! 550: signal(sig, SIG_DFL); /* Reset to default */ ! 551: kill(getpid(), sig); /* Send catched signal */ ! 552: wait(); ! 553: } ! 554: ! 555: /* ! 556: * Catch alarm. ! 557: */ ! 558: int catchalarm() ! 559: { ! 560: signal(SIGALRM, catchalarm); ! 561: time(&clock); ! 562: tm = localtime(&clock); ! 563: alarm(61 - tm->tm_sec); ! 564: } ! 565:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.