]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/run_conf.c
This commit was manufactured by cvs2svn to create tag
[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    s_wom,                           /* 1st, 2nd, ...*/
51    s_woy,                           /* week of year w00 - w53 */
52 };  
53
54 struct s_keyw {
55   char *name;                         /* keyword */
56   enum e_state state;                 /* parser state */
57   int code;                           /* state value */
58 };
59
60 /* Keywords understood by parser */
61 static struct s_keyw keyw[] = {
62   {N_("on"),         s_none,    0},
63   {N_("at"),         s_at,      0},
64
65   {N_("sun"),        s_wday,    0},
66   {N_("mon"),        s_wday,    1},
67   {N_("tue"),        s_wday,    2},
68   {N_("wed"),        s_wday,    3},
69   {N_("thu"),        s_wday,    4},
70   {N_("fri"),        s_wday,    5},
71   {N_("sat"),        s_wday,    6},
72   {N_("jan"),        s_month,   0},
73   {N_("feb"),        s_month,   1},
74   {N_("mar"),        s_month,   2},
75   {N_("apr"),        s_month,   3},
76   {N_("may"),        s_month,   4},
77   {N_("jun"),        s_month,   5},
78   {N_("jul"),        s_month,   6},
79   {N_("aug"),        s_month,   7},
80   {N_("sep"),        s_month,   8},
81   {N_("oct"),        s_month,   9},
82   {N_("nov"),        s_month,  10},
83   {N_("dec"),        s_month,  11},
84
85   {N_("sunday"),     s_wday,    0},
86   {N_("monday"),     s_wday,    1},
87   {N_("tuesday"),    s_wday,    2},
88   {N_("wednesday"),  s_wday,    3},
89   {N_("thursday"),   s_wday,    4},
90   {N_("friday"),     s_wday,    5},
91   {N_("saturday"),   s_wday,    6},
92   {N_("january"),    s_month,   0},
93   {N_("february"),   s_month,   1},
94   {N_("march"),      s_month,   2},
95   {N_("april"),      s_month,   3},
96   {N_("june"),       s_month,   5},
97   {N_("july"),       s_month,   6},
98   {N_("august"),     s_month,   7},
99   {N_("september"),  s_month,   8},
100   {N_("october"),    s_month,   9},
101   {N_("november"),   s_month,  10},
102   {N_("december"),   s_month,  11},
103
104   {N_("daily"),      s_daily,   0},
105   {N_("weekly"),     s_weekly,  0},
106   {N_("monthly"),    s_monthly, 0},
107   {N_("hourly"),     s_hourly,  0},
108
109   {N_("1st"),        s_wom,     0},
110   {N_("2nd"),        s_wom,     1},
111   {N_("3rd"),        s_wom,     2},
112   {N_("4th"),        s_wom,     3},
113   {N_("5th"),        s_wom,     4},
114
115   {N_("first"),      s_wom,     0},
116   {N_("second"),     s_wom,     1},
117   {N_("third"),      s_wom,     2},
118   {N_("fourth"),     s_wom,     3},
119   {N_("fifth"),      s_wom,     4},
120   {NULL,         s_none,    0}
121 };
122
123 static bool have_hour, have_mday, have_wday, have_month, have_wom;
124 static bool have_at, have_woy;
125 static RUN lrun;
126
127 static void clear_defaults()
128 {
129    have_hour = have_mday = have_wday = have_month = have_wom = have_woy = true;
130    clear_bit(0,lrun.hour);
131    clear_bits(0, 30, lrun.mday);
132    clear_bits(0, 6, lrun.wday);
133    clear_bits(0, 11, lrun.month);
134    clear_bits(0, 4, lrun.wom);
135    clear_bits(0, 53, lrun.woy);
136 }
137
138 static void set_defaults()
139 {
140    have_hour = have_mday = have_wday = have_month = have_wom = have_woy = false;
141    have_at = false;
142    set_bit(0,lrun.hour);
143    set_bits(0, 30, lrun.mday);
144    set_bits(0, 6, lrun.wday);
145    set_bits(0, 11, lrun.month);
146    set_bits(0, 4, lrun.wom);
147    set_bits(0, 53, lrun.woy);
148 }
149
150
151 /* Keywords (RHS) permitted in Run records */
152 static struct s_kw RunFields[] = {
153    {"pool",     'P'},
154    {"level",    'L'},
155    {"storage",  'S'},
156    {"messages", 'M'},
157    {"priority", 'p'},
158    {NULL,        0}
159 };
160
161 /* 
162  * Store Schedule Run information   
163  * 
164  * Parse Run statement:
165  *
166  *  Run <keyword=value ...> [on] 2 january at 23:45
167  *
168  *   Default Run time is daily at 0:0
169  *  
170  *   There can be multiple run statements, they are simply chained
171  *   together.
172  *
173  */
174 void store_run(LEX *lc, struct res_items *item, int index, int pass)
175 {
176    int i, j;
177    bool found;
178    int token, state, state2 = 0, code = 0, code2 = 0;
179    int options = lc->options;
180    RUN **run = (RUN **)(item->value);   
181    RUN *trun;
182    char *p;
183    RES *res;
184
185
186    lc->options |= LOPT_NO_IDENT;      /* want only "strings" */
187
188    /* clear local copy of run record */
189    memset(&lrun, 0, sizeof(RUN));
190
191    /* scan for Job level "full", "incremental", ... */
192    for (found=true; found; ) {
193       found = false;
194       token = lex_get_token(lc, T_NAME);
195       for (i=0; RunFields[i].name; i++) {
196          if (strcasecmp(lc->str, RunFields[i].name) == 0) {
197             found = true;
198             if (lex_get_token(lc, T_ALL) != T_EQUALS) {
199                scan_err1(lc, "Expected an equals, got: %s", lc->str);
200                /* NOT REACHED */ 
201             }
202             switch (RunFields[i].token) {
203             case 'L':                 /* level */
204                token = lex_get_token(lc, T_NAME);
205                for (j=0; joblevels[j].level_name; j++) {
206                   if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
207                      lrun.level = joblevels[j].level;
208                      lrun.job_type = joblevels[j].job_type;
209                      j = 0;
210                      break;
211                   }
212                }
213                if (j != 0) {
214                   scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
215                   /* NOT REACHED */
216                }
217                break;
218             case 'p':                 /* Priority */
219                token = lex_get_token(lc, T_PINT32);
220                if (pass == 2) {
221                   lrun.Priority = lc->pint32_val;
222                }
223                break;
224             case 'P':                 /* Pool */
225                token = lex_get_token(lc, T_NAME);
226                if (pass == 2) {
227                   res = GetResWithName(R_POOL, lc->str);
228                   if (res == NULL) {
229                      scan_err1(lc, "Could not find specified Pool Resource: %s",
230                                 lc->str);
231                      /* NOT REACHED */
232                   }
233                   lrun.pool = (POOL *)res;
234                }
235                break;
236             case 'S':                 /* storage */
237                token = lex_get_token(lc, T_NAME);
238                if (pass == 2) {
239                   res = GetResWithName(R_STORAGE, lc->str);
240                   if (res == NULL) {
241                      scan_err1(lc, "Could not find specified Storage Resource: %s",
242                                 lc->str);
243                      /* NOT REACHED */
244                   }
245                   lrun.storage = (STORE *)res;
246                }
247                break;
248             case 'M':                 /* messages */
249                token = lex_get_token(lc, T_NAME);
250                if (pass == 2) {
251                   res = GetResWithName(R_MSGS, lc->str);
252                   if (res == NULL) {
253                      scan_err1(lc, "Could not find specified Messages Resource: %s",
254                                 lc->str);
255                      /* NOT REACHED */
256                   }
257                   lrun.msgs = (MSGS *)res;
258                }
259                break;
260             default:
261                scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
262                /* NOT REACHED */
263                break;
264             } /* end switch */     
265          } /* end if strcasecmp */
266       } /* end for RunFields */
267
268       /* At this point, it is not a keyword. Check for old syle
269        * Job Levels without keyword. This form is depreciated!!!
270        */
271       for (j=0; joblevels[j].level_name; j++) {
272          if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
273             lrun.level = joblevels[j].level;
274             lrun.job_type = joblevels[j].job_type;
275             found = true;
276             break;
277          }
278       }
279    } /* end for found */
280
281
282    /*
283     * Scan schedule times.
284     * Default is: daily at 0:0
285     */
286    state = s_none;
287    set_defaults();
288
289    for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
290       int len, pm = 0;
291       switch (token) {
292       case T_NUMBER:
293          state = s_mday;
294          code = atoi(lc->str) - 1;
295          if (code < 0 || code > 30) {
296             scan_err0(lc, _("Day number out of range (1-31)"));
297          }
298          break;
299       case T_NAME:                 /* this handles drop through from keyword */
300       case T_UNQUOTED_STRING:
301          if (strchr(lc->str, (int)'-')) {
302             state = s_range;
303             break;
304          }
305          if (strchr(lc->str, (int)':')) {
306             state = s_time;
307             break;
308          }
309          if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
310              is_an_integer(lc->str+1)) {
311             code = atoi(lc->str+1);
312             if (code < 0 || code > 53) {
313                scan_err0(lc, _("Week number out of range (0-53)"));
314             }
315             state = s_woy;            /* week of year */
316             break;
317          }
318          /* everything else must be a keyword */
319          for (i=0; keyw[i].name; i++) {
320             if (strcasecmp(lc->str, keyw[i].name) == 0) {
321                state = keyw[i].state;
322                code   = keyw[i].code;
323                i = 0;
324                break;
325             }
326          }
327          if (i != 0) {
328             scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
329             /* NOT REACHED */
330          }
331          break;
332       case T_COMMA:
333          continue;
334       default:
335          scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
336          /* NOT REACHED */
337          break;
338       }
339       switch (state) {
340       case s_none:
341          continue;
342       case s_mday:                 /* day of month */
343          if (!have_mday) {
344             clear_bits(0, 30, lrun.mday);
345             clear_bits(0, 6, lrun.wday);
346             have_mday = true;
347          }
348          set_bit(code, lrun.mday);
349          break;
350       case s_month:                /* month of year */
351          if (!have_month) {
352             clear_bits(0, 11, lrun.month);
353             have_month = true;
354          }
355          set_bit(code, lrun.month);
356          break;
357       case s_wday:                 /* week day */
358          if (!have_wday) {
359             clear_bits(0, 6, lrun.wday);
360             clear_bits(0, 30, lrun.mday);
361             have_wday = true;
362          }
363          set_bit(code, lrun.wday);
364          break;
365       case s_wom:                  /* Week of month 1st, ... */
366          if (!have_wom) {
367             clear_bits(0, 4, lrun.wom);
368             have_wom = true;
369          }
370          set_bit(code, lrun.wom);
371          break;
372       case s_woy:
373          if (!have_woy) {
374             clear_bits(0, 53, lrun.woy);
375             have_woy = true;
376          }
377          set_bit(code, lrun.woy);
378          break;
379       case s_time:                 /* time */
380          if (!have_at) {
381             scan_err0(lc, _("Time must be preceded by keyword AT."));
382             /* NOT REACHED */
383          }
384          if (!have_hour) {
385             clear_bit(0, lrun.hour);
386          }
387          p = strchr(lc->str, ':');
388          if (!p)  {
389             scan_err0(lc, _("Time logic error.\n"));
390             /* NOT REACHED */
391          }
392          *p++ = 0;                 /* separate two halves */
393          code = atoi(lc->str);
394          len = strlen(p);
395          if (len > 2 && p[len-1] == 'm') {
396             if (p[len-2] == 'a') {
397                pm = 0;
398             } else if (p[len-2] == 'p') {
399                pm = 1;
400             } else {
401                scan_err0(lc, _("Bad time specification."));
402                /* NOT REACHED */
403             }
404          } else {
405             pm = 0;
406          }
407          code2 = atoi(p);
408          if (pm) {
409             code += 12;
410          }
411          if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
412             scan_err0(lc, _("Bad time specification."));
413             /* NOT REACHED */
414          }
415          set_bit(code, lrun.hour);
416          lrun.minute = code2;
417          have_hour = true;
418          break;
419       case s_at:
420          have_at = true;
421          break;
422       case s_range:
423          p = strchr(lc->str, '-');
424          if (!p) {
425             scan_err0(lc, _("Range logic error.\n"));
426          }
427          *p++ = 0;                 /* separate two halves */
428
429          /* Check for day range */
430          if (is_an_integer(lc->str) && is_an_integer(p)) {
431             code = atoi(lc->str) - 1;
432             code2 = atoi(p) - 1;
433             if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
434                scan_err0(lc, _("Bad day range specification."));
435             }
436             if (!have_mday) {
437                clear_bits(0, 30, lrun.mday);
438                clear_bits(0, 6, lrun.wday);
439                have_mday = true;
440             }
441             if (code < code2) {
442                set_bits(code, code2, lrun.mday);
443             } else {
444                set_bits(code, 30, lrun.mday);
445                set_bits(0, code2, lrun.mday);
446             }
447             break;
448          }
449          /* Check for week of year range */
450          if (strlen(lc->str) == 3 && strlen(p) == 3 &&
451              (lc->str[0] == 'w' || lc->str[0] == 'W') &&
452              (p[0] == 'w' || p[0] == 'W') &&
453              is_an_integer(lc->str+1) && is_an_integer(p+1)) {
454             code = atoi(lc->str+1);
455             code2 = atoi(p+1);
456             if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
457                scan_err0(lc, _("Week number out of range (0-53)"));
458             }
459             if (!have_woy) {
460                clear_bits(0, 53, lrun.woy);
461                have_woy = true;
462             }
463             if (code < code2) {
464                set_bits(code, code2, lrun.woy);
465             } else {
466                set_bits(code, 53, lrun.woy);
467                set_bits(0, code2, lrun.woy);
468             }
469             break;
470          }
471          /* lookup first half of keyword range (week days or months) */
472          lcase(lc->str);
473          for (i=0; keyw[i].name; i++) {
474             if (strcmp(lc->str, keyw[i].name) == 0) {
475                state = keyw[i].state;
476                code   = keyw[i].code;
477                i = 0;
478                break;
479             }
480          }
481          if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) {
482             scan_err0(lc, _("Invalid month, week or position day range"));
483             /* NOT REACHED */
484          }
485
486          /* Lookup end of range */
487          lcase(p);
488          for (i=0; keyw[i].name; i++) {
489             if (strcmp(p, keyw[i].name) == 0) {
490                state2  = keyw[i].state;
491                code2   = keyw[i].code;
492                i = 0;
493                break;
494             }
495          }
496          if (i != 0 || state != state2 || code == code2) {
497             scan_err0(lc, _("Invalid month, weekday or position range"));
498             /* NOT REACHED */
499          }
500          if (state == s_wday) {
501             if (!have_wday) {
502                clear_bits(0, 6, lrun.wday);
503                clear_bits(0, 30, lrun.mday);
504                have_wday = true;
505             }
506             if (code < code2) {
507                set_bits(code, code2, lrun.wday);
508             } else {
509                set_bits(code, 6, lrun.wday);
510                set_bits(0, code2, lrun.wday);
511             }
512          } else if (state == s_month) {
513             if (!have_month) {
514                clear_bits(0, 30, lrun.month);
515                have_month = true;
516             }
517             if (code < code2) {
518                set_bits(code, code2, lrun.month);
519             } else {
520                /* this is a bit odd, but we accept it anyway */
521                set_bits(code, 30, lrun.month);
522                set_bits(0, code2, lrun.month);
523             }
524          } else {
525             /* Must be position */
526             if (!have_wom) {
527                clear_bits(0, 4, lrun.wom);
528                have_wom = true;
529             }
530             if (code < code2) {
531                set_bits(code, code2, lrun.wom);
532             } else {
533                set_bits(code, 4, lrun.wom);
534                set_bits(0, code2, lrun.wom);
535             }
536          }                      
537          break;
538       case s_hourly:
539          clear_defaults();
540          set_bits(0, 23, lrun.hour);
541          set_bits(0, 30, lrun.mday);
542          set_bits(0, 11, lrun.month);
543          set_bits(0, 4, lrun.wom);
544          set_bits(0, 53, lrun.woy);
545          break;
546       case s_weekly:
547          clear_defaults();
548          set_bit(0, lrun.wday);
549          set_bits(0, 11, lrun.month);
550          set_bits(0, 4, lrun.wom);
551          set_bits(0, 53, lrun.woy);
552          break;
553       case s_daily:
554          clear_defaults();
555          set_bits(0, 30, lrun.mday);
556          set_bits(0, 11, lrun.month);
557          set_bits(0, 4,  lrun.wom);
558          set_bits(0, 53, lrun.woy);
559          break;
560       case s_monthly:
561          clear_defaults();
562          set_bits(0, 11, lrun.month);
563          set_bits(0, 4,  lrun.wom);
564          set_bits(0, 53, lrun.woy);
565          break;
566       default:
567          scan_err0(lc, _("Unexpected run state\n"));
568          /* NOT REACHED */
569          break;
570       }
571    }
572
573    /* Allocate run record, copy new stuff into it,
574     * and link it into the list of run records 
575     * in the schedule resource.
576     */
577    if (pass == 2) {
578       trun = (RUN *)malloc(sizeof(RUN));
579       memcpy(trun, &lrun, sizeof(RUN));
580       if (*run) {
581          trun->next = *run;
582       }
583       *run = trun;
584    }
585
586    lc->options = options;             /* restore scanner options */
587    set_bit(index, res_all.res_sch.hdr.item_present);
588 }