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