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