xref: /minix3/minix/commands/cron/cron.c (revision d0055759dd8892194db7fce6acc5085d5c9aeaee)
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