1 /* Copyright 1988,1990,1993 by Paul Vixie
4 * Distribute freely, except: don't remove my name from the source or
5 * documentation (don't take credit for my work), mark your changes (don't
6 * get me blamed for your possible bugs), don't alter or remove this
7 * notice. May be sold if buildable source is provided to buyer. No
8 * warrantee of any kind, express or implied, is included with this
9 * software; use at your own risk, responsibility for damages (if any) to
10 * anyone resulting from the use of this software rests entirely with the
13 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
14 * I'll try to keep a version up to date. I can be reached as follows:
15 * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
18 #if !defined(lint) && !defined(LINT)
19 static char rcsid
[] = "$Id: cron.c,v 1.1 1994/01/05 20:40:12 jtc Exp $";
28 #include <sys/signal.h>
30 # include <sys/time.h>
36 static void usage
__P((void)),
37 run_reboot_jobs
__P((cron_db
*)),
38 cron_tick
__P((cron_db
*)),
39 cron_sync
__P((void)),
40 cron_sleep
__P((void)),
42 sigchld_handler
__P((int)),
44 parse_args
__P((int c
, char *v
[]));
49 fprintf(stderr
, "usage: %s [-x debugflag[,...]]\n", ProgramName
);
61 ProgramName
= argv
[0];
68 parse_args(argc
, argv
);
71 (void) signal(SIGCHLD
, sigchld_handler
);
73 (void) signal(SIGCLD
, SIG_IGN
);
76 acquire_daemonlock(0);
81 setenv("PATH", _PATH_DEFPATH
, 1);
84 /* if there are no debug flags turned on, fork as a daemon should.
91 (void) fprintf(stderr
, "[%d] cron started\n", getpid());
95 log_it("CRON",getpid(),"DEATH","can't fork");
100 log_it("CRON",getpid(),"STARTUP","fork ok");
104 /* parent process should just die */
109 acquire_daemonlock(0);
110 database
.head
= NULL
;
111 database
.tail
= NULL
;
112 database
.mtime
= (time_t) 0;
113 load_database(&database
);
114 run_reboot_jobs(&database
);
118 if (!(DebugFlags
& DTEST
))
119 # endif /*DEBUGGING*/
122 load_database(&database
);
126 cron_tick(&database
);
142 for (u
= db
->head
; u
!= NULL
; u
= u
->next
) {
143 for (e
= u
->crontab
; e
!= NULL
; e
= e
->next
) {
144 if (e
->flags
& WHEN_REBOOT
) {
149 (void) job_runqueue();
157 register struct tm
*tm
= localtime(&TargetTime
);
158 register int minute
, hour
, dom
, month
, dow
;
162 /* make 0-based values out of these so we can use them as indicies
164 minute
= tm
->tm_min
-FIRST_MINUTE
;
165 hour
= tm
->tm_hour
-FIRST_HOUR
;
166 dom
= tm
->tm_mday
-FIRST_DOM
;
167 month
= tm
->tm_mon
+1 /* 0..11 -> 1..12 */ -FIRST_MONTH
;
168 dow
= tm
->tm_wday
-FIRST_DOW
;
170 Debug(DSCH
, ("[%d] tick(%d,%d,%d,%d,%d)\n",
171 getpid(), minute
, hour
, dom
, month
, dow
))
173 /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
174 * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
175 * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
176 * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
177 * like many bizarre things, it's the standard.
179 for (u
= db
->head
; u
!= NULL
; u
= u
->next
) {
180 Debug(DSCH
|DEXT
, ("user [%s:%d:%d:...]\n",
181 env_get("LOGNAME", u
->envp
), u
->uid
, u
->gid
))
182 for (e
= u
->crontab
; e
!= NULL
; e
= e
->next
) {
183 Debug(DSCH
|DEXT
, ("entry [%s]\n", e
->cmd
))
184 if (bit_test(e
->minute
, minute
)
185 && bit_test(e
->hour
, hour
)
186 && bit_test(e
->month
, month
)
187 && ( ((e
->flags
& DOM_STAR
) || (e
->flags
& DOW_STAR
))
188 ? (bit_test(e
->dow
,dow
) && bit_test(e
->dom
,dom
))
189 : (bit_test(e
->dow
,dow
) || bit_test(e
->dom
,dom
))
199 /* the task here is to figure out how long it's going to be until :00 of the
200 * following minute and initialize TargetTime to this value. TargetTime
201 * will subsequently slide 60 seconds at a time, with correction applied
202 * implicitly in cron_sleep(). it would be nice to let cron execute in
203 * the "current minute" before going to sleep, but by restarting cron you
204 * could then get it to execute a given minute's jobs more than once.
205 * instead we have the chance of missing a minute's jobs completely, but
206 * that's something sysadmin's know to expect what with crashing computers..
210 register struct tm
*tm
;
212 TargetTime
= time((time_t*)0);
213 tm
= localtime(&TargetTime
);
214 TargetTime
+= (60 - tm
->tm_sec
);
220 register int seconds_to_wait
;
223 seconds_to_wait
= (int) (TargetTime
- time((time_t*)0));
224 Debug(DSCH
, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
225 getpid(), TargetTime
, seconds_to_wait
))
227 /* if we intend to sleep, this means that it's finally
228 * time to empty the job queue (execute it).
230 * if we run any jobs, we'll probably screw up our timing,
233 * note that we depend here on the left-to-right nature
234 * of &&, and the short-circuiting.
236 } while (seconds_to_wait
> 0 && job_runqueue());
238 while (seconds_to_wait
> 0) {
239 Debug(DSCH
, ("[%d] sleeping for %d seconds\n",
240 getpid(), seconds_to_wait
))
241 seconds_to_wait
= (int) sleep((unsigned int) seconds_to_wait
);
253 pid
= wait3(&waiter
, WNOHANG
, (struct rusage
*)0);
257 ("[%d] sigchld...no children\n", getpid()))
261 ("[%d] sigchld...no dead kids\n", getpid()))
265 ("[%d] sigchld...pid #%d died, stat=%d\n",
266 getpid(), pid
, WEXITSTATUS(waiter
)))
270 #endif /*USE_SIGCHLD*/
274 parse_args(argc
, argv
)
280 while (EOF
!= (argch
= getopt(argc
, argv
, "x:"))) {
285 if (!set_debug_flags(optarg
))