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