1433d6423SLionel Sambuc /* cron 1.4 - clock daemon Author: Kees J. Bot
2433d6423SLionel Sambuc * 7 Dec 1996
3433d6423SLionel Sambuc */
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #define nil ((void*)0)
6433d6423SLionel Sambuc #include <sys/types.h>
7433d6423SLionel Sambuc #include <stdio.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <string.h>
10433d6423SLionel Sambuc #include <signal.h>
11433d6423SLionel Sambuc #include <limits.h>
12433d6423SLionel Sambuc #include <dirent.h>
13433d6423SLionel Sambuc #include <time.h>
14433d6423SLionel Sambuc #include <errno.h>
15433d6423SLionel Sambuc #include <unistd.h>
16433d6423SLionel Sambuc #include <fcntl.h>
17433d6423SLionel Sambuc #include <pwd.h>
18433d6423SLionel Sambuc #include <grp.h>
19433d6423SLionel Sambuc #include <sys/stat.h>
20433d6423SLionel Sambuc #include <sys/wait.h>
21433d6423SLionel Sambuc #include "misc.h"
22433d6423SLionel Sambuc #include "tab.h"
23433d6423SLionel Sambuc
24433d6423SLionel Sambuc static volatile int busy; /* Set when something is afoot, don't sleep! */
25433d6423SLionel Sambuc static volatile int need_reload;/* Set if table reload required. */
26433d6423SLionel Sambuc static volatile int need_quit; /* Set if cron must exit. */
27433d6423SLionel Sambuc static volatile int debug; /* Debug level. */
28433d6423SLionel Sambuc
run_job(cronjob_t * job)29433d6423SLionel Sambuc static void run_job(cronjob_t *job)
30433d6423SLionel Sambuc /* Execute a cron job. Register its pid in the job structure. If a job's
31433d6423SLionel Sambuc * crontab has an owner then its output is mailed to that owner, otherwise
32433d6423SLionel Sambuc * no special provisions are made, so the output will go where cron's output
33433d6423SLionel Sambuc * goes. This keeps root's mailbox from filling up.
34433d6423SLionel Sambuc */
35433d6423SLionel Sambuc {
36433d6423SLionel Sambuc pid_t pid;
37433d6423SLionel Sambuc int need_mailer;
38433d6423SLionel Sambuc int mailfd[2], errfd[2];
39433d6423SLionel Sambuc struct passwd *pw;
40433d6423SLionel Sambuc crontab_t *tab= job->tab;
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc need_mailer= (tab->user != nil);
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc if (job->atjob) {
45433d6423SLionel Sambuc struct stat st;
46433d6423SLionel Sambuc
47433d6423SLionel Sambuc need_mailer= 1;
48433d6423SLionel Sambuc if (rename(tab->file, tab->data) < 0) {
49433d6423SLionel Sambuc if (errno == ENOENT) {
50433d6423SLionel Sambuc /* Normal error, job deleted. */
51433d6423SLionel Sambuc need_reload= 1;
52433d6423SLionel Sambuc } else {
53433d6423SLionel Sambuc /* Bad error, halt processing AT jobs. */
54*d0055759SDavid van Moolenbroek cronlog(LOG_CRIT, "Can't rename %s: %s\n",
55433d6423SLionel Sambuc tab->file, strerror(errno));
56433d6423SLionel Sambuc tab_reschedule(job);
57433d6423SLionel Sambuc }
58433d6423SLionel Sambuc return;
59433d6423SLionel Sambuc }
60433d6423SLionel Sambuc /* Will need to determine the next AT job. */
61433d6423SLionel Sambuc need_reload= 1;
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc if (stat(tab->data, &st) < 0) {
64*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "Can't stat %s: %s\n",
65433d6423SLionel Sambuc tab->data, strerror(errno));
66433d6423SLionel Sambuc tab_reschedule(job);
67433d6423SLionel Sambuc return;
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc if ((pw= getpwuid(st.st_uid)) == nil) {
70*d0055759SDavid van Moolenbroek cronlog(LOG_ERR,
71*d0055759SDavid van Moolenbroek "Unknown owner for uid %lu of AT job %s\n",
72433d6423SLionel Sambuc (unsigned long) st.st_uid, job->cmd);
73433d6423SLionel Sambuc tab_reschedule(job);
74433d6423SLionel Sambuc return;
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc } else {
77433d6423SLionel Sambuc pw= nil;
78433d6423SLionel Sambuc if (job->user != nil && (pw= getpwnam(job->user)) == nil) {
79*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "%s: Unknown user\n", job->user);
80433d6423SLionel Sambuc tab_reschedule(job);
81433d6423SLionel Sambuc return;
82433d6423SLionel Sambuc }
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if (need_mailer) {
86433d6423SLionel Sambuc errfd[0]= -1;
87433d6423SLionel Sambuc if (pipe(errfd) < 0 || pipe(mailfd) < 0) {
88*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "pipe() call failed: %s\n",
89433d6423SLionel Sambuc strerror(errno));
90433d6423SLionel Sambuc if (errfd[0] != -1) {
91433d6423SLionel Sambuc close(errfd[0]);
92433d6423SLionel Sambuc close(errfd[1]);
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc tab_reschedule(job);
95433d6423SLionel Sambuc return;
96433d6423SLionel Sambuc }
97433d6423SLionel Sambuc (void) fcntl(errfd[1], F_SETFD,
98433d6423SLionel Sambuc fcntl(errfd[1], F_GETFD) | FD_CLOEXEC);
99433d6423SLionel Sambuc
100433d6423SLionel Sambuc if ((pid= fork()) == -1) {
101*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "fork() call failed: %s\n",
102433d6423SLionel Sambuc strerror(errno));
103433d6423SLionel Sambuc close(errfd[0]);
104433d6423SLionel Sambuc close(errfd[1]);
105433d6423SLionel Sambuc close(mailfd[0]);
106433d6423SLionel Sambuc close(mailfd[1]);
107433d6423SLionel Sambuc tab_reschedule(job);
108433d6423SLionel Sambuc return;
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc
111433d6423SLionel Sambuc if (pid == 0) {
112433d6423SLionel Sambuc /* Child that is to be the mailer. */
113433d6423SLionel Sambuc char subject[70+20], *ps;
114433d6423SLionel Sambuc
115433d6423SLionel Sambuc close(errfd[0]);
116433d6423SLionel Sambuc close(mailfd[1]);
117433d6423SLionel Sambuc if (mailfd[0] != 0) {
118433d6423SLionel Sambuc dup2(mailfd[0], 0);
119433d6423SLionel Sambuc close(mailfd[0]);
120433d6423SLionel Sambuc }
121433d6423SLionel Sambuc
122433d6423SLionel Sambuc memset(subject, 0, sizeof(subject));
123433d6423SLionel Sambuc sprintf(subject,
124433d6423SLionel Sambuc "Output from your %s job: %.50s",
125433d6423SLionel Sambuc job->atjob ? "AT" : "cron",
126433d6423SLionel Sambuc job->cmd);
127433d6423SLionel Sambuc if (subject[70] != 0) {
128433d6423SLionel Sambuc strcpy(subject+70-3, "...");
129433d6423SLionel Sambuc }
130433d6423SLionel Sambuc for (ps= subject; *ps != 0; ps++) {
131433d6423SLionel Sambuc if (*ps == '\n') *ps= '%';
132433d6423SLionel Sambuc }
133433d6423SLionel Sambuc
134433d6423SLionel Sambuc execl("/usr/bin/mail", "mail", "-s", subject,
135433d6423SLionel Sambuc pw->pw_name, (char *) nil);
136433d6423SLionel Sambuc write(errfd[1], &errno, sizeof(errno));
137433d6423SLionel Sambuc _exit(1);
138433d6423SLionel Sambuc }
139433d6423SLionel Sambuc
140433d6423SLionel Sambuc close(mailfd[0]);
141433d6423SLionel Sambuc close(errfd[1]);
142433d6423SLionel Sambuc if (read(errfd[0], &errno, sizeof(errno)) > 0) {
143*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "can't execute /usr/bin/mail: %s\n",
144433d6423SLionel Sambuc strerror(errno));
145433d6423SLionel Sambuc close(errfd[0]);
146433d6423SLionel Sambuc close(mailfd[1]);
147433d6423SLionel Sambuc tab_reschedule(job);
148433d6423SLionel Sambuc return;
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc close(errfd[0]);
151433d6423SLionel Sambuc }
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc if (pipe(errfd) < 0) {
154*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "pipe() call failed: %s\n", strerror(errno));
155433d6423SLionel Sambuc if (need_mailer) close(mailfd[1]);
156433d6423SLionel Sambuc tab_reschedule(job);
157433d6423SLionel Sambuc return;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc (void) fcntl(errfd[1], F_SETFD, fcntl(errfd[1], F_GETFD) | FD_CLOEXEC);
160433d6423SLionel Sambuc
161433d6423SLionel Sambuc if ((pid= fork()) == -1) {
162*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "fork() call failed: %s\n", strerror(errno));
163433d6423SLionel Sambuc close(errfd[0]);
164433d6423SLionel Sambuc close(errfd[1]);
165433d6423SLionel Sambuc if (need_mailer) close(mailfd[1]);
166433d6423SLionel Sambuc tab_reschedule(job);
167433d6423SLionel Sambuc return;
168433d6423SLionel Sambuc }
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc if (pid == 0) {
171433d6423SLionel Sambuc /* Child that is to be the cron job. */
172433d6423SLionel Sambuc close(errfd[0]);
173433d6423SLionel Sambuc if (need_mailer) {
174433d6423SLionel Sambuc if (mailfd[1] != 1) {
175433d6423SLionel Sambuc dup2(mailfd[1], 1);
176433d6423SLionel Sambuc close(mailfd[1]);
177433d6423SLionel Sambuc }
178433d6423SLionel Sambuc dup2(1, 2);
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc if (pw != nil) {
182433d6423SLionel Sambuc /* Change id to the owner of the job. */
183433d6423SLionel Sambuc initgroups(pw->pw_name, pw->pw_gid);
184433d6423SLionel Sambuc setgid(pw->pw_gid);
185433d6423SLionel Sambuc setuid(pw->pw_uid);
186433d6423SLionel Sambuc chdir(pw->pw_dir);
187433d6423SLionel Sambuc if (setenv("USER", pw->pw_name, 1) < 0) goto bad;
188433d6423SLionel Sambuc if (setenv("LOGNAME", pw->pw_name, 1) < 0) goto bad;
189433d6423SLionel Sambuc if (setenv("HOME", pw->pw_dir, 1) < 0) goto bad;
190433d6423SLionel Sambuc if (setenv("SHELL", pw->pw_shell[0] == 0 ? "/bin/sh"
191433d6423SLionel Sambuc : pw->pw_shell, 1) < 0) goto bad;
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc
194433d6423SLionel Sambuc if (job->atjob) {
195433d6423SLionel Sambuc execl("/bin/sh", "sh", tab->data, (char *) nil);
196433d6423SLionel Sambuc } else {
197433d6423SLionel Sambuc execl("/bin/sh", "sh", "-c", job->cmd, (char *) nil);
198433d6423SLionel Sambuc }
199433d6423SLionel Sambuc bad:
200433d6423SLionel Sambuc write(errfd[1], &errno, sizeof(errno));
201433d6423SLionel Sambuc _exit(1);
202433d6423SLionel Sambuc }
203433d6423SLionel Sambuc
204433d6423SLionel Sambuc if (need_mailer) close(mailfd[1]);
205433d6423SLionel Sambuc close(errfd[1]);
206433d6423SLionel Sambuc if (read(errfd[0], &errno, sizeof(errno)) > 0) {
207*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "can't execute /bin/sh: %s\n",
208*d0055759SDavid van Moolenbroek strerror(errno));
209433d6423SLionel Sambuc close(errfd[0]);
210433d6423SLionel Sambuc tab_reschedule(job);
211433d6423SLionel Sambuc return;
212433d6423SLionel Sambuc }
213433d6423SLionel Sambuc close(errfd[0]);
214433d6423SLionel Sambuc job->pid= pid;
215433d6423SLionel Sambuc if (debug >= 1) fprintf(stderr, "executing >%s<, pid = %ld\n",
216433d6423SLionel Sambuc job->cmd, (long) job->pid);
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc
load_crontabs(void)219433d6423SLionel Sambuc static void load_crontabs(void)
220433d6423SLionel Sambuc /* Load all the crontabs we like to run. We didn't bother to make a list in
221433d6423SLionel Sambuc * an array or something, this is too system specific to make nice.
222433d6423SLionel Sambuc */
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc DIR *spool;
225433d6423SLionel Sambuc #if __minix_vmd
226433d6423SLionel Sambuc FILE *pkgs;
227433d6423SLionel Sambuc #endif
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc tab_parse("/usr/lib/crontab", nil);
230433d6423SLionel Sambuc tab_parse("/usr/local/lib/crontab", nil);
231433d6423SLionel Sambuc tab_parse("/var/lib/crontab", nil);
232433d6423SLionel Sambuc
233433d6423SLionel Sambuc #if __minix_vmd
234433d6423SLionel Sambuc if ((pkgs= fopen("/usr/lib/packages", "r")) != nil) {
235433d6423SLionel Sambuc char name[NAME_MAX+1];
236433d6423SLionel Sambuc char *np;
237433d6423SLionel Sambuc int c;
238433d6423SLionel Sambuc char tab[sizeof("/var/opt//lib/crontab") + NAME_MAX];
239433d6423SLionel Sambuc
240433d6423SLionel Sambuc while ((c= fgetc(pkgs)) != EOF) {
241433d6423SLionel Sambuc np= name;
242433d6423SLionel Sambuc while (c != EOF && c != '/' && c != '\n') {
243433d6423SLionel Sambuc if (np < name+NAME_MAX) *np++ = c;
244433d6423SLionel Sambuc c= fgetc(pkgs);
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc *np= 0;
247433d6423SLionel Sambuc while (c != EOF && c != '\n') c= fgetc(pkgs);
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc if (name[0] == 0) continue; /* ? */
250433d6423SLionel Sambuc
251433d6423SLionel Sambuc strcpy(tab, "/var/opt/");
252433d6423SLionel Sambuc strcat(tab, name);
253433d6423SLionel Sambuc strcat(tab, "/lib/crontab");
254433d6423SLionel Sambuc tab_parse(tab, nil);
255433d6423SLionel Sambuc }
256433d6423SLionel Sambuc if (ferror(pkgs)) {
257*d0055759SDavid van Moolenbroek cronlog(LOG_CRIT, "/usr/lib/packages: %s\n",
258433d6423SLionel Sambuc strerror(errno));
259433d6423SLionel Sambuc }
260433d6423SLionel Sambuc fclose(pkgs);
261433d6423SLionel Sambuc } else {
262433d6423SLionel Sambuc if (errno != ENOENT) {
263*d0055759SDavid van Moolenbroek cronlog(LOG_ERR, "/usr/lib/packages: %s\n",
264433d6423SLionel Sambuc strerror(errno));
265433d6423SLionel Sambuc }
266433d6423SLionel Sambuc }
267433d6423SLionel Sambuc #endif /* Minix-vmd */
268433d6423SLionel Sambuc
269433d6423SLionel Sambuc if ((spool= opendir("/usr/spool/crontabs")) != nil) {
270433d6423SLionel Sambuc struct dirent *entry;
271433d6423SLionel Sambuc char tab[sizeof("/usr/spool/crontabs/") + NAME_MAX];
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc while ((entry= readdir(spool)) != nil) {
274433d6423SLionel Sambuc if (entry->d_name[0] == '.') continue;
275433d6423SLionel Sambuc
276433d6423SLionel Sambuc strcpy(tab, "/usr/spool/crontabs/");
277433d6423SLionel Sambuc strcat(tab, entry->d_name);
278433d6423SLionel Sambuc tab_parse(tab, entry->d_name);
279433d6423SLionel Sambuc }
280433d6423SLionel Sambuc closedir(spool);
281433d6423SLionel Sambuc }
282433d6423SLionel Sambuc
283433d6423SLionel Sambuc /* Find the first to be executed AT job. */
284433d6423SLionel Sambuc tab_find_atjob("/usr/spool/at");
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc tab_purge();
287433d6423SLionel Sambuc if (debug >= 2) {
288433d6423SLionel Sambuc tab_print(stderr);
289433d6423SLionel Sambuc fprintf(stderr, "%lu memory chunks in use\n",
290433d6423SLionel Sambuc (unsigned long) alloc_count);
291433d6423SLionel Sambuc }
292433d6423SLionel Sambuc }
293433d6423SLionel Sambuc
handler(int sig)294433d6423SLionel Sambuc static void handler(int sig)
295433d6423SLionel Sambuc {
296433d6423SLionel Sambuc switch (sig) {
297433d6423SLionel Sambuc case SIGHUP:
298433d6423SLionel Sambuc need_reload= 1;
299433d6423SLionel Sambuc break;
300433d6423SLionel Sambuc case SIGINT:
301433d6423SLionel Sambuc case SIGTERM:
302433d6423SLionel Sambuc need_quit= 1;
303433d6423SLionel Sambuc break;
304433d6423SLionel Sambuc case SIGUSR1:
305433d6423SLionel Sambuc debug++;
306433d6423SLionel Sambuc break;
307433d6423SLionel Sambuc case SIGUSR2:
308433d6423SLionel Sambuc debug= 0;
309433d6423SLionel Sambuc break;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc alarm(1); /* A signal may come just before a blocking call. */
312433d6423SLionel Sambuc busy= 1;
313433d6423SLionel Sambuc }
314433d6423SLionel Sambuc
usage(void)315433d6423SLionel Sambuc static void usage(void)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc fprintf(stderr, "Usage: %s [-d[#]]\n", prog_name);
318433d6423SLionel Sambuc exit(1);
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc
main(int argc,char ** argv)321433d6423SLionel Sambuc int main(int argc, char **argv)
322433d6423SLionel Sambuc {
323433d6423SLionel Sambuc int i;
324433d6423SLionel Sambuc struct sigaction sa, osa;
325433d6423SLionel Sambuc FILE *pf;
326433d6423SLionel Sambuc int r;
327433d6423SLionel Sambuc
328433d6423SLionel Sambuc prog_name= strrchr(argv[0], '/');
329433d6423SLionel Sambuc if (prog_name == nil) prog_name= argv[0]; else prog_name++;
330433d6423SLionel Sambuc
331433d6423SLionel Sambuc i= 1;
332433d6423SLionel Sambuc while (i < argc && argv[i][0] == '-') {
333433d6423SLionel Sambuc char *opt= argv[i++] + 1;
334433d6423SLionel Sambuc
335433d6423SLionel Sambuc if (opt[0] == '-' && opt[1] == 0) break; /* -- */
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc while (*opt != 0) switch (*opt++) {
338433d6423SLionel Sambuc case 'd':
339433d6423SLionel Sambuc if (*opt == 0) {
340433d6423SLionel Sambuc debug= 1;
341433d6423SLionel Sambuc } else {
342433d6423SLionel Sambuc debug= strtoul(opt, &opt, 10);
343433d6423SLionel Sambuc if (*opt != 0) usage();
344433d6423SLionel Sambuc }
345433d6423SLionel Sambuc break;
346433d6423SLionel Sambuc default:
347433d6423SLionel Sambuc usage();
348433d6423SLionel Sambuc }
349433d6423SLionel Sambuc }
350433d6423SLionel Sambuc if (i != argc) usage();
351433d6423SLionel Sambuc
352433d6423SLionel Sambuc selectlog(SYSLOG);
353433d6423SLionel Sambuc openlog(prog_name, LOG_PID, LOG_DAEMON);
354433d6423SLionel Sambuc setlogmask(LOG_UPTO(LOG_INFO));
355433d6423SLionel Sambuc
356433d6423SLionel Sambuc /* Save process id. */
357433d6423SLionel Sambuc if ((pf= fopen(PIDFILE, "w")) == NULL) {
358433d6423SLionel Sambuc fprintf(stderr, "%s: %s\n", PIDFILE, strerror(errno));
359433d6423SLionel Sambuc exit(1);
360433d6423SLionel Sambuc }
361433d6423SLionel Sambuc fprintf(pf, "%d\n", getpid());
362433d6423SLionel Sambuc if (ferror(pf) || fclose(pf) == EOF) {
363433d6423SLionel Sambuc fprintf(stderr, "%s: %s\n", PIDFILE, strerror(errno));
364433d6423SLionel Sambuc exit(1);
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc
367433d6423SLionel Sambuc sigemptyset(&sa.sa_mask);
368433d6423SLionel Sambuc sa.sa_flags= 0;
369433d6423SLionel Sambuc sa.sa_handler= handler;
370433d6423SLionel Sambuc
371433d6423SLionel Sambuc /* Hangup: Reload crontab files. */
372433d6423SLionel Sambuc sigaction(SIGHUP, &sa, nil);
373433d6423SLionel Sambuc
374433d6423SLionel Sambuc /* User signal 1 & 2: Raise or reset debug level. */
375433d6423SLionel Sambuc sigaction(SIGUSR1, &sa, nil);
376433d6423SLionel Sambuc sigaction(SIGUSR2, &sa, nil);
377433d6423SLionel Sambuc
378433d6423SLionel Sambuc /* Interrupt and Terminate: Cleanup and exit. */
379433d6423SLionel Sambuc if (sigaction(SIGINT, nil, &osa) == 0 && osa.sa_handler != SIG_IGN) {
380433d6423SLionel Sambuc sigaction(SIGINT, &sa, nil);
381433d6423SLionel Sambuc }
382433d6423SLionel Sambuc if (sigaction(SIGTERM, nil, &osa) == 0 && osa.sa_handler != SIG_IGN) {
383433d6423SLionel Sambuc sigaction(SIGTERM, &sa, nil);
384433d6423SLionel Sambuc }
385433d6423SLionel Sambuc
386433d6423SLionel Sambuc /* Alarm: Wake up and run a job. */
387433d6423SLionel Sambuc sigaction(SIGALRM, &sa, nil);
388433d6423SLionel Sambuc
389433d6423SLionel Sambuc /* Initialize current time and time next to do something. */
390433d6423SLionel Sambuc time(&now);
391433d6423SLionel Sambuc next= NEVER;
392433d6423SLionel Sambuc
393433d6423SLionel Sambuc /* Table load required first time. */
394433d6423SLionel Sambuc need_reload= 1;
395433d6423SLionel Sambuc
396433d6423SLionel Sambuc do {
397433d6423SLionel Sambuc if (need_reload) {
398433d6423SLionel Sambuc need_reload= 0;
399433d6423SLionel Sambuc load_crontabs();
400433d6423SLionel Sambuc busy= 1;
401433d6423SLionel Sambuc }
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc /* Run jobs whose time has come. */
404433d6423SLionel Sambuc if (next <= now) {
405433d6423SLionel Sambuc cronjob_t *job;
406433d6423SLionel Sambuc
407433d6423SLionel Sambuc if ((job= tab_nextjob()) != nil) run_job(job);
408433d6423SLionel Sambuc busy= 1;
409433d6423SLionel Sambuc }
410433d6423SLionel Sambuc
411433d6423SLionel Sambuc if (busy) {
412433d6423SLionel Sambuc /* Did a job finish? */
413433d6423SLionel Sambuc r= waitpid(-1, nil, WNOHANG);
414433d6423SLionel Sambuc busy= 0;
415433d6423SLionel Sambuc } else {
416433d6423SLionel Sambuc /* Sleep until the next job must be started. */
417433d6423SLionel Sambuc if (next == NEVER) {
418433d6423SLionel Sambuc alarm(0);
419433d6423SLionel Sambuc } else {
420433d6423SLionel Sambuc #if __minix_vmd
421433d6423SLionel Sambuc struct timeval tvnext;
422433d6423SLionel Sambuc
423433d6423SLionel Sambuc tvnext.tv_sec= next;
424433d6423SLionel Sambuc tvnext.tv_usec= 0;
425433d6423SLionel Sambuc sysutime(UTIME_SETALARM, &tvnext);
426433d6423SLionel Sambuc #else
427433d6423SLionel Sambuc alarm((next - now) > INT_MAX
428433d6423SLionel Sambuc ? INT_MAX : (next - now));
429433d6423SLionel Sambuc #endif
430433d6423SLionel Sambuc }
431433d6423SLionel Sambuc if (debug >= 1) fprintf(stderr, "%s: sleep until %s",
432433d6423SLionel Sambuc prog_name, ctime(&next));
433433d6423SLionel Sambuc
434433d6423SLionel Sambuc closelog(); /* Don't keep resources open. */
435433d6423SLionel Sambuc
436433d6423SLionel Sambuc /* Wait for a job to exit or a timeout. */
437433d6423SLionel Sambuc r= waitpid(-1, nil, 0);
438433d6423SLionel Sambuc if (r == -1 && errno == ECHILD) pause();
439433d6423SLionel Sambuc alarm(0);
440433d6423SLionel Sambuc time(&now);
441433d6423SLionel Sambuc }
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc if (r > 0) {
444433d6423SLionel Sambuc /* A job has finished, reschedule it. */
445433d6423SLionel Sambuc if (debug >= 1) fprintf(stderr, "pid %d has exited\n",
446433d6423SLionel Sambuc r);
447433d6423SLionel Sambuc tab_reap_job((pid_t) r);
448433d6423SLionel Sambuc busy= 1;
449433d6423SLionel Sambuc }
450433d6423SLionel Sambuc } while (!need_quit);
451433d6423SLionel Sambuc
452433d6423SLionel Sambuc /* Remove the pid file to signal that cron is gone. */
453433d6423SLionel Sambuc unlink(PIDFILE);
454433d6423SLionel Sambuc
455433d6423SLionel Sambuc return 0;
456433d6423SLionel Sambuc }
457433d6423SLionel Sambuc
458433d6423SLionel Sambuc /*
459433d6423SLionel Sambuc * $PchId: cron.c,v 1.4 2000/07/17 19:00:35 philip Exp $
460433d6423SLionel Sambuc */
461