Commit | Line | Data |
---|---|---|
ce4fd43b | 1 | #ifndef lint |
109f044c | 2 | static char *sccsid = "@(#)cron.c 4.13 (Berkeley) %G%"; |
ce4fd43b SL |
3 | #endif |
4 | ||
87404803 BJ |
5 | #include <sys/types.h> |
6 | #include <stdio.h> | |
7 | #include <ctype.h> | |
8 | #include <signal.h> | |
ce4fd43b | 9 | #include <sys/time.h> |
87404803 | 10 | #include <sys/stat.h> |
b442ae41 JB |
11 | #include <sys/wait.h> |
12 | #include <sys/ioctl.h> | |
13 | #include <sys/file.h> | |
109f044c | 14 | #include <sys/resource.h> |
b442ae41 | 15 | #include <pwd.h> |
7e82f706 | 16 | #include <fcntl.h> |
109f044c | 17 | #include <syslog.h> |
87404803 | 18 | |
3eeb310b BJ |
19 | #define LISTS (2*BUFSIZ) |
20 | #define MAXLIN BUFSIZ | |
87404803 | 21 | |
b442ae41 JB |
22 | #ifndef CRONTAB |
23 | #define CRONTAB "/usr/lib/crontab" | |
24 | #endif | |
25 | ||
d4692977 JL |
26 | #ifndef CRONTABLOC |
27 | #define CRONTABLOC "/usr/lib/crontab.local" | |
28 | #endif | |
29 | ||
26fec655 BJ |
30 | #define EXACT 100 |
31 | #define ANY 101 | |
32 | #define LIST 102 | |
33 | #define RANGE 103 | |
34 | #define EOS 104 | |
d4692977 | 35 | |
b442ae41 | 36 | char crontab[] = CRONTAB; |
d4692977 | 37 | char loc_crontab[] = CRONTABLOC; |
109f044c | 38 | time_t itime, time(); |
87404803 BJ |
39 | struct tm *loct; |
40 | struct tm *localtime(); | |
41 | char *malloc(); | |
42 | char *realloc(); | |
b442ae41 | 43 | int reapchild(); |
87404803 BJ |
44 | int flag; |
45 | char *list; | |
d4692977 | 46 | char *listend; |
87404803 BJ |
47 | unsigned listsize; |
48 | ||
7e82f706 KM |
49 | FILE *debug; |
50 | #define dprintf if (debug) fprintf | |
51 | ||
52 | main(argc, argv) | |
53 | int argc; | |
54 | char **argv; | |
87404803 BJ |
55 | { |
56 | register char *cp; | |
57 | char *cmp(); | |
58 | time_t filetime = 0; | |
d4692977 | 59 | time_t lfiletime = 0; |
7e82f706 KM |
60 | char c; |
61 | extern char *optarg; | |
87404803 | 62 | |
109f044c KB |
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: | |
87404803 | 73 | exit(0); |
109f044c KB |
74 | /* NOTREACHED */ |
75 | } | |
76 | ||
7e82f706 KM |
77 | c = getopt(argc, argv, "d:"); |
78 | if (c == 'd') { | |
79 | debug = fopen(optarg, "w"); | |
80 | if (debug == NULL) | |
81 | exit(1); | |
109f044c | 82 | (void) fcntl(fileno(debug), F_SETFL, FAPPEND); |
7e82f706 | 83 | } |
109f044c KB |
84 | (void) chdir("/"); |
85 | (void) freopen("/", "r", stdout); | |
86 | (void) freopen("/", "r", stderr); | |
b442ae41 | 87 | untty(); |
109f044c KB |
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); | |
87404803 | 93 | itime -= localtime(&itime)->tm_sec; |
87404803 BJ |
94 | |
95 | for (;; itime+=60, slp()) { | |
d4692977 JL |
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) { | |
87404803 | 103 | filetime = cstat.st_mtime; |
d4692977 JL |
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) { | |
87404803 | 116 | init(); |
d4692977 JL |
117 | append(crontab); |
118 | append(loc_crontab); | |
119 | *listend++ = EOS; | |
120 | *listend++ = EOS; | |
87404803 | 121 | } |
d4692977 | 122 | |
87404803 BJ |
123 | loct = localtime(&itime); |
124 | loct->tm_mon++; /* 1-12 for month */ | |
fd14b795 | 125 | if (loct->tm_wday == 0) |
8fe4ad90 | 126 | loct->tm_wday = 7; /* sunday is 7, not 0 */ |
87404803 BJ |
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); | |
edf12f68 | 134 | if(flag == 0) |
87404803 | 135 | ex(cp); |
87404803 BJ |
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 | ||
109f044c | 184 | (void) time(&t); |
87404803 | 185 | i = itime - t; |
edf12f68 BJ |
186 | if(i < -60 * 60 || i > 60 * 60) { |
187 | itime = t; | |
188 | i = 60 - localtime(&itime)->tm_sec; | |
189 | itime += i; | |
190 | } | |
87404803 | 191 | if(i > 0) |
109f044c | 192 | sleep((u_int)i); |
87404803 BJ |
193 | } |
194 | ||
195 | ex(s) | |
196 | char *s; | |
197 | { | |
b442ae41 JB |
198 | register struct passwd *pwd; |
199 | char user[BUFSIZ]; | |
200 | char *c = user; | |
7e82f706 | 201 | int pid; |
87404803 | 202 | |
109f044c KB |
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: | |
87404803 BJ |
211 | return; |
212 | } | |
7e82f706 | 213 | pid = getpid(); |
b442ae41 JB |
214 | while(*s != ' ' && *s != '\t') |
215 | *c++ = *s++; | |
216 | *c = '\0'; | |
7e82f706 | 217 | s++; |
b442ae41 | 218 | if ((pwd = getpwnam(user)) == NULL) { |
109f044c | 219 | syslog(LOG_ERR, "invalid user name \"%s\"", user); |
7e82f706 KM |
220 | dprintf(debug, "%d: cannot find %s\n", pid, user), |
221 | fflush(debug); | |
b442ae41 JB |
222 | exit(1); |
223 | } | |
224 | (void) setgid(pwd->pw_gid); | |
109f044c | 225 | (void) initgroups(pwd->pw_name, pwd->pw_gid); |
b442ae41 | 226 | (void) setuid(pwd->pw_uid); |
109f044c KB |
227 | (void) freopen("/", "r", stdin); |
228 | closelog(); | |
7e82f706 KM |
229 | dprintf(debug, "%d: executing %s", pid, s), fflush (debug); |
230 | execl("/bin/sh", "sh", "-c", s, 0); | |
109f044c | 231 | syslog(LOG_ERR, "cannot exec /bin/sh: %m"); |
7e82f706 | 232 | dprintf(debug, "%d: cannot execute sh\n", pid), fflush (debug); |
87404803 BJ |
233 | exit(0); |
234 | } | |
235 | ||
236 | init() | |
d4692977 JL |
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; | |
87404803 BJ |
252 | { |
253 | register i, c; | |
254 | register char *cp; | |
255 | register char *ocp; | |
256 | register int n; | |
257 | ||
d4692977 JL |
258 | if (freopen(fn, "r", stdin) == NULL) |
259 | return; | |
260 | cp = listend; | |
87404803 | 261 | loop: |
3eeb310b | 262 | if(cp > list+listsize-MAXLIN) { |
d4692977 JL |
263 | int length = cp - list; |
264 | ||
87404803 | 265 | listsize += LISTS; |
87404803 | 266 | list = realloc(list, listsize); |
d4692977 | 267 | cp = list + length; |
87404803 BJ |
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) { | |
109f044c | 336 | (void) fclose(stdin); |
d4692977 | 337 | listend = cp; |
87404803 BJ |
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 | } | |
109f044c | 354 | (void) ungetc(c, stdin); |
b442ae41 | 355 | if (n>=100) |
87404803 BJ |
356 | return(-1); |
357 | return(n); | |
358 | } | |
b442ae41 JB |
359 | |
360 | reapchild() | |
361 | { | |
362 | union wait status; | |
7e82f706 | 363 | int pid; |
b442ae41 | 364 | |
109f044c | 365 | while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) |
7e82f706 KM |
366 | dprintf(debug, "%d: child exits with signal %d status %d\n", |
367 | pid, status.w_termsig, status.w_retcode), | |
368 | fflush (debug); | |
b442ae41 JB |
369 | } |
370 | ||
371 | untty() | |
372 | { | |
373 | int i; | |
374 | ||
375 | i = open("/dev/tty", O_RDWR); | |
376 | if (i >= 0) { | |
109f044c | 377 | (void) ioctl(i, TIOCNOTTY, (char *)0); |
b442ae41 JB |
378 | (void) close(i); |
379 | } | |
380 | } |