]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/run_conf.c
c58a713f5da19c12b23760bd14def279595b4e71
[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       lcase(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;
182             i = 0;
183             break;
184          }
185       }
186       if (i != 0) {
187          scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
188       }
189    }
190
191    /*
192     * Scan schedule times.
193     * Default is: daily at 0:0
194     */
195    state = s_none;
196    set_defaults();
197
198    while ((token = lex_get_token(lc)) != T_EOL) {
199       int len, pm;
200       switch (token) {
201          case T_NUMBER:
202             state = s_mday;
203             code = atoi(lc->str) - 1;
204             if (code < 0 || code > 30) {
205                scan_err0(lc, _("Day number out of range (1-31)"));
206             }
207             break;
208          case T_STRING:
209             if (strchr(lc->str, (int)'-')) {
210                state = s_range;
211                break;
212             }
213             if (strchr(lc->str, (int)':')) {
214                state = s_time;
215                break;
216             }
217             /* everything else must be a keyword */
218             lcase(lc->str);
219             for (i=0; keyw[i].name; i++) {
220                if (strcmp(lc->str, keyw[i].name) == 0) {
221                   state = keyw[i].state;
222                   code   = keyw[i].code;
223                   i = 0;
224                   break;
225                }
226             }
227             if (i != 0) {
228                scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
229             }
230             break;
231          case T_COMMA:
232             continue;
233          default:
234             scan_err1(lc, _("Unexpected token: %s"), lc->str);
235             break;
236       }
237       switch (state) {
238          case s_none:
239             continue;
240          case s_mday:                 /* day of month */
241             if (!have_mday) {
242                clear_bits(0, 30, lrun.mday);
243                clear_bits(0, 6, lrun.wday);
244                have_mday = TRUE;
245             }
246             set_bit(code, lrun.mday);
247             break;
248          case s_month:                /* month of year */
249             if (!have_month) {
250                clear_bits(0, 11, lrun.month);
251                have_month = TRUE;
252             }
253             set_bit(code, lrun.month);
254             break;
255          case s_wday:                 /* week day */
256             if (!have_wday) {
257                clear_bits(0, 6, lrun.wday);
258                clear_bits(0, 30, lrun.mday);
259                have_wday = TRUE;
260             }
261             set_bit(code, lrun.wday);
262             break;
263          case s_time:                 /* time */
264             if (!have_at) {
265                scan_err0(lc, _("Time must be preceded by keyword AT."));
266             }
267             if (!have_hour) {
268                clear_bit(0, lrun.hour);
269                have_hour = TRUE;
270             }
271             p = strchr(lc->str, ':');
272             if (!p)  {
273                scan_err0(lc, _("Time logic error.\n"));
274             }
275             *p++ = 0;                 /* separate two halves */
276             code = atoi(lc->str);
277             len = strlen(p);
278             if (len > 2 && p[len-1] == 'm') {
279                if (p[len-2] == 'a') {
280                   pm = 0;
281                } else if (p[len-2] == 'p') {
282                   pm = 1;
283                } else {
284                   scan_err0(lc, _("Bad time specification."));
285                }
286             } else {
287                pm = 0;
288             }
289             code2 = atoi(p);
290             if (pm) {
291                code += 12;
292             }
293             if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
294                scan_err0(lc, _("Bad time specification."));
295             }
296             set_bit(code, lrun.hour);
297             lrun.minute = code2;
298             break;
299          case s_at:
300             have_at = TRUE;
301             break;
302          case s_range:
303             p = strchr(lc->str, '-');
304             if (!p) {
305                scan_err0(lc, _("Range logic error.\n"));
306             }
307             *p++ = 0;                 /* separate two halves */
308
309             /* Check for day range */
310             if (is_num(lc->str) && is_num(p)) {
311                code = atoi(lc->str) - 1;
312                code2 = atoi(p) - 1;
313                if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
314                   scan_err0(lc, _("Bad day range specification."));
315                }
316                if (!have_mday) {
317                   clear_bits(0, 30, lrun.mday);
318                   clear_bits(0, 6, lrun.wday);
319                   have_mday = TRUE;
320                }
321                if (code < code2) {
322                   set_bits(code, code2, lrun.mday);
323                } else {
324                   set_bits(code, 30, lrun.mday);
325                   set_bits(0, code2, lrun.mday);
326                }
327                break;
328             }
329
330             /* lookup first half of keyword range (week days or months) */
331             lcase(lc->str);
332             for (i=0; keyw[i].name; i++) {
333                if (strcmp(lc->str, keyw[i].name) == 0) {
334                   state = keyw[i].state;
335                   code   = keyw[i].code;
336                   i = 0;
337                   break;
338                }
339             }
340             if (i != 0 || (state != s_month && state != s_wday)) {
341                scan_err0(lc, _("Invalid month or week day range"));
342             }
343
344             /* Lookup end of range */
345             lcase(p);
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;
350                   i = 0;
351                   break;
352                }
353             }
354             if (i != 0 || state != state2 || 
355                (state2 != s_month && state2 != s_wday) || code == code2) {
356                scan_err0(lc, _("Invalid month or weekday range"));
357             }
358             if (state == s_wday) {
359                if (!have_wday) {
360                   clear_bits(0, 6, lrun.wday);
361                   clear_bits(0, 30, lrun.mday);
362                   have_wday = TRUE;
363                }
364                if (code < code2) {
365                   set_bits(code, code2, lrun.wday);
366                } else {
367                   set_bits(code, 6, lrun.wday);
368                   set_bits(0, code2, lrun.wday);
369                }
370             } else {
371                /* must be s_month */
372                if (!have_month) {
373                   clear_bits(0, 30, lrun.month);
374                   have_month = TRUE;
375                }
376                if (code < code2) {
377                   set_bits(code, code2, lrun.month);
378                } else {
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);
382                }
383             }
384             break;
385          case s_hourly:
386             clear_defaults();
387             set_bits(0, 23, lrun.hour);
388             set_bits(0, 30, lrun.mday);
389             set_bits(0, 11, lrun.month);
390             break;
391          case s_weekly:
392             clear_defaults();
393             set_bit(0, lrun.wday);
394             set_bits(0, 11, lrun.month);
395             break;
396          case s_daily:
397             clear_defaults();
398             set_bits(0, 30, lrun.mday);
399             set_bits(0, 11, lrun.month);
400             break;
401          case s_monthly:
402             clear_defaults();
403             set_bit(0, lrun.mday);
404             set_bits(0, 11, lrun.month);
405             break;
406          default:
407             scan_err0(lc, _("Unexpected run state\n"));
408             break;
409       }
410    }
411
412    /* Allocate run record, copy new stuff into it,
413     * and link it into the list of run records 
414     * in the schedule resource.
415     */
416    if (pass == 1) {
417       trun = (RUN *) malloc(sizeof(RUN));
418       memcpy(trun, &lrun, sizeof(RUN));
419       if (*run) {
420          trun->next = *run;
421       }
422       *run = trun;
423    }
424
425    lc->options = options;             /* restore scanner options */
426    set_bit(index, res_all.res_sch.hdr.item_present);
427 }