4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / usr.sbin / cron / cron.c
CommitLineData
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
9static 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 15static 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
42char crontab[] = _PATH_CRON;
43char loc_crontab[] = _PATH_LCRON;
109f044c 44time_t itime, time();
87404803
BJ
45struct tm *loct;
46struct tm *localtime();
47char *malloc();
48char *realloc();
7f3b056b 49void reapchild();
87404803
BJ
50int flag;
51char *list;
d4692977 52char *listend;
87404803
BJ
53unsigned listsize;
54
7e82f706
KM
55FILE *debug;
56#define dprintf if (debug) fprintf
57
58main(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
150char *
151cmp(p, v)
152char *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
187slp()
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
203ex(s)
204char *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
244init()
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
258append(fn)
259char *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 269loop:
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
340ignore:
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
353number(c)
354register 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 368void
b442ae41
JB
369reapchild()
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}