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