|
|
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.