add xref to fsdb(8)
[unix-history] / usr / src / usr.sbin / cron / cron.c
CommitLineData
ce4fd43b 1#ifndef lint
109f044c 2static 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 36char crontab[] = CRONTAB;
d4692977 37char loc_crontab[] = CRONTABLOC;
109f044c 38time_t itime, time();
87404803
BJ
39struct tm *loct;
40struct tm *localtime();
41char *malloc();
42char *realloc();
b442ae41 43int reapchild();
87404803
BJ
44int flag;
45char *list;
d4692977 46char *listend;
87404803
BJ
47unsigned listsize;
48
7e82f706
KM
49FILE *debug;
50#define dprintf if (debug) fprintf
51
52main(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
142char *
143cmp(p, v)
144char *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
179slp()
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
195ex(s)
196char *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
236init()
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
250append(fn)
251char *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 261loop:
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
332ignore:
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
345number(c)
346register 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
360reapchild()
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
371untty()
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}