|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)cron.c 4.16 (Berkeley) 6/29/90";
3: #endif
4:
5: #include <sys/types.h>
6: #include <sys/signal.h>
7: #include <sys/time.h>
8: #include <sys/stat.h>
9: #include <sys/wait.h>
10: #include <sys/ioctl.h>
11: #include <sys/file.h>
12: #include <sys/resource.h>
13: #include <pwd.h>
14: #include <fcntl.h>
15: #include <syslog.h>
16: #include <stdio.h>
17: #include <ctype.h>
18: #include "pathnames.h"
19:
20: #define LISTS (2*BUFSIZ)
21: #define MAXLIN BUFSIZ
22:
23: #define EXACT 100
24: #define ANY 101
25: #define LIST 102
26: #define RANGE 103
27: #define EOS 104
28:
29: char crontab[] = _PATH_CRON;
30: char loc_crontab[] = _PATH_LCRON;
31: time_t itime, time();
32: struct tm *loct;
33: struct tm *localtime();
34: char *malloc();
35: char *realloc();
36: int reapchild();
37: int flag;
38: char *list;
39: char *listend;
40: unsigned listsize;
41:
42: FILE *debug;
43: #define dprintf if (debug) fprintf
44:
45: main(argc, argv)
46: int argc;
47: char **argv;
48: {
49: register char *cp;
50: char *cmp();
51: time_t filetime = 0;
52: time_t lfiletime = 0;
53: char c;
54: extern char *optarg;
55:
56: if (geteuid()) {
57: fprintf(stderr, "cron: NOT super-user\n");
58: exit(1);
59: }
60:
61: openlog("cron", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_DAEMON);
62: switch (fork()) {
63:
64: case -1:
65: syslog(LOG_ERR, "fork: %m");
66: exit(1);
67: /* NOTREACHED */
68: case 0:
69: break;
70: default:
71: exit(0);
72: /* NOTREACHED */
73: }
74:
75: c = getopt(argc, argv, "d:");
76: if (c == 'd') {
77: debug = fopen(optarg, "w");
78: if (debug == NULL)
79: exit(1);
80: (void) fcntl(fileno(debug), F_SETFL, FAPPEND);
81: }
82: daemon(0, 0);
83: (void) signal(SIGHUP, SIG_IGN);
84: (void) signal(SIGINT, SIG_IGN);
85: (void) signal(SIGQUIT, SIG_IGN);
86: (void) signal(SIGCHLD, reapchild);
87: (void) time(&itime);
88: itime -= localtime(&itime)->tm_sec;
89:
90: for (;; itime+=60, slp()) {
91: struct stat cstat, lcstat;
92: int newcron, newloc;
93:
94: newcron = 0;
95: if (stat(crontab, &cstat) < 0)
96: cstat.st_mtime = 1;
97: if (cstat.st_mtime != filetime) {
98: filetime = cstat.st_mtime;
99: newcron++;
100: }
101:
102: newloc = 0;
103: if (stat(loc_crontab, &lcstat) < 0)
104: lcstat.st_mtime = 1;
105: if (lcstat.st_mtime != lfiletime) {
106: lfiletime = lcstat.st_mtime;
107: newloc++;
108: }
109:
110: if (newcron || newloc) {
111: init();
112: append(crontab);
113: append(loc_crontab);
114: *listend++ = EOS;
115: *listend++ = EOS;
116: }
117:
118: loct = localtime(&itime);
119: loct->tm_mon++; /* 1-12 for month */
120: if (loct->tm_wday == 0)
121: loct->tm_wday = 7; /* sunday is 7, not 0 */
122: for(cp = list; *cp != EOS;) {
123: flag = 0;
124: cp = cmp(cp, loct->tm_min);
125: cp = cmp(cp, loct->tm_hour);
126: cp = cmp(cp, loct->tm_mday);
127: cp = cmp(cp, loct->tm_mon);
128: cp = cmp(cp, loct->tm_wday);
129: if(flag == 0)
130: ex(cp);
131: while(*cp++ != 0)
132: ;
133: }
134: }
135: }
136:
137: char *
138: cmp(p, v)
139: char *p;
140: {
141: register char *cp;
142:
143: cp = p;
144: switch(*cp++) {
145:
146: case EXACT:
147: if (*cp++ != v)
148: flag++;
149: return(cp);
150:
151: case ANY:
152: return(cp);
153:
154: case LIST:
155: while(*cp != LIST)
156: if(*cp++ == v) {
157: while(*cp++ != LIST)
158: ;
159: return(cp);
160: }
161: flag++;
162: return(cp+1);
163:
164: case RANGE:
165: if(*cp > v || cp[1] < v)
166: flag++;
167: return(cp+2);
168: }
169: if(cp[-1] != v)
170: flag++;
171: return(cp);
172: }
173:
174: slp()
175: {
176: register i;
177: time_t t;
178:
179: (void) time(&t);
180: i = itime - t;
181: if(i < -60 * 60 || i > 60 * 60) {
182: itime = t;
183: i = 60 - localtime(&itime)->tm_sec;
184: itime += i;
185: }
186: if(i > 0)
187: sleep((u_int)i);
188: }
189:
190: ex(s)
191: char *s;
192: {
193: register struct passwd *pwd;
194: char user[BUFSIZ];
195: char *c = user;
196: int pid;
197:
198: switch (fork()) {
199: case 0:
200: break;
201: case -1:
202: syslog(LOG_ERR, "cannot fork: %m (running %.40s%s)",
203: s, strlen(s) > 40 ? "..." : "");
204: /*FALLTHROUGH*/
205: default:
206: return;
207: }
208: pid = getpid();
209: while(*s != ' ' && *s != '\t')
210: *c++ = *s++;
211: *c = '\0';
212: s++;
213: if ((pwd = getpwnam(user)) == NULL) {
214: syslog(LOG_ERR, "invalid user name \"%s\"", user);
215: dprintf(debug, "%d: cannot find %s\n", pid, user),
216: fflush(debug);
217: exit(1);
218: }
219: (void) setgid(pwd->pw_gid);
220: (void) initgroups(pwd->pw_name, pwd->pw_gid);
221: (void) setuid(pwd->pw_uid);
222: (void) freopen("/", "r", stdin);
223: closelog();
224: dprintf(debug, "%d: executing %s", pid, s), fflush (debug);
225: execl(_PATH_BSHELL, "sh", "-c", s, 0);
226: syslog(LOG_ERR, "cannot exec %s: %m");
227: dprintf(debug, "%d: cannot execute sh\n", pid), fflush (debug);
228: exit(0);
229: }
230:
231: init()
232: {
233: /*
234: * Don't free in case was longer than LISTS. Trades off
235: * the rare case of crontab shrinking vs. the common case of
236: * extra realloc's needed in append() for a large crontab.
237: */
238: if (list == 0) {
239: list = malloc(LISTS);
240: listsize = LISTS;
241: }
242: listend = list;
243: }
244:
245: append(fn)
246: char *fn;
247: {
248: register i, c;
249: register char *cp;
250: register char *ocp;
251: register int n;
252:
253: if (freopen(fn, "r", stdin) == NULL)
254: return;
255: cp = listend;
256: loop:
257: if(cp > list+listsize-MAXLIN) {
258: int length = cp - list;
259:
260: listsize += LISTS;
261: list = realloc(list, listsize);
262: cp = list + length;
263: }
264: ocp = cp;
265: for(i=0;; i++) {
266: do
267: c = getchar();
268: while(c == ' ' || c == '\t')
269: ;
270: if(c == EOF || c == '\n')
271: goto ignore;
272: if(i == 5)
273: break;
274: if(c == '*') {
275: *cp++ = ANY;
276: continue;
277: }
278: if ((n = number(c)) < 0)
279: goto ignore;
280: c = getchar();
281: if(c == ',')
282: goto mlist;
283: if(c == '-')
284: goto mrange;
285: if(c != '\t' && c != ' ')
286: goto ignore;
287: *cp++ = EXACT;
288: *cp++ = n;
289: continue;
290:
291: mlist:
292: *cp++ = LIST;
293: *cp++ = n;
294: do {
295: if ((n = number(getchar())) < 0)
296: goto ignore;
297: *cp++ = n;
298: c = getchar();
299: } while (c==',');
300: if(c != '\t' && c != ' ')
301: goto ignore;
302: *cp++ = LIST;
303: continue;
304:
305: mrange:
306: *cp++ = RANGE;
307: *cp++ = n;
308: if ((n = number(getchar())) < 0)
309: goto ignore;
310: c = getchar();
311: if(c != '\t' && c != ' ')
312: goto ignore;
313: *cp++ = n;
314: }
315: while(c != '\n') {
316: if(c == EOF)
317: goto ignore;
318: if(c == '%')
319: c = '\n';
320: *cp++ = c;
321: c = getchar();
322: }
323: *cp++ = '\n';
324: *cp++ = 0;
325: goto loop;
326:
327: ignore:
328: cp = ocp;
329: while(c != '\n') {
330: if(c == EOF) {
331: (void) fclose(stdin);
332: listend = cp;
333: return;
334: }
335: c = getchar();
336: }
337: goto loop;
338: }
339:
340: number(c)
341: register c;
342: {
343: register n = 0;
344:
345: while (isdigit(c)) {
346: n = n*10 + c - '0';
347: c = getchar();
348: }
349: (void) ungetc(c, stdin);
350: if (n>=100)
351: return(-1);
352: return(n);
353: }
354:
355: reapchild()
356: {
357: union wait status;
358: int pid;
359:
360: while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0)
361: dprintf(debug, "%d: child exits with signal %d status %d\n",
362: pid, status.w_termsig, status.w_retcode),
363: fflush (debug);
364: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.