]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/run_conf.c
1.20 update -- kes18May02
[bacula/bacula] / bacula / src / dird / run_conf.c
1 /*
2  *
3  *  Configuration parser for Director Run Configuration
4  *   directives, which are part of the Schedule Resource
5  *
6  *     Kern Sibbald, May MM
7  */
8 /*
9    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
10
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.
15
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.
20
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,
24    MA 02111-1307, USA.
25
26  */
27
28 #include "bacula.h"
29 #include "dird.h"
30
31 extern URES res_all;
32 extern struct s_jl joblevels[];
33
34 /* Forward referenced subroutines */
35
36 enum e_state {
37    s_none = 0,
38    s_range,
39    s_mday,
40    s_month,
41    s_time,
42    s_at,
43    s_wday,
44    s_daily,
45    s_weekly,
46    s_monthly,
47    s_hourly,
48 };  
49
50 struct s_keyw {
51   char *name;                         /* keyword */
52   enum e_state state;                 /* parser state */
53   int code;                           /* state value */
54 };
55
56 /* Keywords understood by parser */
57 static struct s_keyw keyw[] = {
58   {N_("on"),         s_none,    0},
59   {N_("at"),         s_at,      0},
60
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},
80
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},
99
100   {N_("daily"),      s_daily,   0},
101   {N_("weekly"),     s_weekly,  0},
102   {N_("monthly"),    s_monthly, 0},
103   {N_("hourly"),     s_hourly,  0},
104   {NULL,         s_none,    0}
105 };
106
107 static int have_hour, have_mday, have_wday, have_month;
108 static int have_at;
109 static RUN lrun;
110
111 static void clear_defaults()
112 {
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);
118 }
119
120 static void set_defaults()
121 {
122    have_hour = have_mday = have_wday = have_month = FALSE;
123    have_at = 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);
128 }
129
130
131 /* Check if string is a number */
132 static int is_num(char *num)
133 {
134    char *p = num;
135    int ch;
136    while ((ch = *p++)) {
137       if (ch < '0' || ch > '9') {
138          return FALSE;
139       }
140    }
141    return TRUE;
142 }
143
144
145 /* 
146  * Store Schedule Run information   
147  * 
148  * Parse Run statement:
149  *
150  *  Run <full|incremental|...> [on] 2 january at 23:45
151  *
152  *   Default Run time is daily at 0:0
153  *  
154  *   There can be multiple run statements, they are simply chained
155  *   together.
156  *
157  */
158 void store_run(LEX *lc, struct res_items *item, int index, int pass)
159 {
160    int token, state, state2, i, code, code2;
161    int options = lc->options;
162    RUN **run = (RUN **)(item->value);   
163    RUN *trun;
164    char *p;
165
166
167    lc->options |= LOPT_NO_IDENT;      /* want only "strings" */
168
169    /* clear local copy of run record */
170    memset(&lrun, 0, sizeof(RUN));
171
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);
176    } else {
177       if (strcasecmp(lc->str, "level")) {
178          if (lex_get_token(lc) != T_EQUALS) {
179             scan_err1(lc, "Expected an equals, got: %s", lc->str);
180          }
181          token = lex_get_token(lc);
182       }
183       for (i=0; joblevels[i].level_name; i++) {
184          if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
185             lrun.level = joblevels[i].level;
186             lrun.job_type = joblevels[i].job_type;
187             i = 0;
188             break;
189          }
190       }
191       if (i != 0) {
192          scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
193       }
194    }
195
196    /*
197     * Scan schedule times.
198     * Default is: daily at 0:0
199     */
200    state = s_none;
201    set_defaults();
202
203    while ((token = lex_get_token(lc)) != T_EOL) {
204       int len, pm;
205       switch (token) {
206          case T_NUMBER:
207             state = s_mday;
208             code = atoi(lc->str) - 1;
209             if (code < 0 || code > 30) {
210                scan_err0(lc, _("Day number out of range (1-31)"));
211             }
212             break;
213          case T_STRING:
214             if (strchr(lc->str, (int)'-')) {
215                state = s_range;
216                break;
217             }
218             if (strchr(lc->str, (int)':')) {
219                state = s_time;
220                break;
221             }
222             /* everything else must be a keyword */
223             lcase(lc->str);
224             for (i=0; keyw[i].name; i++) {
225                if (strcmp(lc->str, keyw[i].name) == 0) {
226                   state = keyw[i].state;
227                   code   = keyw[i].code;
228                   i = 0;
229                   break;
230                }
231             }
232             if (i != 0) {
233                scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
234             }
235             break;
236          case T_COMMA:
237             continue;
238          default:
239             scan_err1(lc, _("Unexpected token: %s"), lc->str);
240             break;
241       }
242       switch (state) {
243          case s_none:
244             continue;
245          case s_mday:                 /* day of month */
246             if (!have_mday) {
247                clear_bits(0, 30, lrun.mday);
248                clear_bits(0, 6, lrun.wday);
249                have_mday = TRUE;
250             }
251             set_bit(code, lrun.mday);
252             break;
253          case s_month:                /* month of year */
254             if (!have_month) {
255                clear_bits(0, 11, lrun.month);
256                have_month = TRUE;
257             }
258             set_bit(code, lrun.month);
259             break;
260          case s_wday:                 /* week day */
261             if (!have_wday) {
262                clear_bits(0, 6, lrun.wday);
263                clear_bits(0, 30, lrun.mday);
264                have_wday = TRUE;
265             }
266             set_bit(code, lrun.wday);
267             break;
268          case s_time:                 /* time */
269             if (!have_at) {
270                scan_err0(lc, _("Time must be preceded by keyword AT."));
271             }
272             if (!have_hour) {
273                clear_bit(0, lrun.hour);
274                have_hour = TRUE;
275             }
276             p = strchr(lc->str, ':');
277             if (!p)  {
278                scan_err0(lc, _("Time logic error.\n"));
279             }
280             *p++ = 0;                 /* separate two halves */
281             code = atoi(lc->str);
282             len = strlen(p);
283             if (len > 2 && p[len-1] == 'm') {
284                if (p[len-2] == 'a') {
285                   pm = 0;
286                } else if (p[len-2] == 'p') {
287                   pm = 1;
288                } else {
289                   scan_err0(lc, _("Bad time specification."));
290                }
291             } else {
292                pm = 0;
293             }
294             code2 = atoi(p);
295             if (pm) {
296                code += 12;
297             }
298             if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
299                scan_err0(lc, _("Bad time specification."));
300             }
301             set_bit(code, lrun.hour);
302             lrun.minute = code2;
303             break;
304          case s_at:
305             have_at = TRUE;
306             break;
307          case s_range:
308             p = strchr(lc->str, '-');
309             if (!p) {
310                scan_err0(lc, _("Range logic error.\n"));
311             }
312             *p++ = 0;                 /* separate two halves */
313
314             /* Check for day range */
315             if (is_num(lc->str) && is_num(p)) {
316                code = atoi(lc->str) - 1;
317                code2 = atoi(p) - 1;
318                if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
319                   scan_err0(lc, _("Bad day range specification."));
320                }
321                if (!have_mday) {
322                   clear_bits(0, 30, lrun.mday);
323                   clear_bits(0, 6, lrun.wday);
324                   have_mday = TRUE;
325                }
326                if (code < code2) {
327                   set_bits(code, code2, lrun.mday);
328                } else {
329                   set_bits(code, 30, lrun.mday);
330                   set_bits(0, code2, lrun.mday);
331                }
332                break;
333             }
334
335             /* lookup first half of keyword range (week days or months) */
336             lcase(lc->str);
337             for (i=0; keyw[i].name; i++) {
338                if (strcmp(lc->str, keyw[i].name) == 0) {
339                   state = keyw[i].state;
340                   code   = keyw[i].code;
341                   i = 0;
342                   break;
343                }
344             }
345             if (i != 0 || (state != s_month && state != s_wday)) {
346                scan_err0(lc, _("Invalid month or week day range"));
347             }
348
349             /* Lookup end of range */
350             lcase(p);
351             for (i=0; keyw[i].name; i++) {
352                if (strcmp(p, keyw[i].name) == 0) {
353                   state2  = keyw[i].state;
354                   code2   = keyw[i].code;
355                   i = 0;
356                   break;
357                }
358             }
359             if (i != 0 || state != state2 || 
360                (state2 != s_month && state2 != s_wday) || code == code2) {
361                scan_err0(lc, _("Invalid month or weekday range"));
362             }
363             if (state == s_wday) {
364                if (!have_wday) {
365                   clear_bits(0, 6, lrun.wday);
366                   clear_bits(0, 30, lrun.mday);
367                   have_wday = TRUE;
368                }
369                if (code < code2) {
370                   set_bits(code, code2, lrun.wday);
371                } else {
372                   set_bits(code, 6, lrun.wday);
373                   set_bits(0, code2, lrun.wday);
374                }
375             } else {
376                /* must be s_month */
377                if (!have_month) {
378                   clear_bits(0, 30, lrun.month);
379                   have_month = TRUE;
380                }
381                if (code < code2) {
382                   set_bits(code, code2, lrun.month);
383                } else {
384                   /* this is a bit odd, but we accept it anyway */
385                   set_bits(code, 30, lrun.month);
386                   set_bits(0, code2, lrun.month);
387                }
388             }
389             break;
390          case s_hourly:
391             clear_defaults();
392             set_bits(0, 23, lrun.hour);
393             set_bits(0, 30, lrun.mday);
394             set_bits(0, 11, lrun.month);
395             break;
396          case s_weekly:
397             clear_defaults();
398             set_bit(0, lrun.wday);
399             set_bits(0, 11, lrun.month);
400             break;
401          case s_daily:
402             clear_defaults();
403             set_bits(0, 30, lrun.mday);
404             set_bits(0, 11, lrun.month);
405             break;
406          case s_monthly:
407             clear_defaults();
408             set_bit(0, lrun.mday);
409             set_bits(0, 11, lrun.month);
410             break;
411          default:
412             scan_err0(lc, _("Unexpected run state\n"));
413             break;
414       }
415    }
416
417    /* Allocate run record, copy new stuff into it,
418     * and link it into the list of run records 
419     * in the schedule resource.
420     */
421    if (pass == 1) {
422       trun = (RUN *) malloc(sizeof(RUN));
423       memcpy(trun, &lrun, sizeof(RUN));
424       if (*run) {
425          trun->next = *run;
426       }
427       *run = trun;
428    }
429
430    lc->options = options;             /* restore scanner options */
431    set_bit(index, res_all.res_sch.hdr.item_present);
432 }