/[pkg-cron]/trunk/cron.c
ViewVC logotype

Contents of /trunk/cron.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download)
Sun Apr 11 19:10:18 1999 UTC (14 years, 1 month ago) by steveg
File MIME type: text/plain
File size: 6857 byte(s)
Initial revision
1 /* Copyright 1988,1990,1993,1994 by Paul Vixie
2 * All rights reserved
3 *
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
11 * user.
12 *
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
16 */
17
18 #if !defined(lint) && !defined(LINT)
19 static char rcsid[] = "$Id: cron.c,v 2.11 1994/01/15 20:43:43 vixie Exp $";
20 #endif
21
22
23 #define MAIN_PROGRAM
24
25
26 #include "cron.h"
27 #include <sys/signal.h>
28 #if SYS_TIME_H
29 # include <sys/time.h>
30 #else
31 # include <time.h>
32 #endif
33
34
35 static void usage __P((void)),
36 run_reboot_jobs __P((cron_db *)),
37 cron_tick __P((cron_db *)),
38 cron_sync __P((void)),
39 cron_sleep __P((void)),
40 #ifdef USE_SIGCHLD
41 sigchld_handler __P((int)),
42 #endif
43 sighup_handler __P((int)),
44 parse_args __P((int c, char *v[]));
45
46
47 static void
48 usage() {
49 fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
50 exit(ERROR_EXIT);
51 }
52
53
54 int
55 main(argc, argv)
56 int argc;
57 char *argv[];
58 {
59 cron_db database;
60
61 ProgramName = argv[0];
62
63 #if defined(BSD)
64 setlinebuf(stdout);
65 setlinebuf(stderr);
66 #endif
67
68 parse_args(argc, argv);
69
70 #ifdef USE_SIGCHLD
71 (void) signal(SIGCHLD, sigchld_handler);
72 #else
73 (void) signal(SIGCLD, SIG_IGN);
74 #endif
75 (void) signal(SIGHUP, sighup_handler);
76
77 acquire_daemonlock(0);
78 set_cron_uid();
79 set_cron_cwd();
80
81 #if defined(POSIX)
82 setenv("PATH", _PATH_DEFPATH, 1);
83 #endif
84
85 /* if there are no debug flags turned on, fork as a daemon should.
86 */
87 # if DEBUGGING
88 if (DebugFlags) {
89 # else
90 if (0) {
91 # endif
92 (void) fprintf(stderr, "[%d] cron started\n", getpid());
93 } else {
94 switch (fork()) {
95 case -1:
96 log_it("CRON",getpid(),"DEATH","can't fork");
97 exit(0);
98 break;
99 case 0:
100 /* child process */
101 log_it("CRON",getpid(),"STARTUP","fork ok");
102 (void) setsid();
103 break;
104 default:
105 /* parent process should just die */
106 _exit(0);
107 }
108 }
109
110 acquire_daemonlock(0);
111 database.head = NULL;
112 database.tail = NULL;
113 database.mtime = (time_t) 0;
114 load_database(&database);
115 run_reboot_jobs(&database);
116 cron_sync();
117 while (TRUE) {
118 # if DEBUGGING
119 if (!(DebugFlags & DTEST))
120 # endif /*DEBUGGING*/
121 cron_sleep();
122
123 load_database(&database);
124
125 /* do this iteration
126 */
127 cron_tick(&database);
128
129 /* sleep 1 minute
130 */
131 TargetTime += 60;
132 }
133 }
134
135
136 static void
137 run_reboot_jobs(db)
138 cron_db *db;
139 {
140 register user *u;
141 register entry *e;
142
143 for (u = db->head; u != NULL; u = u->next) {
144 for (e = u->crontab; e != NULL; e = e->next) {
145 if (e->flags & WHEN_REBOOT) {
146 job_add(e, u);
147 }
148 }
149 }
150 (void) job_runqueue();
151 }
152
153
154 static void
155 cron_tick(db)
156 cron_db *db;
157 {
158 register struct tm *tm = localtime(&TargetTime);
159 register int minute, hour, dom, month, dow;
160 register user *u;
161 register entry *e;
162
163 /* make 0-based values out of these so we can use them as indicies
164 */
165 minute = tm->tm_min -FIRST_MINUTE;
166 hour = tm->tm_hour -FIRST_HOUR;
167 dom = tm->tm_mday -FIRST_DOM;
168 month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
169 dow = tm->tm_wday -FIRST_DOW;
170
171 Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
172 getpid(), minute, hour, dom, month, dow))
173
174 /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
175 * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
176 * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
177 * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
178 * like many bizarre things, it's the standard.
179 */
180 for (u = db->head; u != NULL; u = u->next) {
181 for (e = u->crontab; e != NULL; e = e->next) {
182 Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
183 env_get("LOGNAME", e->envp),
184 e->uid, e->gid, e->cmd))
185 if (bit_test(e->minute, minute)
186 && bit_test(e->hour, hour)
187 && bit_test(e->month, month)
188 && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
189 ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
190 : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
191 )
192 ) {
193 job_add(e, u);
194 }
195 }
196 }
197 }
198
199
200 /* the task here is to figure out how long it's going to be until :00 of the
201 * following minute and initialize TargetTime to this value. TargetTime
202 * will subsequently slide 60 seconds at a time, with correction applied
203 * implicitly in cron_sleep(). it would be nice to let cron execute in
204 * the "current minute" before going to sleep, but by restarting cron you
205 * could then get it to execute a given minute's jobs more than once.
206 * instead we have the chance of missing a minute's jobs completely, but
207 * that's something sysadmin's know to expect what with crashing computers..
208 */
209 static void
210 cron_sync() {
211 register struct tm *tm;
212
213 TargetTime = time((time_t*)0);
214 tm = localtime(&TargetTime);
215 TargetTime += (60 - tm->tm_sec);
216 }
217
218
219 static void
220 cron_sleep() {
221 register int seconds_to_wait;
222
223 do {
224 seconds_to_wait = (int) (TargetTime - time((time_t*)0));
225 Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
226 getpid(), TargetTime, seconds_to_wait))
227
228 /* if we intend to sleep, this means that it's finally
229 * time to empty the job queue (execute it).
230 *
231 * if we run any jobs, we'll probably screw up our timing,
232 * so go recompute.
233 *
234 * note that we depend here on the left-to-right nature
235 * of &&, and the short-circuiting.
236 */
237 } while (seconds_to_wait > 0 && job_runqueue());
238
239 while (seconds_to_wait > 0) {
240 Debug(DSCH, ("[%d] sleeping for %d seconds\n",
241 getpid(), seconds_to_wait))
242 seconds_to_wait = (int) sleep((unsigned int) seconds_to_wait);
243 }
244 }
245
246
247 #ifdef USE_SIGCHLD
248 static void
249 sigchld_handler(x) {
250 WAIT_T waiter;
251 PID_T pid;
252
253 for (;;) {
254 #ifdef POSIX
255 pid = waitpid(-1, &waiter, WNOHANG);
256 #else
257 pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
258 #endif
259 switch (pid) {
260 case -1:
261 Debug(DPROC,
262 ("[%d] sigchld...no children\n", getpid()))
263 return;
264 case 0:
265 Debug(DPROC,
266 ("[%d] sigchld...no dead kids\n", getpid()))
267 return;
268 default:
269 Debug(DPROC,
270 ("[%d] sigchld...pid #%d died, stat=%d\n",
271 getpid(), pid, WEXITSTATUS(waiter)))
272 }
273 }
274 }
275 #endif /*USE_SIGCHLD*/
276
277
278 static void
279 sighup_handler(x) {
280 log_close();
281 }
282
283
284 static void
285 parse_args(argc, argv)
286 int argc;
287 char *argv[];
288 {
289 int argch;
290
291 while (EOF != (argch = getopt(argc, argv, "x:"))) {
292 switch (argch) {
293 default:
294 usage();
295 case 'x':
296 if (!set_debug_flags(optarg))
297 usage();
298 break;
299 }
300 }
301 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.5