]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
Backport from BEE
[bacula/bacula] / bacula / src / dird / inc_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *   Configuration file parser for new and old Include and
18  *      Exclude records
19  *
20  *     Written by Kern Sibbald, March MMIII
21  *
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26 #ifndef HAVE_REGEX_H
27 #include "lib/bregex.h"
28 #else
29 #include <regex.h>
30 #endif
31
32 /* Forward referenced subroutines */
33
34 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
35
36 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
37 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
38 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
39 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
40 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass);
41 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
42 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
43 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
44 static void setup_current_opts(void);
45
46 /* Include and Exclude items */
47 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
48 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
49 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
50 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
51
52
53 /* We build the current resource here as we are
54  * scanning the resource configuration definition,
55  * then move it to allocated memory when the resource
56  * scan is complete.
57  */
58 #if defined(_MSC_VER)
59 extern "C" { // work around visual compiler mangling variables
60    extern URES res_all;
61 }
62 #else
63 extern URES res_all;
64 #endif
65 extern int32_t  res_all_size;
66
67 /* We build the current new Include and Exclude items here */
68 static INCEXE res_incexe;
69
70 /*
71  * new Include/Exclude items
72  *   name             handler     value    code flags default_value
73  */
74 static RES_ITEM2 newinc_items[] = {
75    {"file",            store_fname,       {0},      0, 0, 0},
76    {"plugin",          store_plugin_name, {0},      0, 0, 0},
77    {"excludedircontaining", store_excludedir,  {0}, 0, 0, 0},
78    {"options",         options_res,       {0},      0, 0, 0},
79    {NULL, NULL, {0}, 0, 0, 0}
80 };
81
82 /*
83  * Items that are valid in an Options resource
84  */
85 static RES_ITEM options_items[] = {
86    {"compression",     store_opts,    {0},     0, 0, 0},
87    {"signature",       store_opts,    {0},     0, 0, 0},
88    {"basejob",         store_opts,    {0},     0, 0, 0},
89    {"accurate",        store_opts,    {0},     0, 0, 0},
90    {"verify",          store_opts,    {0},     0, 0, 0},
91    {"onefs",           store_opts,    {0},     0, 0, 0},
92    {"recurse",         store_opts,    {0},     0, 0, 0},
93    {"sparse",          store_opts,    {0},     0, 0, 0},
94    {"hardlinks",       store_opts,    {0},     0, 0, 0},
95    {"readfifo",        store_opts,    {0},     0, 0, 0},
96    {"replace",         store_opts,    {0},     0, 0, 0},
97    {"portable",        store_opts,    {0},     0, 0, 0},
98    {"mtimeonly",       store_opts,    {0},     0, 0, 0},
99    {"keepatime",       store_opts,    {0},     0, 0, 0},
100    {"regex",           store_regex,   {0},     0, 0, 0},
101    {"regexdir",        store_regex,   {0},     1, 0, 0},
102    {"regexfile",       store_regex,   {0},     2, 0, 0},
103    {"base",            store_base,    {0},     0, 0, 0},
104    {"wild",            store_wild,    {0},     0, 0, 0},
105    {"wilddir",         store_wild,    {0},     1, 0, 0},
106    {"wildfile",        store_wild,    {0},     2, 0, 0},
107    {"exclude",         store_opts,    {0},     0, 0, 0},
108    {"aclsupport",      store_opts,    {0},     0, 0, 0},
109    {"plugin",          store_plugin,  {0},     0, 0, 0},
110    {"ignorecase",      store_opts,    {0},     0, 0, 0},
111    {"fstype",          store_fstype,  {0},     0, 0, 0},
112    {"hfsplussupport",  store_opts,    {0},     0, 0, 0},
113    {"noatime",         store_opts,    {0},     0, 0, 0},
114    {"enhancedwild",    store_opts,    {0},     0, 0, 0},
115    {"drivetype",       store_drivetype, {0},   0, 0, 0},
116    {"checkfilechanges",store_opts,    {0},     0, 0, 1},
117    {"strippath",       store_opts,    {0},     0, 0, 0},
118    {"honornodumpflag", store_opts,    {0},     0, 0, 0},
119    {"xattrsupport",    store_opts,    {0},     0, 0, 0},
120    {NULL, NULL, {0}, 0, 0, 0}
121 };
122
123
124 /* Define FileSet KeyWord values */
125 enum {
126    INC_KW_NONE,
127    INC_KW_COMPRESSION,
128    INC_KW_DIGEST,
129    INC_KW_ENCRYPTION,
130    INC_KW_VERIFY,
131    INC_KW_BASEJOB,
132    INC_KW_ACCURATE,
133    INC_KW_ONEFS,
134    INC_KW_RECURSE,
135    INC_KW_SPARSE,
136    INC_KW_HARDLINK,
137    INC_KW_REPLACE,               /* restore options */
138    INC_KW_READFIFO,              /* Causes fifo data to be read */
139    INC_KW_PORTABLE,
140    INC_KW_MTIMEONLY,
141    INC_KW_KEEPATIME,
142    INC_KW_EXCLUDE,
143    INC_KW_ACL,
144    INC_KW_IGNORECASE,
145    INC_KW_HFSPLUS,
146    INC_KW_NOATIME,
147    INC_KW_ENHANCEDWILD,
148    INC_KW_CHKCHANGES,
149    INC_KW_STRIPPATH,
150    INC_KW_HONOR_NODUMP,
151    INC_KW_XATTR
152 };
153
154 /*
155  * This is the list of options that can be stored by store_opts
156  *   Note, now that the old style Include/Exclude code is gone,
157  *   the INC_KW code could be put into the "code" field of the
158  *   options given above.
159  */
160 static struct s_kw FS_option_kw[] = {
161    {"compression", INC_KW_COMPRESSION},
162    {"signature",   INC_KW_DIGEST},
163    {"encryption",  INC_KW_ENCRYPTION},
164    {"verify",      INC_KW_VERIFY},
165    {"basejob",     INC_KW_BASEJOB},
166    {"accurate",    INC_KW_ACCURATE},
167    {"onefs",       INC_KW_ONEFS},
168    {"recurse",     INC_KW_RECURSE},
169    {"sparse",      INC_KW_SPARSE},
170    {"hardlinks",   INC_KW_HARDLINK},
171    {"replace",     INC_KW_REPLACE},
172    {"readfifo",    INC_KW_READFIFO},
173    {"portable",    INC_KW_PORTABLE},
174    {"mtimeonly",   INC_KW_MTIMEONLY},
175    {"keepatime",   INC_KW_KEEPATIME},
176    {"exclude",     INC_KW_EXCLUDE},
177    {"aclsupport",  INC_KW_ACL},
178    {"ignorecase",  INC_KW_IGNORECASE},
179    {"hfsplussupport", INC_KW_HFSPLUS},
180    {"noatime",     INC_KW_NOATIME},
181    {"enhancedwild", INC_KW_ENHANCEDWILD},
182    {"checkfilechanges", INC_KW_CHKCHANGES},
183    {"strippath",   INC_KW_STRIPPATH},
184    {"honornodumpflag", INC_KW_HONOR_NODUMP},
185    {"xattrsupport", INC_KW_XATTR},
186    {NULL,          0}
187 };
188
189 /* Options for FileSet keywords */
190
191 struct s_fs_opt {
192    const char *name;
193    int keyword;
194    const char *option;
195 };
196
197 /*
198  * Options permitted for each keyword and resulting value.
199  * The output goes into opts, which are then transmitted to
200  * the FD for application as options to the following list of
201  * included files.
202  */
203 static struct s_fs_opt FS_options[] = {
204    {"md5",      INC_KW_DIGEST,        "M"},
205    {"sha1",     INC_KW_DIGEST,        "S"},
206    {"sha256",   INC_KW_DIGEST,       "S2"},
207    {"sha512",   INC_KW_DIGEST,       "S3"},
208    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
209    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
210    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
211    {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
212    {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
213    {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
214    {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
215    {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
216    {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
217    {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
218    {"lzo",      INC_KW_COMPRESSION,  "Zo"},
219    {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
220    {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
221    {"yes",      INC_KW_ONEFS,         "0"},
222    {"no",       INC_KW_ONEFS,         "f"},
223    {"yes",      INC_KW_RECURSE,       "0"},
224    {"no",       INC_KW_RECURSE,       "h"},
225    {"yes",      INC_KW_SPARSE,        "s"},
226    {"no",       INC_KW_SPARSE,        "0"},
227    {"yes",      INC_KW_HARDLINK,      "0"},
228    {"no",       INC_KW_HARDLINK,      "H"},
229    {"always",   INC_KW_REPLACE,       "a"},
230    {"ifnewer",  INC_KW_REPLACE,       "w"},
231    {"never",    INC_KW_REPLACE,       "n"},
232    {"yes",      INC_KW_READFIFO,      "r"},
233    {"no",       INC_KW_READFIFO,      "0"},
234    {"yes",      INC_KW_PORTABLE,      "p"},
235    {"no",       INC_KW_PORTABLE,      "0"},
236    {"yes",      INC_KW_MTIMEONLY,     "m"},
237    {"no",       INC_KW_MTIMEONLY,     "0"},
238    {"yes",      INC_KW_KEEPATIME,     "k"},
239    {"no",       INC_KW_KEEPATIME,     "0"},
240    {"yes",      INC_KW_EXCLUDE,       "e"},
241    {"no",       INC_KW_EXCLUDE,       "0"},
242    {"yes",      INC_KW_ACL,           "A"},
243    {"no",       INC_KW_ACL,           "0"},
244    {"yes",      INC_KW_IGNORECASE,    "i"},
245    {"no",       INC_KW_IGNORECASE,    "0"},
246    {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
247    {"no",       INC_KW_HFSPLUS,       "0"},
248    {"yes",      INC_KW_NOATIME,       "K"},
249    {"no",       INC_KW_NOATIME,       "0"},
250    {"yes",      INC_KW_ENHANCEDWILD,  "K"},
251    {"no",       INC_KW_ENHANCEDWILD,  "0"},
252    {"yes",      INC_KW_CHKCHANGES,    "c"},
253    {"no",       INC_KW_CHKCHANGES,    "0"},
254    {"yes",      INC_KW_HONOR_NODUMP,  "N"},
255    {"no",       INC_KW_HONOR_NODUMP,  "0"},
256    {"yes",      INC_KW_XATTR,         "X"},
257    {"no",       INC_KW_XATTR,         "0"},
258    {NULL,       0,                      0}
259 };
260
261
262
263 /*
264  * Scan for right hand side of Include options (keyword=option) is
265  *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
266  *    Whatever is found is concatenated to the opts string.
267  * This code is also used inside an Options resource.
268  */
269 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
270 {
271    int i;
272    char option[3];
273    int lcopts = lc->options;
274
275    option[0] = 0;                     /* default option = none */
276    option[2] = 0;                     /* terminate options */
277    lc->options |= LOPT_STRING;        /* force string */
278    lex_get_token(lc, T_STRING);       /* expect at least one option */
279    if (keyword == INC_KW_VERIFY) { /* special case */
280       /* ***FIXME**** ensure these are in permitted set */
281       bstrncat(opts, "V", optlen);         /* indicate Verify */
282       bstrncat(opts, lc->str, optlen);
283       bstrncat(opts, ":", optlen);         /* terminate it */
284       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
285    } else if (keyword == INC_KW_ACCURATE) { /* special case */
286       /* ***FIXME**** ensure these are in permitted set */
287       bstrncat(opts, "C", optlen);         /* indicate Accurate */
288       bstrncat(opts, lc->str, optlen);
289       bstrncat(opts, ":", optlen);         /* terminate it */
290       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
291    } else if (keyword == INC_KW_BASEJOB) { /* special case */
292       /* ***FIXME**** ensure these are in permitted set */
293       bstrncat(opts, "J", optlen);         /* indicate BaseJob */
294       bstrncat(opts, lc->str, optlen);
295       bstrncat(opts, ":", optlen);         /* terminate it */
296       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
297    } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
298       if (!is_an_integer(lc->str)) {
299          scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
300       }
301       bstrncat(opts, "P", optlen);         /* indicate strip path */
302       bstrncat(opts, lc->str, optlen);
303       bstrncat(opts, ":", optlen);         /* terminate it */
304       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
305    /*
306     * Standard keyword options for Include/Exclude
307     */
308    } else {
309       for (i=0; FS_options[i].name; i++) {
310          if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
311             /* NOTE! maximum 2 letters here or increase option[3] */
312             option[0] = FS_options[i].option[0];
313             option[1] = FS_options[i].option[1];
314             i = 0;
315             break;
316          }
317       }
318       if (i != 0) {
319          scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
320       } else { /* add option */
321          bstrncat(opts, option, optlen);
322          Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
323       }
324    }
325    lc->options = lcopts;
326
327    /* If option terminated by comma, eat it */
328    if (lc->ch == ',') {
329       lex_get_token(lc, T_ALL);      /* yes, eat comma */
330    }
331 }
332
333 /*
334  *
335  * Store FileSet Include/Exclude info
336  *  new style includes are handled in store_newinc()
337  */
338 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
339 {
340    int token;
341
342    /*
343     * Decide if we are doing a new Include or an old include. The
344     *  new Include is followed immediately by open brace, whereas the
345     *  old include has options following the Include.
346     */
347    token = lex_get_token(lc, T_SKIP_EOL);
348    if (token == T_BOB) {
349       store_newinc(lc, item, index, pass);
350       return;
351    }
352    scan_err0(lc, _("Old style Include/Exclude not supported\n"));
353 }
354
355
356 /*
357  * Store new style FileSet Include/Exclude info
358  *
359  *  Note, when this routine is called, we are inside a FileSet
360  *  resource.  We treat the Include/Execlude like a sort of
361  *  mini-resource within the FileSet resource.
362  */
363 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
364 {
365    int token, i;
366    INCEXE *incexe;
367    bool options;
368
369    if (!res_all.res_fs.have_MD5) {
370       MD5Init(&res_all.res_fs.md5c);
371       res_all.res_fs.have_MD5 = true;
372    }
373    memset(&res_incexe, 0, sizeof(INCEXE));
374    res_all.res_fs.new_include = true;
375    while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
376       if (token == T_EOB) {
377          break;
378       }
379       if (token != T_IDENTIFIER) {
380          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
381       }
382       for (i=0; newinc_items[i].name; i++) {
383          options = strcasecmp(lc->str, "options") == 0;
384          if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
385             if (!options) {
386                token = lex_get_token(lc, T_SKIP_EOL);
387                if (token != T_EQUALS) {
388                   scan_err1(lc, _("expected an equals, got: %s"), lc->str);
389                }
390             }
391             /* Call item handler */
392             newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
393             i = -1;
394             break;
395          }
396       }
397       if (i >=0) {
398          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
399       }
400    }
401    if (pass == 1) {
402       incexe = (INCEXE *)malloc(sizeof(INCEXE));
403       memcpy(incexe, &res_incexe, sizeof(INCEXE));
404       memset(&res_incexe, 0, sizeof(INCEXE));
405       if (item->code == 0) { /* include */
406          if (res_all.res_fs.num_includes == 0) {
407             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
408          } else {
409             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
410                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
411          }
412          res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
413          Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
414       } else {    /* exclude */
415          if (res_all.res_fs.num_excludes == 0) {
416             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
417          } else {
418             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
419                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
420          }
421          res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
422          Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
423       }
424    }
425    scan_to_eol(lc);
426    set_bit(index, res_all.hdr.item_present);
427 }
428
429
430 /* Store regex info */
431 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
432 {
433    int token, rc;
434    regex_t preg;
435    char prbuf[500];
436    const char *type;
437    int newsize;
438
439    token = lex_get_token(lc, T_SKIP_EOL);
440    if (pass == 1) {
441       /* Pickup regex string
442        */
443       switch (token) {
444       case T_IDENTIFIER:
445       case T_UNQUOTED_STRING:
446       case T_QUOTED_STRING:
447          rc = regcomp(&preg, lc->str, REG_EXTENDED);
448          if (rc != 0) {
449             regerror(rc, &preg, prbuf, sizeof(prbuf));
450             regfree(&preg);
451             scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
452             break;
453          }
454          regfree(&preg);
455          if (item->code == 1) {
456             type = "regexdir";
457             res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
458             newsize = res_incexe.current_opts->regexdir.size();
459          } else if (item->code == 2) {
460             type = "regexfile";
461             res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
462             newsize = res_incexe.current_opts->regexfile.size();
463          } else {
464             type = "regex";
465             res_incexe.current_opts->regex.append(bstrdup(lc->str));
466             newsize = res_incexe.current_opts->regex.size();
467          }
468          Dmsg4(900, "set %s %p size=%d %s\n",
469             type, res_incexe.current_opts, newsize, lc->str);
470          break;
471       default:
472          scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
473       }
474    }
475    scan_to_eol(lc);
476 }
477
478 /* Store Base info */
479 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
480 {
481
482    lex_get_token(lc, T_NAME);
483    if (pass == 1) {
484       /*
485        * Pickup Base Job Name
486        */
487       res_incexe.current_opts->base.append(bstrdup(lc->str));
488    }
489    scan_to_eol(lc);
490 }
491
492 /* Store reader info */
493 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
494 {
495
496    lex_get_token(lc, T_NAME);
497    if (pass == 1) {
498       /*
499        * Pickup plugin command
500        */
501       res_incexe.current_opts->plugin = bstrdup(lc->str);
502    }
503    scan_to_eol(lc);
504 }
505
506
507 /* Store Wild-card info */
508 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
509 {
510    int token;
511    const char *type;
512    int newsize;
513
514    token = lex_get_token(lc, T_SKIP_EOL);
515    if (pass == 1) {
516       /*
517        * Pickup Wild-card string
518        */
519       switch (token) {
520       case T_IDENTIFIER:
521       case T_UNQUOTED_STRING:
522       case T_QUOTED_STRING:
523          if (item->code == 1) {
524             type = "wilddir";
525             res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
526             newsize = res_incexe.current_opts->wilddir.size();
527          } else if (item->code == 2) {
528             if (strpbrk(lc->str, "/\\") != NULL) {
529                type = "wildfile";
530                res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
531                newsize = res_incexe.current_opts->wildfile.size();
532             } else {
533                type = "wildbase";
534                res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
535                newsize = res_incexe.current_opts->wildbase.size();
536             }
537          } else {
538             type = "wild";
539             res_incexe.current_opts->wild.append(bstrdup(lc->str));
540             newsize = res_incexe.current_opts->wild.size();
541          }
542          Dmsg4(9, "set %s %p size=%d %s\n",
543             type, res_incexe.current_opts, newsize, lc->str);
544          break;
545       default:
546          scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
547       }
548    }
549    scan_to_eol(lc);
550 }
551
552 /* Store fstype info */
553 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
554 {
555    int token;
556
557    token = lex_get_token(lc, T_SKIP_EOL);
558    if (pass == 1) {
559       /* Pickup fstype string */
560       switch (token) {
561       case T_IDENTIFIER:
562       case T_UNQUOTED_STRING:
563       case T_QUOTED_STRING:
564          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
565          Dmsg3(900, "set fstype %p size=%d %s\n",
566             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
567          break;
568       default:
569          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
570       }
571    }
572    scan_to_eol(lc);
573 }
574
575 /* Store exclude directory containing  info */
576 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
577 {
578
579    if (exclude) {
580       scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
581       /* NOT REACHED */
582    }
583    lex_get_token(lc, T_NAME);
584    if (pass == 1) {
585       res_incexe.ignoredir = bstrdup(lc->str);
586    }
587    scan_to_eol(lc);
588 }
589
590 /* Store drivetype info */
591 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
592 {
593    int token;
594
595    token = lex_get_token(lc, T_SKIP_EOL);
596    if (pass == 1) {
597       /* Pickup drivetype string */
598       switch (token) {
599       case T_IDENTIFIER:
600       case T_UNQUOTED_STRING:
601       case T_QUOTED_STRING:
602          res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
603          Dmsg3(900, "set drivetype %p size=%d %s\n",
604             res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
605          break;
606       default:
607          scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
608       }
609    }
610    scan_to_eol(lc);
611 }
612
613 /*
614  * Store Filename info. Note, for minor efficiency reasons, we
615  * always increase the name buffer by 10 items because we expect
616  * to add more entries.
617  */
618 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
619 {
620    int token;
621    INCEXE *incexe;
622
623    token = lex_get_token(lc, T_SKIP_EOL);
624    if (pass == 1) {
625       /* Pickup Filename string
626        */
627       switch (token) {
628       case T_IDENTIFIER:
629       case T_UNQUOTED_STRING:
630          if (strchr(lc->str, '\\')) {
631             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
632             /* NOT REACHED */
633          }
634       case T_QUOTED_STRING:
635          if (res_all.res_fs.have_MD5) {
636             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
637          }
638          incexe = &res_incexe;
639          if (incexe->name_list.size() == 0) {
640             incexe->name_list.init(10, true);
641          }
642          incexe->name_list.append(bstrdup(lc->str));
643          Dmsg1(900, "Add to name_list %s\n", lc->str);
644          break;
645       default:
646          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
647       }
648    }
649    scan_to_eol(lc);
650 }
651
652 /*
653  * Store Filename info. Note, for minor efficiency reasons, we
654  * always increase the name buffer by 10 items because we expect
655  * to add more entries.
656  */
657 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
658 {
659    int token;
660    INCEXE *incexe;
661
662    if (exclude) {
663       scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
664       /* NOT REACHED */
665    }
666    token = lex_get_token(lc, T_SKIP_EOL);
667    if (pass == 1) {
668       /* Pickup Filename string
669        */
670       switch (token) {
671       case T_IDENTIFIER:
672       case T_UNQUOTED_STRING:
673          if (strchr(lc->str, '\\')) {
674             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
675             /* NOT REACHED */
676          }
677       case T_QUOTED_STRING:
678          if (res_all.res_fs.have_MD5) {
679             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
680          }
681          incexe = &res_incexe;
682          if (incexe->plugin_list.size() == 0) {
683             incexe->plugin_list.init(10, true);
684          }
685          incexe->plugin_list.append(bstrdup(lc->str));
686          Dmsg1(900, "Add to plugin_list %s\n", lc->str);
687          break;
688       default:
689          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
690          /* NOT REACHED */
691       }
692    }
693    scan_to_eol(lc);
694 }
695
696
697
698 /*
699  * Come here when Options seen in Include/Exclude
700  */
701 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
702 {
703    int token, i;
704
705    if (exclude) {
706       scan_err0(lc, _("Options section not permitted in Exclude\n"));
707       /* NOT REACHED */
708    }
709    token = lex_get_token(lc, T_SKIP_EOL);
710    if (token != T_BOB) {
711       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
712    }
713
714    if (pass == 1) {
715       setup_current_opts();
716    }
717
718    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
719       if (token == T_EOL) {
720          continue;
721       }
722       if (token == T_EOB) {
723          break;
724       }
725       if (token != T_IDENTIFIER) {
726          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
727       }
728       for (i=0; options_items[i].name; i++) {
729          if (strcasecmp(options_items[i].name, lc->str) == 0) {
730             token = lex_get_token(lc, T_SKIP_EOL);
731             if (token != T_EQUALS) {
732                scan_err1(lc, _("expected an equals, got: %s"), lc->str);
733             }
734             /* Call item handler */
735             options_items[i].handler(lc, &options_items[i], i, pass);
736             i = -1;
737             break;
738          }
739       }
740       if (i >=0) {
741          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
742       }
743    }
744 }
745
746
747 /*
748  * New style options come here
749  */
750 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
751 {
752    int i;
753    int keyword;
754    char inc_opts[100];
755
756    inc_opts[0] = 0;
757    keyword = INC_KW_NONE;
758    /* Look up the keyword */
759    for (i=0; FS_option_kw[i].name; i++) {
760       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
761          keyword = FS_option_kw[i].token;
762          break;
763       }
764    }
765    if (keyword == INC_KW_NONE) {
766       scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
767    }
768    /* Now scan for the value */
769    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
770    if (pass == 1) {
771       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
772       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
773    }
774    scan_to_eol(lc);
775 }
776
777
778
779 /* If current_opts not defined, create first entry */
780 static void setup_current_opts(void)
781 {
782    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
783    memset(fo, 0, sizeof(FOPTS));
784    fo->regex.init(1, true);
785    fo->regexdir.init(1, true);
786    fo->regexfile.init(1, true);
787    fo->wild.init(1, true);
788    fo->wilddir.init(1, true);
789    fo->wildfile.init(1, true);
790    fo->wildbase.init(1, true);
791    fo->base.init(1, true);
792    fo->fstype.init(1, true);
793    fo->drivetype.init(1, true);
794    res_incexe.current_opts = fo;
795    if (res_incexe.num_opts == 0) {
796       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
797    } else {
798       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
799                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
800    }
801    res_incexe.opts_list[res_incexe.num_opts++] = fo;
802 }