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