This source file includes following definitions.
- xmalloc
- conv2int
- read_tab_line
- job_arg_num
- register_env
- register_job
- register_period_job
- unbiased_rand
- parse_tab_line
- read_tab
- execution_order
- arrange_jobs
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
26
27
28
29 #include <string.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <obstack.h>
34 #include <limits.h>
35 #include <fnmatch.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include "global.h"
39 #include "matchrx.h"
40
41 static struct obstack input_o;
42 static struct obstack tab_o;
43 static FILE *tab;
44 job_rec **job_array;
45 int njobs;
46 static int jobs_read;
47 static int line_num;
48 static job_rec *last_job_rec;
49 static env_rec *last_env_rec;
50
51 static int random_number = 0;
52
53
54 #define obstack_chunk_alloc xmalloc
55 #define obstack_chunk_free free
56
57 static void *
58 xmalloc (size_t size)
59
60 {
61 void * ptr;
62
63 ptr = malloc(size);
64 if (ptr == NULL)
65 die("Memory exhausted");
66 return ptr;
67 }
68
69 static int
70 conv2int(const char *s)
71
72
73 {
74 long l;
75
76 errno = 0;
77 l = strtol(s, NULL, 10);
78
79 if (errno == ERANGE || l < 0 || l > INT_MAX) return - 1;
80 return (int)l;
81 }
82
83 static char *
84 read_tab_line (void)
85
86
87
88 {
89 int c, prev=0;
90
91 if (feof(tab)) return NULL;
92 while (1)
93 {
94 c = getc(tab);
95 if ((c == '\n' && prev != '\\') || c == EOF)
96 {
97 if (0 != prev) obstack_1grow(&input_o, (char)prev);
98 break;
99 }
100
101 if ('\\' != prev && 0 != prev && '\n' != prev) obstack_1grow(&input_o, (char)prev);
102 else if ('\n' == prev) obstack_1grow(&input_o, ' ');
103
104 prev = c;
105 }
106 if (ferror(tab)) die_e("Error reading %s", anacrontab);
107 obstack_1grow(&input_o, '\0');
108 return obstack_finish(&input_o);
109 }
110
111 static int
112 job_arg_num(const char *ident)
113
114
115
116 {
117 int i, r;
118
119 for (i = 0; i < job_nargs; i++)
120 {
121 r = fnmatch(job_args[i], ident, 0);
122 if (r == 0) return i;
123 if (r != FNM_NOMATCH) die("fnmatch() error");
124 }
125 return - 1;
126 }
127
128 static void
129 register_env(const char *env_var, const char *value)
130
131 {
132 env_rec *er;
133 int var_len, val_len;
134
135 var_len = (int)strlen(env_var);
136 val_len = (int)strlen(value);
137 if (!var_len) {
138 return;
139 }
140
141 er = obstack_alloc(&tab_o, sizeof(env_rec));
142 if (er == NULL) {
143 die_e("Cannot allocate memory.");
144 }
145
146 er->assign = obstack_alloc(&tab_o, var_len + 1 + val_len + 1);
147 if (er->assign == NULL) {
148 die_e("Cannot allocate memory.");
149 }
150 strcpy(er->assign, env_var);
151 er->assign[var_len] = '=';
152 strcpy(er->assign + var_len + 1, value);
153 er->assign[var_len + 1 + val_len] = 0;
154 if (last_env_rec != NULL) last_env_rec->next = er;
155 else first_env_rec = er;
156 last_env_rec = er;
157 Debug(("on line %d: %s", line_num, er->assign));
158 }
159
160 static void
161 register_job(const char *periods, const char *delays,
162 const char *ident, char *command)
163
164 {
165 int period, delay;
166 job_rec *jr;
167 int ident_len, command_len;
168
169 ident_len = (int)strlen(ident);
170 command_len = (int)strlen(command);
171 jobs_read++;
172 period = conv2int(periods);
173 delay = conv2int(delays);
174 if (period < 0 || delay < 0)
175 {
176 complain("%s: number out of range on line %d, skipping",
177 anacrontab, line_num);
178 return;
179 }
180 jr = obstack_alloc(&tab_o, sizeof(job_rec));
181 if (jr == NULL) {
182 die_e("Cannot allocate memory.");
183 }
184 jr->period = period;
185 jr->named_period = 0;
186 delay += random_number;
187 jr->delay = delay;
188 jr->tab_line = line_num;
189 jr->ident = obstack_alloc(&tab_o, ident_len + 1);
190 if (jr->ident == NULL) {
191 die_e("Cannot allocate memory.");
192 }
193 strcpy(jr->ident, ident);
194 jr->arg_num = job_arg_num(ident);
195 jr->command = obstack_alloc(&tab_o, command_len + 1);
196 if (jr->command == NULL) {
197 die_e("Cannot allocate memory.");
198 }
199 strcpy(jr->command, command);
200 jr->job_pid = jr->mailer_pid = 0;
201 if (last_job_rec != NULL) last_job_rec->next = jr;
202 else first_job_rec = jr;
203 last_job_rec = jr;
204 jr->prev_env_rec = last_env_rec;
205 jr->next = NULL;
206 Debug(("Read job - period=%d, delay=%d, ident=%s, command=%s",
207 jr->period, jr->delay, jr->ident, jr->command));
208 }
209
210 static void
211 register_period_job(const char *periods, const char *delays,
212 const char *ident, char *command)
213
214 {
215 int delay;
216 job_rec *jr;
217 int ident_len, command_len;
218
219 ident_len = (int)strlen(ident);
220 command_len = (int)strlen(command);
221 jobs_read++;
222 delay = conv2int(delays);
223 if (delay < 0)
224 {
225 complain("%s: number out of range on line %d, skipping",
226 anacrontab, line_num);
227 return;
228 }
229
230 jr = obstack_alloc(&tab_o, sizeof(job_rec));
231 if (jr == NULL) {
232 die_e("Cannot allocate memory.");
233 }
234 if (!strncmp ("@monthly", periods, 8)) {
235 jr->named_period = 1;
236 } else if (!strncmp("@yearly", periods, 7) || !strncmp("@annually", periods, 9) || !strncmp("@annualy", periods, 8)) {
237 jr->named_period = 2;
238 } else if (!strncmp ("@daily", periods, 6)) {
239 jr->named_period = 3;
240 } else if (!strncmp ("@weekly", periods, 7)) {
241 jr->named_period = 4;
242 } else {
243 complain("%s: Unknown named period on line %d, skipping",
244 anacrontab, line_num);
245 }
246 jr->period = 0;
247 delay += random_number;
248 jr->delay = delay;
249 jr->tab_line = line_num;
250 jr->ident = obstack_alloc(&tab_o, ident_len + 1);
251 if (jr->ident == NULL) {
252 die_e("Cannot allocate memory.");
253 }
254 strcpy(jr->ident, ident);
255 jr->arg_num = job_arg_num(ident);
256 jr->command = obstack_alloc(&tab_o, command_len + 1);
257 if (jr->command == NULL) {
258 die_e("Cannot allocate memory.");
259 }
260 strcpy(jr->command, command);
261 jr->job_pid = jr->mailer_pid = 0;
262 if (last_job_rec != NULL) last_job_rec->next = jr;
263 else first_job_rec = jr;
264 last_job_rec = jr;
265 jr->prev_env_rec = last_env_rec;
266 jr->next = NULL;
267 Debug(("Read job - period %d, delay=%d, ident%s, command=%s",
268 jr->named_period, jr->delay, jr->ident, jr->command));
269 }
270
271 static long int
272 unbiased_rand(long int max)
273 {
274 long int rn;
275 long int divisor;
276
277 divisor = RAND_MAX / (max + 1);
278
279 do {
280 rn = random() / divisor;
281 } while (rn > max);
282
283 return rn;
284 }
285
286 static void
287 parse_tab_line(char *line)
288 {
289 int r;
290 char *env_var;
291 char *value;
292 char *periods;
293 char *delays;
294 char *ident;
295 char *command;
296 char *from;
297 char *to;
298 char *pref_hour;
299
300
301 r = match_rx("^[ \t]*($|#)", line, 0);
302 if (r == -1) goto reg_err;
303 if (r)
304 {
305 Debug(("line %d empty", line_num));
306 return;
307 }
308
309
310 r = match_rx("^[ \t]*([^ \t=]+)[ \t]*=(.*)$", line, 2,
311 &env_var, &value);
312 if (r == -1) goto reg_err;
313 if (r)
314 {
315 if (strncmp(env_var, "START_HOURS_RANGE", 17) == 0)
316 {
317 r = match_rx("^([[:digit:]]+)-([[:digit:]]+)$", value, 2, &from, &to);
318 if (r == -1) goto reg_err;
319 if (r == 0) goto reg_invalid;
320 range_start = atoi(from);
321 range_stop = atoi(to);
322 if (range_stop < range_start) {
323 range_start = 0; range_stop = 0;
324 goto reg_invalid;
325 }
326 Debug(("Jobs will start in the %02d:00-%02d:00 range.", range_start, range_stop));
327 }
328 else if (strncmp(env_var, "RANDOM_DELAY", 12) == 0) {
329 r = match_rx("^([[:digit:]]+)$", value, 0);
330 if (r == -1) goto reg_err;
331 if (r == 0) goto reg_invalid;
332
333 random_number = (int)unbiased_rand(atoi(value));
334 Debug(("Randomized delay set: %d", random_number));
335 }
336 else if (strncmp(env_var, "PREFERRED_HOUR", 14) == 0) {
337 r = match_rx("^([[:digit:]]+)$", value, 1, &pref_hour);
338 if (r == -1) goto reg_err;
339
340 if (r) {
341 preferred_hour = atoi(pref_hour);
342 if ((preferred_hour < 0) || (preferred_hour > 24)) {
343 preferred_hour = -1;
344 goto reg_invalid;
345 }
346 }
347 }
348 register_env(env_var, value);
349 return;
350 }
351
352
353 r = match_rx("^[ \t]*([[:digit:]]+)[ \t]+([[:digit:]]+)[ \t]+"
354 "([^ \t/]+)[ \t]+([^ \t].*)$",
355 line, 4, &periods, &delays, &ident, &command);
356 if (r == -1) goto reg_err;
357 if (r)
358 {
359 register_job(periods, delays, ident, command);
360 return;
361 }
362
363
364 r = match_rx("^[ \t]*(@[^ \t]+)[ \t]+([[:digit:]]+)[ \t]+"
365 "([^ \t/]+)[ \t]+([^ \t].*)$",
366 line, 4, &periods, &delays, &ident, &command);
367 if (r == -1) goto reg_err;
368 if (r)
369 {
370 register_period_job(periods, delays, ident, command);
371 return;
372 }
373
374 reg_invalid:
375 complain("Invalid syntax in %s on line %d - skipping this line",
376 anacrontab, line_num);
377 return;
378
379 reg_err:
380 die("Regex error reading %s", anacrontab);
381 }
382
383 void
384 read_tab(int cwd)
385
386 {
387 char *tab_line;
388
389 first_job_rec = last_job_rec = NULL;
390 first_env_rec = last_env_rec = NULL;
391 jobs_read = 0;
392 line_num = 0;
393
394 if (fchdir(cwd)) die_e("Can't chdir to original cwd");
395 tab = fopen(anacrontab, "r");
396 if (chdir(spooldir)) die_e("Can't chdir to %s", spooldir);
397
398 if (tab == NULL) die_e("Error opening %s", anacrontab);
399
400 obstack_init(&input_o);
401 obstack_init(&tab_o);
402 while ((tab_line = read_tab_line()) != NULL)
403 {
404 line_num++;
405 parse_tab_line(tab_line);
406 obstack_free(&input_o, tab_line);
407 }
408 if (fclose(tab)) die_e("Error closing %s", anacrontab);
409 }
410
411 static int
412 execution_order(const job_rec **job1, const job_rec **job2)
413
414
415 {
416 int d;
417
418 d = (*job1)->arg_num - (*job2)->arg_num;
419 if (d != 0 && now) return d;
420 d = (*job1)->delay - (*job2)->delay;
421 if (d != 0) return d;
422 d = (*job1)->tab_line - (*job2)->tab_line;
423 return d;
424 }
425
426 void
427 arrange_jobs(void)
428
429
430
431
432 {
433 job_rec *j;
434
435 j = first_job_rec;
436 njobs = 0;
437 while (j != NULL)
438 {
439 if (j->arg_num != -1 && (update_only || testing_only || consider_job(j)))
440 {
441 njobs++;
442 obstack_grow(&tab_o, &j, sizeof(j));
443 }
444 j = j->next;
445 }
446 job_array = obstack_finish(&tab_o);
447
448
449 qsort(job_array, (size_t)njobs, sizeof(*job_array),
450 (int (*)(const void *, const void *))execution_order);
451 }