3 * Configuration parser for Director Run Configuration
4 * directives, which are part of the Schedule Resource
11 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 extern struct s_jl joblevels[];
36 /* Forward referenced subroutines */
53 char *name; /* keyword */
54 enum e_state state; /* parser state */
55 int code; /* state value */
58 /* Keywords understood by parser */
59 static struct s_keyw keyw[] = {
60 {N_("on"), s_none, 0},
63 {N_("sun"), s_wday, 0},
64 {N_("mon"), s_wday, 1},
65 {N_("tue"), s_wday, 2},
66 {N_("wed"), s_wday, 3},
67 {N_("thu"), s_wday, 4},
68 {N_("fri"), s_wday, 5},
69 {N_("sat"), s_wday, 6},
70 {N_("jan"), s_month, 0},
71 {N_("feb"), s_month, 1},
72 {N_("mar"), s_month, 2},
73 {N_("apr"), s_month, 3},
74 {N_("may"), s_month, 4},
75 {N_("jun"), s_month, 5},
76 {N_("jul"), s_month, 6},
77 {N_("aug"), s_month, 7},
78 {N_("sep"), s_month, 8},
79 {N_("oct"), s_month, 9},
80 {N_("nov"), s_month, 10},
81 {N_("dec"), s_month, 11},
83 {N_("sunday"), s_wday, 0},
84 {N_("monday"), s_wday, 1},
85 {N_("tuesday"), s_wday, 2},
86 {N_("wednesday"), s_wday, 3},
87 {N_("thursday"), s_wday, 4},
88 {N_("friday"), s_wday, 5},
89 {N_("saturday"), s_wday, 6},
90 {N_("january"), s_month, 0},
91 {N_("february"), s_month, 1},
92 {N_("march"), s_month, 2},
93 {N_("april"), s_month, 3},
94 {N_("june"), s_month, 5},
95 {N_("july"), s_month, 6},
96 {N_("august"), s_month, 7},
97 {N_("september"), s_month, 8},
98 {N_("october"), s_month, 9},
99 {N_("november"), s_month, 10},
100 {N_("december"), s_month, 11},
102 {N_("daily"), s_daily, 0},
103 {N_("weekly"), s_weekly, 0},
104 {N_("monthly"), s_monthly, 0},
105 {N_("hourly"), s_hourly, 0},
109 static int have_hour, have_mday, have_wday, have_month;
113 static void clear_defaults()
115 have_hour = have_mday = have_wday = have_month = TRUE;
116 clear_bit(0,lrun.hour);
117 clear_bits(0, 30, lrun.mday);
118 clear_bits(0, 6, lrun.wday);
119 clear_bits(0, 11, lrun.month);
122 static void set_defaults()
124 have_hour = have_mday = have_wday = have_month = FALSE;
126 set_bit(0,lrun.hour);
127 set_bits(0, 30, lrun.mday);
128 set_bits(0, 6, lrun.wday);
129 set_bits(0, 11, lrun.month);
133 /* Check if string is a number */
134 static int is_num(char *num)
138 while ((ch = *p++)) {
139 if (ch < '0' || ch > '9') {
146 /* Keywords (RHS) permitted in Run records */
147 static struct s_kw RunFields[] = {
156 * Store Schedule Run information
158 * Parse Run statement:
160 * Run <keyword=value ...> [on] 2 january at 23:45
162 * Default Run time is daily at 0:0
164 * There can be multiple run statements, they are simply chained
168 void store_run(LEX *lc, struct res_items *item, int index, int pass)
171 int token, state, state2 = 0, code = 0, code2 = 0;
172 int options = lc->options;
173 RUN **run = (RUN **)(item->value);
179 lc->options |= LOPT_NO_IDENT; /* want only "strings" */
181 /* clear local copy of run record */
182 memset(&lrun, 0, sizeof(RUN));
184 /* scan for Job level "full", "incremental", ... */
185 for (found=TRUE; found; ) {
187 token = lex_get_token(lc, T_NAME);
188 for (i=0; RunFields[i].name; i++) {
189 if (strcasecmp(lc->str, RunFields[i].name) == 0) {
191 if (lex_get_token(lc, T_ALL) != T_EQUALS) {
192 scan_err1(lc, "Expected an equals, got: %s", lc->str);
195 token = lex_get_token(lc, T_NAME);
196 switch (RunFields[i].token) {
197 case 'L': /* level */
198 for (j=0; joblevels[j].level_name; j++) {
199 if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
200 lrun.level = joblevels[j].level;
201 lrun.job_type = joblevels[j].job_type;
207 scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
213 res = GetResWithName(R_POOL, lc->str);
215 scan_err1(lc, "Could not find specified Pool Resource: %s",
219 lrun.pool = (POOL *)res;
222 case 'S': /* storage */
224 res = GetResWithName(R_STORAGE, lc->str);
226 scan_err1(lc, "Could not find specified Storage Resource: %s",
230 lrun.storage = (STORE *)res;
233 case 'M': /* messages */
235 res = GetResWithName(R_MSGS, lc->str);
237 scan_err1(lc, "Could not find specified Messages Resource: %s",
241 lrun.msgs = (MSGS *)res;
245 scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
249 } /* end if strcasecmp */
250 } /* end for RunFields */
252 /* At this point, it is not a keyword. Check for old syle
253 * Job Levels without keyword. This form is depreciated!!!
255 for (j=0; joblevels[j].level_name; j++) {
256 if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
257 lrun.level = joblevels[j].level;
258 lrun.job_type = joblevels[j].job_type;
263 } /* end for found */
267 * Scan schedule times.
268 * Default is: daily at 0:0
273 for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
278 code = atoi(lc->str) - 1;
279 if (code < 0 || code > 30) {
280 scan_err0(lc, _("Day number out of range (1-31)"));
283 case T_NAME: /* this handles drop through from keyword */
284 case T_UNQUOTED_STRING:
285 if (strchr(lc->str, (int)'-')) {
289 if (strchr(lc->str, (int)':')) {
293 /* everything else must be a keyword */
294 for (i=0; keyw[i].name; i++) {
295 if (strcasecmp(lc->str, keyw[i].name) == 0) {
296 state = keyw[i].state;
303 scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
310 scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
317 case s_mday: /* day of month */
319 clear_bits(0, 30, lrun.mday);
320 clear_bits(0, 6, lrun.wday);
323 set_bit(code, lrun.mday);
325 case s_month: /* month of year */
327 clear_bits(0, 11, lrun.month);
330 set_bit(code, lrun.month);
332 case s_wday: /* week day */
334 clear_bits(0, 6, lrun.wday);
335 clear_bits(0, 30, lrun.mday);
338 set_bit(code, lrun.wday);
340 case s_time: /* time */
342 scan_err0(lc, _("Time must be preceded by keyword AT."));
346 clear_bit(0, lrun.hour);
348 p = strchr(lc->str, ':');
350 scan_err0(lc, _("Time logic error.\n"));
353 *p++ = 0; /* separate two halves */
354 code = atoi(lc->str);
356 if (len > 2 && p[len-1] == 'm') {
357 if (p[len-2] == 'a') {
359 } else if (p[len-2] == 'p') {
362 scan_err0(lc, _("Bad time specification."));
372 if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
373 scan_err0(lc, _("Bad time specification."));
376 set_bit(code, lrun.hour);
384 p = strchr(lc->str, '-');
386 scan_err0(lc, _("Range logic error.\n"));
388 *p++ = 0; /* separate two halves */
390 /* Check for day range */
391 if (is_num(lc->str) && is_num(p)) {
392 code = atoi(lc->str) - 1;
394 if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
395 scan_err0(lc, _("Bad day range specification."));
398 clear_bits(0, 30, lrun.mday);
399 clear_bits(0, 6, lrun.wday);
403 set_bits(code, code2, lrun.mday);
405 set_bits(code, 30, lrun.mday);
406 set_bits(0, code2, lrun.mday);
411 /* lookup first half of keyword range (week days or months) */
413 for (i=0; keyw[i].name; i++) {
414 if (strcmp(lc->str, keyw[i].name) == 0) {
415 state = keyw[i].state;
421 if (i != 0 || (state != s_month && state != s_wday)) {
422 scan_err0(lc, _("Invalid month or week day range"));
426 /* Lookup end of range */
428 for (i=0; keyw[i].name; i++) {
429 if (strcmp(p, keyw[i].name) == 0) {
430 state2 = keyw[i].state;
431 code2 = keyw[i].code;
436 if (i != 0 || state != state2 ||
437 (state2 != s_month && state2 != s_wday) || code == code2) {
438 scan_err0(lc, _("Invalid month or weekday range"));
441 if (state == s_wday) {
443 clear_bits(0, 6, lrun.wday);
444 clear_bits(0, 30, lrun.mday);
448 set_bits(code, code2, lrun.wday);
450 set_bits(code, 6, lrun.wday);
451 set_bits(0, code2, lrun.wday);
454 /* must be s_month */
456 clear_bits(0, 30, lrun.month);
460 set_bits(code, code2, lrun.month);
462 /* this is a bit odd, but we accept it anyway */
463 set_bits(code, 30, lrun.month);
464 set_bits(0, code2, lrun.month);
470 set_bits(0, 23, lrun.hour);
471 set_bits(0, 30, lrun.mday);
472 set_bits(0, 11, lrun.month);
476 set_bit(0, lrun.wday);
477 set_bits(0, 11, lrun.month);
481 set_bits(0, 30, lrun.mday);
482 set_bits(0, 11, lrun.month);
486 set_bits(0, 11, lrun.month);
489 scan_err0(lc, _("Unexpected run state\n"));
495 /* Allocate run record, copy new stuff into it,
496 * and link it into the list of run records
497 * in the schedule resource.
500 trun = (RUN *)malloc(sizeof(RUN));
501 memcpy(trun, &lrun, sizeof(RUN));
508 lc->options = options; /* restore scanner options */
509 set_bit(index, res_all.res_sch.hdr.item_present);