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