]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
d9aac3bad1b740fa4423e08bcc0750d4aa476d82
[bacula/bacula] / bacula / src / dird / inc_conf.c
1 /*
2  *   Configuration file parser for Include, Exclude, Finclude
3  *    and FExclude records.
4  *
5  *     Kern Sibbald, March MMIII
6  *
7  *     Version $Id$
8  */
9 /*
10    Copyright (C) 2000-2003 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "dird.h"
31
32 /* Forward referenced subroutines */
33
34 void store_inc(LEX *lc, struct res_items *item, int index, int pass);
35 void store_finc(LEX *lc, struct res_items *item, int index, int pass);
36
37 static void store_match(LEX *lc, struct res_items *item, int index, int pass);
38 static void store_opts(LEX *lc, struct res_items *item, int index, int pass);
39 static void store_fname(LEX *lc, struct res_items *item, int index, int pass);
40 static void store_base(LEX *lc, struct res_items *item, int index, int pass);
41 static void setup_current_opts(void);
42
43
44 /* We build the current resource here as we are
45  * scanning the resource configuration definition,
46  * then move it to allocated memory when the resource
47  * scan is complete.
48  */
49 extern URES res_all;
50 extern int  res_all_size;
51
52 /* We build the current Finclude Fexclude item here */
53 static INCEXE res_incexe;
54
55 /* 
56  * FInclude/FExclude items
57  *   name             handler     value                        code flags default_value
58  */
59 static struct res_items finc_items[] = {
60    {"compression",     store_opts,    NULL,     0, 0, 0},
61    {"signature",       store_opts,    NULL,     0, 0, 0},
62    {"verify",          store_opts,    NULL,     0, 0, 0},
63    {"onefs",           store_opts,    NULL,     0, 0, 0},
64    {"recurse",         store_opts,    NULL,     0, 0, 0},
65    {"sparse",          store_opts,    NULL,     0, 0, 0},
66    {"readfifo",        store_opts,    NULL,     0, 0, 0},
67    {"replace",         store_opts,    NULL,     0, 0, 0},
68    {"portable",        store_opts,    NULL,     0, 0, 0},
69    {"match",           store_match,   NULL,     0, 0, 0},
70    {"file",            store_fname,   NULL,     0, 0, 0},
71    {"base",            store_base,    NULL,     0, 0, 0},
72    {NULL, NULL, NULL, 0, 0, 0} 
73 };
74
75 /* Define FileSet KeyWord values */
76
77 #define INC_KW_NONE         0
78 #define INC_KW_COMPRESSION  1
79 #define INC_KW_SIGNATURE    2
80 #define INC_KW_ENCRYPTION   3
81 #define INC_KW_VERIFY       4
82 #define INC_KW_ONEFS        5
83 #define INC_KW_RECURSE      6
84 #define INC_KW_SPARSE       7
85 #define INC_KW_REPLACE      8         /* restore options */
86 #define INC_KW_READFIFO     9         /* Causes fifo data to be read */
87 #define INC_KW_PORTABLE    10
88
89 /* Include keywords -- these are keywords that can appear
90  *    in the options lists of an include ( Include = compression= ...)
91  */
92 static struct s_kw FS_option_kw[] = {
93    {"compression", INC_KW_COMPRESSION},
94    {"signature",   INC_KW_SIGNATURE},
95    {"encryption",  INC_KW_ENCRYPTION},
96    {"verify",      INC_KW_VERIFY},
97    {"onefs",       INC_KW_ONEFS},
98    {"recurse",     INC_KW_RECURSE},
99    {"sparse",      INC_KW_SPARSE},
100    {"replace",     INC_KW_REPLACE},
101    {"readfifo",    INC_KW_READFIFO},
102    {"portable",    INC_KW_PORTABLE},
103    {NULL,          0}
104 };
105
106 /* Options for FileSet keywords */
107
108 struct s_fs_opt {
109    char *name;
110    int keyword;
111    char *option;
112 };
113
114 /*
115  * Options permitted for each keyword and resulting value.     
116  * The output goes into opts, which are then transmitted to
117  * the FD for application as options to the following list of
118  * included files.
119  */
120 static struct s_fs_opt FS_options[] = {
121    {"md5",      INC_KW_SIGNATURE,    "M"},
122    {"sha1",     INC_KW_SIGNATURE,    "S"},
123    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
124    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
125    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
126    {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
127    {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
128    {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
129    {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
130    {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
131    {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
132    {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
133    {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
134    {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
135    {"yes",      INC_KW_ONEFS,         "0"},
136    {"no",       INC_KW_ONEFS,         "f"},
137    {"yes",      INC_KW_RECURSE,       "0"},
138    {"no",       INC_KW_RECURSE,       "h"},
139    {"yes",      INC_KW_SPARSE,        "s"},
140    {"no",       INC_KW_SPARSE,        "0"},
141    {"always",   INC_KW_REPLACE,       "a"},
142    {"ifnewer",  INC_KW_REPLACE,       "w"},
143    {"never",    INC_KW_REPLACE,       "n"},
144    {"yes",      INC_KW_READFIFO,      "r"},
145    {"no",       INC_KW_READFIFO,      "0"},
146    {"yes",      INC_KW_PORTABLE,      "p"},
147    {"no",       INC_KW_PORTABLE,      "0"},
148    {NULL,       0,                   0}
149 };
150
151
152
153 /* 
154  * Scan for Include options (keyword=option) is converted into one or
155  *  two characters. Verifyopts=xxxx is Vxxxx:
156  */
157 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
158 {
159    int token, i;
160    char option[3];
161
162    option[0] = 0;                     /* default option = none */
163    option[2] = 0;                     /* terminate options */
164    token = lex_get_token(lc, T_NAME);             /* expect at least one option */       
165    if (keyword == INC_KW_VERIFY) { /* special case */
166       /* ***FIXME**** ensure these are in permitted set */
167       bstrncat(opts, "V", optlen);         /* indicate Verify */
168       bstrncat(opts, lc->str, optlen);
169       bstrncat(opts, ":", optlen);         /* terminate it */
170
171    /*
172     * Standard keyword options for Include/Exclude 
173     */
174    } else {
175       for (i=0; FS_options[i].name; i++) {
176          if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
177             /* NOTE! maximum 2 letters here or increase option[3] */
178             option[0] = FS_options[i].option[0];
179             option[1] = FS_options[i].option[1];
180             i = 0;
181             break;
182          }
183       }
184       if (i != 0) {
185          scan_err1(lc, "Expected a FileSet option keyword, got:%s:", lc->str);
186       } else { /* add option */
187          bstrncat(opts, option, optlen);
188          Dmsg3(200, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
189       }
190    }
191
192    /* If option terminated by comma, eat it */
193    if (lc->ch == ',') {
194       token = lex_get_token(lc, T_ALL);      /* yes, eat comma */
195    }
196 }
197
198 /* Store FileSet Include/Exclude info */
199 void store_inc(LEX *lc, struct res_items *item, int index, int pass)
200 {
201    int token, i;
202    int options = lc->options;
203    int keyword;
204    char inc_opts[100];
205    int inc_opts_len;
206
207    lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
208    memset(&res_incexe, 0, sizeof(INCEXE));
209
210    /* Get include options */
211    inc_opts[0] = 0;
212    while ((token=lex_get_token(lc, T_ALL)) != T_BOB) {
213       keyword = INC_KW_NONE;
214       for (i=0; FS_option_kw[i].name; i++) {
215          if (strcasecmp(lc->str, FS_option_kw[i].name) == 0) {
216             keyword = FS_option_kw[i].token;
217             break;
218          }
219       }
220       if (keyword == INC_KW_NONE) {
221          scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
222       }
223       /* Option keyword should be following by = <option> */
224       if ((token=lex_get_token(lc, T_ALL)) != T_EQUALS) {
225          scan_err1(lc, _("expected an = following keyword, got: %s"), lc->str);
226       } else {
227          scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
228       }
229       if (token == T_BOB) {
230          break;
231       }
232    }
233    if (!inc_opts[0]) {
234       strcat(inc_opts, "0");          /* set no options */
235    }
236    inc_opts_len = strlen(inc_opts);
237
238    if (pass == 1) {
239       INCEXE *incexe;
240       if (!res_all.res_fs.have_MD5) {
241          MD5Init(&res_all.res_fs.md5c);
242          res_all.res_fs.have_MD5 = TRUE;
243       }
244       setup_current_opts();
245       bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
246       Dmsg1(200, "incexe opts=%s\n", res_incexe.current_opts->opts);
247
248       /* Create incexe structure */
249       Dmsg0(200, "Create INCEXE structure\n");
250       incexe = (INCEXE *)malloc(sizeof(INCEXE));
251       memcpy(incexe, &res_incexe, sizeof(INCEXE));
252       memset(&res_incexe, 0, sizeof(INCEXE));
253       if (item->code == 0) { /* include */
254          if (res_all.res_fs.num_includes == 0) {
255             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
256           } else {
257             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
258                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
259           }
260           res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
261           Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
262       } else {    /* exclude */
263          if (res_all.res_fs.num_excludes == 0) {
264             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
265           } else {
266             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
267                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
268           }
269           res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
270           Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
271       }
272
273       /* Pickup include/exclude names.  They are stored in INCEXE
274        *  structures which contains the options and the name.
275        */
276       while ((token = lex_get_token(lc, T_ALL)) != T_EOB) {
277          switch (token) {
278             case T_COMMA:
279             case T_EOL:
280                continue;
281
282             case T_IDENTIFIER:
283             case T_UNQUOTED_STRING:
284             case T_QUOTED_STRING:
285                if (res_all.res_fs.have_MD5) {
286                   MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
287                }
288                if (incexe->num_names == incexe->max_names) {
289                   incexe->max_names += 10;
290                   if (incexe->name_list == NULL) {
291                      incexe->name_list = (char **)malloc(sizeof(char *) * incexe->max_names);
292                   } else {
293                      incexe->name_list = (char **)realloc(incexe->name_list,
294                            sizeof(char *) * incexe->max_names);
295                   }
296                }
297                incexe->name_list[incexe->num_names++] = bstrdup(lc->str);
298                Dmsg1(200, "Add to name_list %s\n", incexe->name_list[incexe->num_names -1]);
299                break;
300             default:
301                scan_err1(lc, "Expected a filename, got: %s", lc->str);
302          }                                 
303       }
304       /* Note, MD5Final is done in backup.c */
305    } else { /* pass 2 */
306       while (lex_get_token(lc, T_ALL) != T_EOB) 
307          {}
308    }
309    scan_to_eol(lc);
310    lc->options = options;
311    set_bit(index, res_all.hdr.item_present);
312 }
313
314
315 /*
316  * Store FileSet FInclude/FExclude info   
317  *  Note, when this routine is called, we are inside a FileSet
318  *  resource.  We treat the Finclude/Fexeclude like a sort of
319  *  mini-resource within the FileSet resource.
320  */
321 void store_finc(LEX *lc, struct res_items *item, int index, int pass)
322 {
323    int token, i;
324    INCEXE *incexe;
325
326    if (!res_all.res_fs.have_MD5) {
327       MD5Init(&res_all.res_fs.md5c);
328       res_all.res_fs.have_MD5 = TRUE;
329    }
330    res_all.res_fs.finclude = TRUE;
331    token = lex_get_token(lc, T_ALL);            
332    if (token != T_BOB) {
333       scan_err1(lc, _("Expecting a beginning brace, got: %s\n"), lc->str);
334    }
335    memset(&res_incexe, 0, sizeof(INCEXE));
336    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
337       if (token == T_EOL) {
338          continue;
339       }
340       if (token == T_EOB) {
341          break;
342       }
343       if (token != T_IDENTIFIER) {
344          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
345       }
346       for (i=0; finc_items[i].name; i++) {
347          if (strcasecmp(finc_items[i].name, lc->str) == 0) {
348             token = lex_get_token(lc, T_ALL);
349             if (token != T_EQUALS) {
350                scan_err1(lc, "expected an equals, got: %s", lc->str);
351             }
352             /* Call item handler */
353             finc_items[i].handler(lc, &finc_items[i], i, pass);
354             i = -1;
355             break;
356          }
357       }
358       if (i >=0) {
359          scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
360       }
361    }
362    if (pass == 1) {
363       incexe = (INCEXE *)malloc(sizeof(INCEXE));
364       memcpy(incexe, &res_incexe, sizeof(INCEXE));
365       memset(&res_incexe, 0, sizeof(INCEXE));
366       if (item->code == 0) { /* include */
367          if (res_all.res_fs.num_includes == 0) {
368             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
369          } else {
370             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
371                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
372          }
373          res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
374          Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
375       } else {    /* exclude */
376          if (res_all.res_fs.num_excludes == 0) {
377             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
378          } else {
379             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
380                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
381          }
382          res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
383          Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
384       }
385    }
386    scan_to_eol(lc);
387    set_bit(index, res_all.hdr.item_present);
388 }
389
390
391 /* Store Match info */
392 static void store_match(LEX *lc, struct res_items *item, int index, int pass)
393 {
394    int token;
395
396    if (pass == 1) {
397       /* Pickup Match string
398        */
399       token = lex_get_token(lc, T_ALL);            
400       switch (token) {
401       case T_IDENTIFIER:
402       case T_UNQUOTED_STRING:
403       case T_QUOTED_STRING:
404          setup_current_opts();
405          res_incexe.current_opts->match.append(bstrdup(lc->str));
406          break;
407       default:
408          scan_err1(lc, _("Expected a filename, got: %s\n"), lc->str);
409       }                                 
410    } else { /* pass 2 */
411       lex_get_token(lc, T_ALL);          
412    }
413    scan_to_eol(lc);
414 }
415
416 /* Store Base info */
417 static void store_base(LEX *lc, struct res_items *item, int index, int pass)
418 {
419    int token;
420
421    if (pass == 1) {
422       setup_current_opts();
423       /*
424        * Pickup Base Job Name
425        */
426       token = lex_get_token(lc, T_NAME);           
427       res_incexe.current_opts->base_list.append(bstrdup(lc->str));
428    } else { /* pass 2 */
429       lex_get_token(lc, T_ALL);          
430    }
431    scan_to_eol(lc);
432 }
433 /*
434  * Store Filename info. Note, for minor efficiency reasons, we
435  * always increase the name buffer by 10 items because we expect
436  * to add more entries.
437  */
438 static void store_fname(LEX *lc, struct res_items *item, int index, int pass)
439 {
440    int token;
441    INCEXE *incexe;
442
443    if (pass == 1) {
444       /* Pickup Filename string
445        */
446       token = lex_get_token(lc, T_ALL);            
447       switch (token) {
448          case T_IDENTIFIER:
449          case T_UNQUOTED_STRING:
450          case T_QUOTED_STRING:
451             if (res_all.res_fs.have_MD5) {
452                MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
453             }
454             incexe = &res_incexe;
455             if (incexe->num_names == incexe->max_names) {
456                incexe->max_names += 10;
457                if (incexe->name_list == NULL) {
458                   incexe->name_list = (char **)malloc(sizeof(char *) * incexe->max_names);
459                } else {
460                   incexe->name_list = (char **)realloc(incexe->name_list,
461                         sizeof(char *) * incexe->max_names);
462                }
463             }
464             incexe->name_list[incexe->num_names++] = bstrdup(lc->str);
465             Dmsg1(200, "Add to name_list %s\n", incexe->name_list[incexe->num_names -1]);
466             break;
467          default:
468             scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
469       }                                 
470    } else { /* pass 2 */
471       lex_get_token(lc, T_ALL);          
472    }
473    scan_to_eol(lc);
474 }
475
476
477 static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
478 {
479    int i;
480    int keyword;
481    char inc_opts[100];
482
483    inc_opts[0] = 0;
484    keyword = INC_KW_NONE;
485    for (i=0; FS_option_kw[i].name; i++) {
486       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
487          keyword = FS_option_kw[i].token;
488          break;
489       }
490    }
491    if (keyword == INC_KW_NONE) {
492       scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
493    }
494    Dmsg2(200, "keyword=%d %s\n", keyword, FS_option_kw[keyword].name);
495    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
496
497    if (pass == 1) {
498       setup_current_opts();
499       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
500    }
501
502    scan_to_eol(lc);
503 }
504
505
506
507 /* If current_opts not defined, create first entry */
508 static void setup_current_opts(void)
509 {
510    if (res_incexe.current_opts == NULL) {
511       res_incexe.current_opts = (FOPTS *)malloc(sizeof(FOPTS));
512       memset(res_incexe.current_opts, 0, sizeof(FOPTS));
513       res_incexe.current_opts->match.init(1, true);
514       res_incexe.current_opts->base_list.init(1, true);
515       res_incexe.num_opts = 1;
516       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
517       res_incexe.opts_list[0] = res_incexe.current_opts;
518    }
519 }