This source file includes following definitions.
- print_version
- print_usage
- parse_opts
- xfork
- xopen
- xclose
- go_background
- handle_sigalrm
- handle_sigchld
- handle_sigusr1
- set_signal_handling
- wait_signal
- wait_children
- orderly_termination
- xsleep
- wait_jobs
- record_start_time
- time_till
- fake_jobs
- explain_intentions
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include "config.h"
26
27 #include <time.h>
28 #include <sys/time.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <locale.h>
38 #include "global.h"
39 #include "gregor.h"
40 #include "cronie_common.h"
41
42 pid_t primary_pid;
43 int day_now;
44 int year, month, day_of_month;
45
46 char *program_name;
47 char *anacrontab;
48 char *spooldir;
49 int serialize, force, update_only, now,
50 no_daemon, quiet, testing_only;
51 char **job_args;
52 int job_nargs;
53 char *defarg = "*";
54 int in_background;
55 sigset_t old_sigmask;
56
57 job_rec *first_job_rec;
58 env_rec *first_env_rec;
59
60 time_t start_sec;
61 static volatile int got_sigalrm, got_sigchld, got_sigusr1;
62 int running_jobs, running_mailers;
63 int range_start = -1;
64 int range_stop = -1;
65 int preferred_hour = -1;
66
67 static void
68 print_version(void)
69 {
70 printf("Anacron from project %s\n"
71 "Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>\n"
72 "Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>\n"
73 "Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>\n"
74 "\n"
75 "Mail comments, suggestions and bug reports to <pasc@redellipse.net>."
76 "\n\n", PACKAGE_STRING);
77 }
78
79 static void
80 print_usage(void)
81 {
82 printf("Usage:\n");
83 printf(" %s [options] [job] ...\n", program_name);
84 printf(" %s -T [-t anacrontab-file]\n", program_name);
85 printf("\nOptions:\n");
86 printf(" -s Serialize execution of jobs\n");
87 printf(" -f Force execution of jobs, even before their time\n");
88 printf(" -n Run jobs with no delay, implies -s\n");
89 printf(" -d Don't fork to the background\n");
90 printf(" -q Suppress stderr messages, only applicable with -d\n");
91 printf(" -u Update the timestamps without actually running anything\n");
92 printf(" -V Print version information\n");
93 printf(" -h Print this message\n");
94 printf(" -t <file> Use alternative anacrontab\n");
95 printf(" -T Test an anacrontab\n");
96 printf(" -S <dir> Select a different spool directory\n");
97 printf("\nSee the anacron(8) manpage for more details.\n");
98 }
99
100 static void
101 parse_opts(int argc, char *argv[])
102
103 {
104 int opt;
105
106 quiet = no_daemon = serialize = force = update_only = now = 0;
107 opterr = 0;
108 while ((opt = getopt(argc, argv, "sfundqt:TS:Vh")) != EOF)
109 {
110 switch (opt)
111 {
112 case 's':
113 serialize = 1;
114 break;
115 case 'f':
116 force = 1;
117 break;
118 case 'u':
119 update_only = 1;
120 break;
121 case 'n':
122 now = serialize = 1;
123 break;
124 case 'd':
125 no_daemon = 1;
126 break;
127 case 'q':
128 quiet = 1;
129 break;
130 case 't':
131 anacrontab = strdup(optarg);
132 break;
133 case 'T':
134 testing_only = 1;
135 break;
136 case 'S':
137 spooldir = strdup(optarg);
138 break;
139 case 'V':
140 print_version();
141 exit(EXIT_SUCCESS);
142 case 'h':
143 print_usage();
144 exit(EXIT_SUCCESS);
145 case '?':
146 fprintf(stderr, "%s: invalid option: %c\n",
147 program_name, optopt);
148 fprintf(stderr, "type: `%s -h' for more information\n",
149 program_name);
150 exit(FAILURE_EXIT);
151 }
152 }
153 if (optind == argc)
154 {
155
156 job_nargs = 1;
157 job_args = &defarg;
158 }
159 else
160 {
161 job_nargs = argc - optind;
162 job_args = argv + optind;
163 }
164 }
165
166 pid_t
167 xfork(void)
168
169 {
170 pid_t pid;
171
172 pid = fork();
173 if (pid == -1) die_e("Can't fork");
174 return pid;
175 }
176
177 int
178 xopen(int fd, const char *file_name, int flags)
179
180
181
182
183
184 {
185 int rfd;
186
187 rfd = open(file_name, flags);
188 if (fd >= 0 && rfd != fd)
189 die_e("Can't open %s on file-descriptor %d", file_name, fd);
190 else if (rfd < 0)
191 die_e("Can't open %s", file_name);
192 return rfd;
193 }
194
195 void
196 xclose(int fd)
197
198 {
199 if (close(fd)) die_e("Can't close file descriptor %d", fd);
200 }
201
202 static void
203 go_background(void)
204
205 {
206 pid_t pid;
207
208
209
210 if (fclose(stdout)) die_e("Can't close stdout");
211 xopen(1, "/dev/null", O_WRONLY);
212
213 if (fclose(stderr)) die_e("Can't close stderr");
214 xopen(2, "/dev/null", O_WRONLY);
215
216 pid = xfork();
217 if (pid != 0)
218 {
219
220 exit(EXIT_SUCCESS);
221 }
222 else
223 {
224
225 primary_pid = getpid();
226 if (setsid() == -1) die_e("setsid() error");
227 in_background = 1;
228 }
229 }
230
231 static void
232 handle_sigalrm(int unused ATTRIBUTE_UNUSED)
233 {
234 got_sigalrm = 1;
235 }
236
237 static void
238 handle_sigchld(int unused ATTRIBUTE_UNUSED)
239 {
240 got_sigchld = 1;
241 }
242
243 static void
244 handle_sigusr1(int unused ATTRIBUTE_UNUSED)
245 {
246 got_sigusr1 = 1;
247 }
248
249 static void
250 set_signal_handling(void)
251
252
253
254 {
255 sigset_t ss;
256 struct sigaction sa;
257
258 got_sigalrm = got_sigchld = got_sigusr1 = 0;
259
260
261 if (sigemptyset(&ss) ||
262 sigaddset(&ss, SIGALRM) ||
263 sigaddset(&ss, SIGCHLD) ||
264 sigaddset(&ss, SIGUSR1)) die_e("sigset error");
265 if (sigprocmask(SIG_BLOCK, &ss, NULL)) die_e ("sigprocmask error");
266
267
268 sa.sa_handler = handle_sigalrm;
269 sa.sa_mask = ss;
270 sa.sa_flags = 0;
271 if (sigaction(SIGALRM, &sa, NULL)) die_e("sigaction error");
272
273
274 sa.sa_handler = handle_sigchld;
275 sa.sa_mask = ss;
276 sa.sa_flags = SA_NOCLDSTOP;
277 if (sigaction(SIGCHLD, &sa, NULL)) die_e("sigaction error");
278
279
280 sa.sa_handler = handle_sigusr1;
281 sa.sa_mask = ss;
282 sa.sa_flags = 0;
283 if (sigaction(SIGUSR1, &sa, NULL)) die_e("sigaction error");
284 }
285
286 static void
287 wait_signal(void)
288
289 {
290 sigset_t ss;
291
292 if (sigprocmask(0, NULL, &ss)) die_e("sigprocmask error");
293 if (sigdelset(&ss, SIGALRM) ||
294 sigdelset(&ss, SIGCHLD) ||
295 sigdelset(&ss, SIGUSR1)) die_e("sigset error");
296 sigsuspend(&ss);
297 }
298
299 static void
300 wait_children(void)
301
302 {
303 while (running_jobs > 0 || running_mailers > 0)
304 {
305 wait_signal();
306 if (got_sigchld) tend_children();
307 got_sigchld = 0;
308 if (got_sigusr1) explain("Received SIGUSR1");
309 got_sigusr1 = 0;
310 }
311 }
312
313 static void
314 orderly_termination(void)
315
316 {
317 explain("Received SIGUSR1");
318 got_sigusr1 = 0;
319 wait_children();
320 explain("Exited");
321 exit(EXIT_SUCCESS);
322 }
323
324 static void
325 xsleep(unsigned int n)
326
327
328
329 {
330 if (n == 0) return;
331 alarm(n);
332 do
333 {
334 wait_signal();
335 if (got_sigchld) tend_children();
336 got_sigchld = 0;
337 if (got_sigusr1) orderly_termination();
338 }
339 while (!got_sigalrm);
340 got_sigalrm = 0;
341 }
342
343 static void
344 wait_jobs(void)
345
346
347
348 {
349 while (running_jobs > 0)
350 {
351 wait_signal();
352 if (got_sigchld) tend_children();
353 got_sigchld = 0;
354 if (got_sigusr1) orderly_termination();
355 }
356 }
357
358 static void
359 record_start_time(void)
360 {
361 struct tm *tm_now;
362
363 start_sec = time(NULL);
364 tm_now = localtime(&start_sec);
365 year = tm_now->tm_year + 1900;
366 month = tm_now->tm_mon + 1;
367 day_of_month = tm_now->tm_mday;
368 day_now = day_num(year, month, day_of_month);
369 if (day_now == -1) die("Invalid date (this is really embarrassing)");
370 if (!update_only && !testing_only)
371 explain("Anacron started on %04d-%02d-%02d",
372 year, month, day_of_month);
373 }
374
375 static unsigned int
376 time_till(job_rec *jr)
377
378
379
380 {
381 time_t tj, tn;
382
383 if (now) return 0;
384 tn = time(NULL);
385 tj = start_sec + (time_t)jr->delay * 60;
386 if (tj < tn) return 0;
387 if (tj - tn > 3600*24)
388 {
389 explain("System time manipulation detected, job `%s' will run immediately",
390 jr->ident);
391 return 0;
392 }
393 return (unsigned int)(tj - tn);
394 }
395
396 static void
397 fake_jobs(void)
398 {
399 int j;
400
401 j = 0;
402 while (j < njobs)
403 {
404 fake_job(job_array[j]);
405 explain("Updated timestamp for job `%s' to %04d-%02d-%02d",
406 job_array[j]->ident, year, month, day_of_month);
407 j++;
408 }
409 }
410
411 static void
412 explain_intentions(void)
413 {
414 int j;
415
416 j = 0;
417 while (j < njobs)
418 {
419 if (now)
420 {
421 explain("Will run job `%s'", job_array[j]->ident);
422 }
423 else
424 {
425 explain("Will run job `%s' in %d min.",
426 job_array[j]->ident, job_array[j]->delay);
427 }
428 j++;
429 }
430 if (serialize && njobs > 0)
431 explain("Jobs will be executed sequentially");
432 }
433
434 int
435 main(int argc, char *argv[])
436 {
437 int j;
438 int cwd;
439 struct timeval tv;
440 struct timezone tz;
441
442 anacrontab = NULL;
443 spooldir = NULL;
444
445 setlocale(LC_ALL, "");
446
447 if (gettimeofday(&tv, &tz) != 0)
448 explain("Can't get exact time, failure.");
449
450 srandom((unsigned int)(getpid() + tv.tv_usec));
451
452 if((program_name = strrchr(argv[0], '/')) == NULL)
453 program_name = argv[0];
454 else
455 ++program_name;
456
457 parse_opts(argc, argv);
458
459 if (anacrontab == NULL)
460 anacrontab = strdup(ANACRONTAB);
461
462 if (spooldir == NULL)
463 spooldir = strdup(ANACRON_SPOOL_DIR);
464
465 if ((cwd = open ("./", O_RDONLY)) == -1) {
466 die_e ("Can't save current directory");
467 }
468
469 in_background = 0;
470
471 if (chdir(spooldir)) die_e("Can't chdir to %s", spooldir );
472
473 if (sigprocmask(0, NULL, &old_sigmask)) die_e("sigset error");
474
475 if (fclose(stdin)) die_e("Can't close stdin");
476 xopen(STDIN_FILENO, "/dev/null", O_RDONLY);
477
478 if (!no_daemon && !testing_only)
479 go_background();
480 else
481 primary_pid = getpid();
482
483 record_start_time();
484 read_tab(cwd);
485 close(cwd);
486 arrange_jobs();
487
488 if (testing_only)
489 {
490 if (complaints) exit (EXIT_FAILURE);
491
492 exit (EXIT_SUCCESS);
493 }
494
495 if (update_only)
496 {
497 fake_jobs();
498 exit(EXIT_SUCCESS);
499 }
500
501 explain_intentions();
502 set_signal_handling();
503 running_jobs = running_mailers = 0;
504 for(j = 0; j < njobs; ++j)
505 {
506 xsleep(time_till(job_array[j]));
507 if (serialize) wait_jobs();
508 launch_job(job_array[j]);
509 }
510 wait_children();
511 explain("Normal exit (%d job%s run)", njobs, njobs == 1 ? "" : "s");
512 exit(EXIT_SUCCESS);
513 }