]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/run_conf.c
Fix uninitialized variables
[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  *     Version $Id$
9  */
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
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.
17
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.
22
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,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 extern URES res_all;
34 extern struct s_jl joblevels[];
35
36 /* Forward referenced subroutines */
37
38 enum e_state {
39    s_none = 0,
40    s_range,
41    s_mday,
42    s_month,
43    s_time,
44    s_at,
45    s_wday,
46    s_daily,
47    s_weekly,
48    s_monthly,
49    s_hourly,
50 };  
51
52 struct s_keyw {
53   char *name;                         /* keyword */
54   enum e_state state;                 /* parser state */
55   int code;                           /* state value */
56 };
57
58 /* Keywords understood by parser */
59 static struct s_keyw keyw[] = {
60   {N_("on"),         s_none,    0},
61   {N_("at"),         s_at,      0},
62
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},
82
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},
101
102   {N_("daily"),      s_daily,   0},
103   {N_("weekly"),     s_weekly,  0},
104   {N_("monthly"),    s_monthly, 0},
105   {N_("hourly"),     s_hourly,  0},
106   {NULL,         s_none,    0}
107 };
108
109 static int have_hour, have_mday, have_wday, have_month;
110 static int have_at;
111 static RUN lrun;
112
113 static void clear_defaults()
114 {
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);
120 }
121
122 static void set_defaults()
123 {
124    have_hour = have_mday = have_wday = have_month = FALSE;
125    have_at = 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);
130 }
131
132
133 /* Check if string is a number */
134 static int is_num(char *num)
135 {
136    char *p = num;
137    int ch;
138    while ((ch = *p++)) {
139       if (ch < '0' || ch > '9') {
140          return FALSE;
141       }
142    }
143    return TRUE;
144 }
145
146 /* Keywords (RHS) permitted in Run records */
147 static struct s_kw RunFields[] = {
148    {"pool",     'P'},
149    {"level",    'L'},
150    {"storage",  'S'},
151    {"messages", 'M'},
152    {NULL,        0}
153 };
154
155 /* 
156  * Store Schedule Run information   
157  * 
158  * Parse Run statement:
159  *
160  *  Run <keyword=value ...> [on] 2 january at 23:45
161  *
162  *   Default Run time is daily at 0:0
163  *  
164  *   There can be multiple run statements, they are simply chained
165  *   together.
166  *
167  */
168 void store_run(LEX *lc, struct res_items *item, int index, int pass)
169 {
170    int i, j, found;
171    int token, state, state2 = 0, code = 0, code2 = 0;
172    int options = lc->options;
173    RUN **run = (RUN **)(item->value);   
174    RUN *trun;
175    char *p;
176    RES *res;
177
178
179    lc->options |= LOPT_NO_IDENT;      /* want only "strings" */
180
181    /* clear local copy of run record */
182    memset(&lrun, 0, sizeof(RUN));
183
184    /* scan for Job level "full", "incremental", ... */
185    for (found=TRUE; found; ) {
186       found = FALSE;
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) {
190             found = TRUE;
191             if (lex_get_token(lc, T_ALL) != T_EQUALS) {
192                scan_err1(lc, "Expected an equals, got: %s", lc->str);
193                /* NOT REACHED */ 
194             }
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;
202                      j = 0;
203                      break;
204                   }
205                }
206                if (j != 0) {
207                   scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
208                   /* NOT REACHED */
209                }
210                break;
211             case 'P':                 /* Pool */
212                if (pass == 2) {
213                   res = GetResWithName(R_POOL, lc->str);
214                   if (res == NULL) {
215                      scan_err1(lc, "Could not find specified Pool Resource: %s",
216                                 lc->str);
217                      /* NOT REACHED */
218                   }
219                   lrun.pool = (POOL *)res;
220                }
221                break;
222             case 'S':                 /* storage */
223                if (pass == 2) {
224                   res = GetResWithName(R_STORAGE, lc->str);
225                   if (res == NULL) {
226                      scan_err1(lc, "Could not find specified Storage Resource: %s",
227                                 lc->str);
228                      /* NOT REACHED */
229                   }
230                   lrun.storage = (STORE *)res;
231                }
232                break;
233             case 'M':                 /* messages */
234                if (pass == 2) {
235                   res = GetResWithName(R_MSGS, lc->str);
236                   if (res == NULL) {
237                      scan_err1(lc, "Could not find specified Messages Resource: %s",
238                                 lc->str);
239                      /* NOT REACHED */
240                   }
241                   lrun.msgs = (MSGS *)res;
242                }
243                break;
244             default:
245                scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
246                /* NOT REACHED */
247                break;
248             } /* end switch */     
249          } /* end if strcasecmp */
250       } /* end for RunFields */
251
252       /* At this point, it is not a keyword. Check for old syle
253        * Job Levels without keyword. This form is depreciated!!!
254        */
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;
259             found = TRUE;
260             break;
261          }
262       }
263    } /* end for found */
264
265
266    /*
267     * Scan schedule times.
268     * Default is: daily at 0:0
269     */
270    state = s_none;
271    set_defaults();
272
273    for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
274       int len, pm = 0;
275       switch (token) {
276          case T_NUMBER:
277             state = s_mday;
278             code = atoi(lc->str) - 1;
279             if (code < 0 || code > 30) {
280                scan_err0(lc, _("Day number out of range (1-31)"));
281             }
282             break;
283          case T_NAME:                 /* this handles drop through from keyword */
284          case T_UNQUOTED_STRING:
285             if (strchr(lc->str, (int)'-')) {
286                state = s_range;
287                break;
288             }
289             if (strchr(lc->str, (int)':')) {
290                state = s_time;
291                break;
292             }
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;
297                   code   = keyw[i].code;
298                   i = 0;
299                   break;
300                }
301             }
302             if (i != 0) {
303                scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
304                /* NOT REACHED */
305             }
306             break;
307          case T_COMMA:
308             continue;
309          default:
310             scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
311             /* NOT REACHED */
312             break;
313       }
314       switch (state) {
315          case s_none:
316             continue;
317          case s_mday:                 /* day of month */
318             if (!have_mday) {
319                clear_bits(0, 30, lrun.mday);
320                clear_bits(0, 6, lrun.wday);
321                have_mday = TRUE;
322             }
323             set_bit(code, lrun.mday);
324             break;
325          case s_month:                /* month of year */
326             if (!have_month) {
327                clear_bits(0, 11, lrun.month);
328                have_month = TRUE;
329             }
330             set_bit(code, lrun.month);
331             break;
332          case s_wday:                 /* week day */
333             if (!have_wday) {
334                clear_bits(0, 6, lrun.wday);
335                clear_bits(0, 30, lrun.mday);
336                have_wday = TRUE;
337             }
338             set_bit(code, lrun.wday);
339             break;
340          case s_time:                 /* time */
341             if (!have_at) {
342                scan_err0(lc, _("Time must be preceded by keyword AT."));
343                /* NOT REACHED */
344             }
345             if (!have_hour) {
346                clear_bit(0, lrun.hour);
347             }
348             p = strchr(lc->str, ':');
349             if (!p)  {
350                scan_err0(lc, _("Time logic error.\n"));
351                /* NOT REACHED */
352             }
353             *p++ = 0;                 /* separate two halves */
354             code = atoi(lc->str);
355             len = strlen(p);
356             if (len > 2 && p[len-1] == 'm') {
357                if (p[len-2] == 'a') {
358                   pm = 0;
359                } else if (p[len-2] == 'p') {
360                   pm = 1;
361                } else {
362                   scan_err0(lc, _("Bad time specification."));
363                   /* NOT REACHED */
364                }
365             } else {
366                pm = 0;
367             }
368             code2 = atoi(p);
369             if (pm) {
370                code += 12;
371             }
372             if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
373                scan_err0(lc, _("Bad time specification."));
374                /* NOT REACHED */
375             }
376             set_bit(code, lrun.hour);
377             lrun.minute = code2;
378             have_hour = TRUE;
379             break;
380          case s_at:
381             have_at = TRUE;
382             break;
383          case s_range:
384             p = strchr(lc->str, '-');
385             if (!p) {
386                scan_err0(lc, _("Range logic error.\n"));
387             }
388             *p++ = 0;                 /* separate two halves */
389
390             /* Check for day range */
391             if (is_num(lc->str) && is_num(p)) {
392                code = atoi(lc->str) - 1;
393                code2 = atoi(p) - 1;
394                if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
395                   scan_err0(lc, _("Bad day range specification."));
396                }
397                if (!have_mday) {
398                   clear_bits(0, 30, lrun.mday);
399                   clear_bits(0, 6, lrun.wday);
400                   have_mday = TRUE;
401                }
402                if (code < code2) {
403                   set_bits(code, code2, lrun.mday);
404                } else {
405                   set_bits(code, 30, lrun.mday);
406                   set_bits(0, code2, lrun.mday);
407                }
408                break;
409             }
410
411             /* lookup first half of keyword range (week days or months) */
412             lcase(lc->str);
413             for (i=0; keyw[i].name; i++) {
414                if (strcmp(lc->str, keyw[i].name) == 0) {
415                   state = keyw[i].state;
416                   code   = keyw[i].code;
417                   i = 0;
418                   break;
419                }
420             }
421             if (i != 0 || (state != s_month && state != s_wday)) {
422                scan_err0(lc, _("Invalid month or week day range"));
423                /* NOT REACHED */
424             }
425
426             /* Lookup end of range */
427             lcase(p);
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;
432                   i = 0;
433                   break;
434                }
435             }
436             if (i != 0 || state != state2 || 
437                (state2 != s_month && state2 != s_wday) || code == code2) {
438                scan_err0(lc, _("Invalid month or weekday range"));
439                /* NOT REACHED */
440             }
441             if (state == s_wday) {
442                if (!have_wday) {
443                   clear_bits(0, 6, lrun.wday);
444                   clear_bits(0, 30, lrun.mday);
445                   have_wday = TRUE;
446                }
447                if (code < code2) {
448                   set_bits(code, code2, lrun.wday);
449                } else {
450                   set_bits(code, 6, lrun.wday);
451                   set_bits(0, code2, lrun.wday);
452                }
453             } else {
454                /* must be s_month */
455                if (!have_month) {
456                   clear_bits(0, 30, lrun.month);
457                   have_month = TRUE;
458                }
459                if (code < code2) {
460                   set_bits(code, code2, lrun.month);
461                } else {
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);
465                }
466             }
467             break;
468          case s_hourly:
469             clear_defaults();
470             set_bits(0, 23, lrun.hour);
471             set_bits(0, 30, lrun.mday);
472             set_bits(0, 11, lrun.month);
473             break;
474          case s_weekly:
475             clear_defaults();
476             set_bit(0, lrun.wday);
477             set_bits(0, 11, lrun.month);
478             break;
479          case s_daily:
480             clear_defaults();
481             set_bits(0, 30, lrun.mday);
482             set_bits(0, 11, lrun.month);
483             break;
484          case s_monthly:
485             clear_defaults();
486             set_bits(0, 11, lrun.month);
487             break;
488          default:
489             scan_err0(lc, _("Unexpected run state\n"));
490             /* NOT REACHED */
491             break;
492       }
493    }
494
495    /* Allocate run record, copy new stuff into it,
496     * and link it into the list of run records 
497     * in the schedule resource.
498     */
499    if (pass == 2) {
500       trun = (RUN *)malloc(sizeof(RUN));
501       memcpy(trun, &lrun, sizeof(RUN));
502       if (*run) {
503          trun->next = *run;
504       }
505       *run = trun;
506    }
507
508    lc->options = options;             /* restore scanner options */
509    set_bit(index, res_all.res_sch.hdr.item_present);
510 }