3 * Configuration parser for Director Run Configuration
4 * directives, which are part of the Schedule Resource
9 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of
14 the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public
22 License along with this program; if not, write to the Free
23 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32 extern struct s_jl joblevels[];
34 /* Forward referenced subroutines */
51 char *name; /* keyword */
52 enum e_state state; /* parser state */
53 int code; /* state value */
56 /* Keywords understood by parser */
57 static struct s_keyw keyw[] = {
58 {N_("on"), s_none, 0},
61 {N_("sun"), s_wday, 0},
62 {N_("mon"), s_wday, 1},
63 {N_("tue"), s_wday, 2},
64 {N_("wed"), s_wday, 3},
65 {N_("thu"), s_wday, 4},
66 {N_("fri"), s_wday, 5},
67 {N_("sat"), s_wday, 6},
68 {N_("jan"), s_month, 0},
69 {N_("feb"), s_month, 1},
70 {N_("mar"), s_month, 2},
71 {N_("apr"), s_month, 3},
72 {N_("may"), s_month, 4},
73 {N_("jun"), s_month, 5},
74 {N_("jul"), s_month, 6},
75 {N_("aug"), s_month, 7},
76 {N_("sep"), s_month, 8},
77 {N_("oct"), s_month, 9},
78 {N_("nov"), s_month, 10},
79 {N_("dec"), s_month, 11},
81 {N_("sunday"), s_wday, 0},
82 {N_("monday"), s_wday, 1},
83 {N_("tuesday"), s_wday, 2},
84 {N_("wednesday"), s_wday, 3},
85 {N_("thursday"), s_wday, 4},
86 {N_("friday"), s_wday, 5},
87 {N_("saturday"), s_wday, 6},
88 {N_("january"), s_month, 0},
89 {N_("february"), s_month, 1},
90 {N_("march"), s_month, 2},
91 {N_("april"), s_month, 3},
92 {N_("june"), s_month, 5},
93 {N_("july"), s_month, 6},
94 {N_("august"), s_month, 7},
95 {N_("september"), s_month, 8},
96 {N_("october"), s_month, 9},
97 {N_("november"), s_month, 10},
98 {N_("december"), s_month, 11},
100 {N_("daily"), s_daily, 0},
101 {N_("weekly"), s_weekly, 0},
102 {N_("monthly"), s_monthly, 0},
103 {N_("hourly"), s_hourly, 0},
107 static int have_hour, have_mday, have_wday, have_month;
111 static void clear_defaults()
113 have_hour = have_mday = have_wday = have_month = TRUE;
114 clear_bit(0,lrun.hour);
115 clear_bits(0, 30, lrun.mday);
116 clear_bits(0, 6, lrun.wday);
117 clear_bits(0, 11, lrun.month);
120 static void set_defaults()
122 have_hour = have_mday = have_wday = have_month = FALSE;
124 set_bit(0,lrun.hour);
125 set_bits(0, 30, lrun.mday);
126 set_bits(0, 6, lrun.wday);
127 set_bits(0, 11, lrun.month);
131 /* Check if string is a number */
132 static int is_num(char *num)
136 while ((ch = *p++)) {
137 if (ch < '0' || ch > '9') {
146 * Store Schedule Run information
148 * Parse Run statement:
150 * Run <full|incremental|...> [on] 2 january at 23:45
152 * Default Run time is daily at 0:0
154 * There can be multiple run statements, they are simply chained
158 void store_run(LEX *lc, struct res_items *item, int index, int pass)
160 int token, state, state2, i, code, code2;
161 int options = lc->options;
162 RUN **run = (RUN **)(item->value);
167 lc->options |= LOPT_NO_IDENT; /* want only "strings" */
169 /* clear local copy of run record */
170 memset(&lrun, 0, sizeof(RUN));
172 /* scan for Job level "full", "incremental", ... */
173 token = lex_get_token(lc);
174 if (token != T_STRING) {
175 scan_err1(lc, _("Expected a Job level identifier, got: %s"), lc->str);
178 for (i=0; joblevels[i].level_name; i++) {
179 if (strcmp(lc->str, joblevels[i].level_name) == 0) {
180 lrun.level = joblevels[i].level;
181 lrun.job_class = joblevels[i].job_class;
187 scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
192 * Scan schedule times.
193 * Default is: daily at 0:0
198 while ((token = lex_get_token(lc)) != T_EOL) {
203 code = atoi(lc->str) - 1;
204 if (code < 0 || code > 30) {
205 scan_err0(lc, _("Day number out of range (1-31)"));
209 if (strchr(lc->str, (int)'-')) {
213 if (strchr(lc->str, (int)':')) {
217 /* everything else must be a keyword */
219 for (i=0; keyw[i].name; i++) {
220 if (strcmp(lc->str, keyw[i].name) == 0) {
221 state = keyw[i].state;
228 scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
234 scan_err1(lc, _("Unexpected token: %s"), lc->str);
240 case s_mday: /* day of month */
242 clear_bits(0, 30, lrun.mday);
243 clear_bits(0, 6, lrun.wday);
246 set_bit(code, lrun.mday);
248 case s_month: /* month of year */
250 clear_bits(0, 11, lrun.month);
253 set_bit(code, lrun.month);
255 case s_wday: /* week day */
257 clear_bits(0, 6, lrun.wday);
258 clear_bits(0, 30, lrun.mday);
261 set_bit(code, lrun.wday);
263 case s_time: /* time */
265 scan_err0(lc, _("Time must be preceded by keyword AT."));
268 clear_bit(0, lrun.hour);
271 p = strchr(lc->str, ':');
273 scan_err0(lc, _("Time logic error.\n"));
275 *p++ = 0; /* separate two halves */
276 code = atoi(lc->str);
278 if (len > 2 && p[len-1] == 'm') {
279 if (p[len-2] == 'a') {
281 } else if (p[len-2] == 'p') {
284 scan_err0(lc, _("Bad time specification."));
293 if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
294 scan_err0(lc, _("Bad time specification."));
296 set_bit(code, lrun.hour);
303 p = strchr(lc->str, '-');
305 scan_err0(lc, _("Range logic error.\n"));
307 *p++ = 0; /* separate two halves */
309 /* Check for day range */
310 if (is_num(lc->str) && is_num(p)) {
311 code = atoi(lc->str) - 1;
313 if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
314 scan_err0(lc, _("Bad day range specification."));
317 clear_bits(0, 30, lrun.mday);
318 clear_bits(0, 6, lrun.wday);
322 set_bits(code, code2, lrun.mday);
324 set_bits(code, 30, lrun.mday);
325 set_bits(0, code2, lrun.mday);
330 /* lookup first half of keyword range (week days or months) */
332 for (i=0; keyw[i].name; i++) {
333 if (strcmp(lc->str, keyw[i].name) == 0) {
334 state = keyw[i].state;
340 if (i != 0 || (state != s_month && state != s_wday)) {
341 scan_err0(lc, _("Invalid month or week day range"));
344 /* Lookup end of range */
346 for (i=0; keyw[i].name; i++) {
347 if (strcmp(p, keyw[i].name) == 0) {
348 state2 = keyw[i].state;
349 code2 = keyw[i].code;
354 if (i != 0 || state != state2 ||
355 (state2 != s_month && state2 != s_wday) || code == code2) {
356 scan_err0(lc, _("Invalid month or weekday range"));
358 if (state == s_wday) {
360 clear_bits(0, 6, lrun.wday);
361 clear_bits(0, 30, lrun.mday);
365 set_bits(code, code2, lrun.wday);
367 set_bits(code, 6, lrun.wday);
368 set_bits(0, code2, lrun.wday);
371 /* must be s_month */
373 clear_bits(0, 30, lrun.month);
377 set_bits(code, code2, lrun.month);
379 /* this is a bit odd, but we accept it anyway */
380 set_bits(code, 30, lrun.month);
381 set_bits(0, code2, lrun.month);
387 set_bits(0, 23, lrun.hour);
388 set_bits(0, 30, lrun.mday);
389 set_bits(0, 11, lrun.month);
393 set_bit(0, lrun.wday);
394 set_bits(0, 11, lrun.month);
398 set_bits(0, 30, lrun.mday);
399 set_bits(0, 11, lrun.month);
403 set_bit(0, lrun.mday);
404 set_bits(0, 11, lrun.month);
407 scan_err0(lc, _("Unexpected run state\n"));
412 /* Allocate run record, copy new stuff into it,
413 * and link it into the list of run records
414 * in the schedule resource.
417 trun = (RUN *) malloc(sizeof(RUN));
418 memcpy(trun, &lrun, sizeof(RUN));
425 lc->options = options; /* restore scanner options */
426 set_bit(index, res_all.res_sch.hdr.item_present);