]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
ebl Modify disk-changer to check if slot contains something before
[bacula/bacula] / bacula / src / dird / inc_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Configuration file parser for new and old Include and
30  *      Exclude records
31  *
32  *     Kern Sibbald, March MMIII
33  *
34  *     Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39 #ifndef HAVE_REGEX_H
40 #include "lib/bregex.h"
41 #else
42 #include <regex.h>
43 #endif
44
45 /* Forward referenced subroutines */
46
47 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
48
49 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
50 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
51 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
52 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
53 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass);
54 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
55 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass);
56 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass);
57 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
58 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
59 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
60 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
61 static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass);
62 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
63 static void setup_current_opts(void);
64
65
66 /* We build the current resource here as we are
67  * scanning the resource configuration definition,
68  * then move it to allocated memory when the resource
69  * scan is complete.
70  */
71 #if defined(_MSC_VER)
72 extern "C" { // work around visual compiler mangling variables
73    extern URES res_all;
74 }
75 #else
76 extern URES res_all;
77 #endif
78 extern int  res_all_size;
79
80 /* We build the current new Include and Exclude items here */
81 static INCEXE res_incexe;
82
83 /*
84  * new Include/Exclude items
85  *   name             handler     value    code flags default_value
86  */
87 static RES_ITEM newinc_items[] = {
88    {"file",            store_fname,       {0},      0, 0, 0},
89    {"plugin",          store_plugin_name, {0},      0, 0, 0},
90    {"ignoredir",       store_ignoredir,   {0},      0, 0, 0},
91    {"options",         options_res,       {0},      0, 0, 0},
92    {NULL, NULL, {0}, 0, 0, 0}
93 };
94
95 /*
96  * Items that are valid in an Options resource
97  */
98 static RES_ITEM options_items[] = {
99    {"compression",     store_opts,    {0},     0, 0, 0},
100    {"signature",       store_opts,    {0},     0, 0, 0},
101    {"accurate",        store_opts,    {0},     0, 0, 0},
102    {"verify",          store_opts,    {0},     0, 0, 0},
103    {"onefs",           store_opts,    {0},     0, 0, 0},
104    {"recurse",         store_opts,    {0},     0, 0, 0},
105    {"sparse",          store_opts,    {0},     0, 0, 0},
106    {"hardlinks",       store_opts,    {0},     0, 0, 0},
107    {"readfifo",        store_opts,    {0},     0, 0, 0},
108    {"replace",         store_opts,    {0},     0, 0, 0},
109    {"portable",        store_opts,    {0},     0, 0, 0},
110    {"mtimeonly",       store_opts,    {0},     0, 0, 0},
111    {"keepatime",       store_opts,    {0},     0, 0, 0},
112    {"regex",           store_regex,   {0},     0, 0, 0},
113    {"regexdir",        store_regex,   {0},     1, 0, 0},
114    {"regexfile",       store_regex,   {0},     2, 0, 0},
115    {"base",            store_base,    {0},     0, 0, 0},
116    {"wild",            store_wild,    {0},     0, 0, 0},
117    {"wilddir",         store_wild,    {0},     1, 0, 0},
118    {"wildfile",        store_wild,    {0},     2, 0, 0},
119    {"exclude",         store_opts,    {0},     0, 0, 0},
120    {"aclsupport",      store_opts,    {0},     0, 0, 0},
121    {"plugin",          store_plugin,  {0},     0, 0, 0},
122    {"reader",          store_reader,  {0},     0, 0, 0},
123    {"writer",          store_writer,  {0},     0, 0, 0},
124    {"ignorecase",      store_opts,    {0},     0, 0, 0},
125    {"fstype",          store_fstype,  {0},     0, 0, 0},
126    {"hfsplussupport",  store_opts,    {0},     0, 0, 0},
127    {"noatime",         store_opts,    {0},     0, 0, 0},
128    {"enhancedwild",    store_opts,    {0},     0, 0, 0},
129    {"drivetype",       store_drivetype, {0},     0, 0, 0},
130    {"checkfilechanges",store_opts,    {0},     0, 0, 0},
131    {"strippath",       store_opts,    {0},     0, 0, 0},
132    {"honornodumpflag", store_opts,    {0},     0, 0, 0},
133    {NULL, NULL, {0}, 0, 0, 0}
134 };
135
136
137 /* Define FileSet KeyWord values */
138 enum {
139    INC_KW_NONE,
140    INC_KW_COMPRESSION,
141    INC_KW_DIGEST,
142    INC_KW_ENCRYPTION,
143    INC_KW_VERIFY,
144    INC_KW_ACCURATE,
145    INC_KW_ONEFS,
146    INC_KW_RECURSE,
147    INC_KW_SPARSE,
148    INC_KW_HARDLINK,
149    INC_KW_REPLACE,               /* restore options */
150    INC_KW_READFIFO,              /* Causes fifo data to be read */
151    INC_KW_PORTABLE,
152    INC_KW_MTIMEONLY,
153    INC_KW_KEEPATIME,
154    INC_KW_EXCLUDE,
155    INC_KW_ACL,
156    INC_KW_IGNORECASE,
157    INC_KW_HFSPLUS,
158    INC_KW_NOATIME,
159    INC_KW_ENHANCEDWILD,
160    INC_KW_CHKCHANGES,
161    INC_KW_STRIPPATH,
162    INC_KW_HONOR_NODUMP
163 };
164
165 /*
166  * This is the list of options that can be stored by store_opts
167  *   Note, now that the old style Include/Exclude code is gone,
168  *   the INC_KW code could be put into the "code" field of the
169  *   options given above.
170  */
171 static struct s_kw FS_option_kw[] = {
172    {"compression", INC_KW_COMPRESSION},
173    {"signature",   INC_KW_DIGEST},
174    {"encryption",  INC_KW_ENCRYPTION},
175    {"verify",      INC_KW_VERIFY},
176    {"accurate",    INC_KW_ACCURATE},
177    {"onefs",       INC_KW_ONEFS},
178    {"recurse",     INC_KW_RECURSE},
179    {"sparse",      INC_KW_SPARSE},
180    {"hardlinks",   INC_KW_HARDLINK},
181    {"replace",     INC_KW_REPLACE},
182    {"readfifo",    INC_KW_READFIFO},
183    {"portable",    INC_KW_PORTABLE},
184    {"mtimeonly",   INC_KW_MTIMEONLY},
185    {"keepatime",   INC_KW_KEEPATIME},
186    {"exclude",     INC_KW_EXCLUDE},
187    {"aclsupport",  INC_KW_ACL},
188    {"ignorecase",  INC_KW_IGNORECASE},
189    {"hfsplussupport", INC_KW_HFSPLUS},
190    {"noatime",     INC_KW_NOATIME},
191    {"enhancedwild", INC_KW_ENHANCEDWILD},
192    {"checkfilechanges", INC_KW_CHKCHANGES},
193    {"strippath",    INC_KW_STRIPPATH},
194    {"honornodumpflag",    INC_KW_HONOR_NODUMP},
195    {NULL,          0}
196 };
197
198 /* Options for FileSet keywords */
199
200 struct s_fs_opt {
201    const char *name;
202    int keyword;
203    const char *option;
204 };
205
206 /*
207  * Options permitted for each keyword and resulting value.
208  * The output goes into opts, which are then transmitted to
209  * the FD for application as options to the following list of
210  * included files.
211  */
212 static struct s_fs_opt FS_options[] = {
213    {"md5",      INC_KW_DIGEST,        "M"},
214    {"sha1",     INC_KW_DIGEST,        "S"},
215    {"sha256",   INC_KW_DIGEST,       "S2"},
216    {"sha512",   INC_KW_DIGEST,       "S3"},
217    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
218    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
219    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
220    {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
221    {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
222    {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
223    {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
224    {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
225    {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
226    {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
227    {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
228    {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
229    {"yes",      INC_KW_ONEFS,         "0"},
230    {"no",       INC_KW_ONEFS,         "f"},
231    {"yes",      INC_KW_RECURSE,       "0"},
232    {"no",       INC_KW_RECURSE,       "h"},
233    {"yes",      INC_KW_SPARSE,        "s"},
234    {"no",       INC_KW_SPARSE,        "0"},
235    {"yes",      INC_KW_HARDLINK,      "0"},
236    {"no",       INC_KW_HARDLINK,      "H"},
237    {"always",   INC_KW_REPLACE,       "a"},
238    {"ifnewer",  INC_KW_REPLACE,       "w"},
239    {"never",    INC_KW_REPLACE,       "n"},
240    {"yes",      INC_KW_READFIFO,      "r"},
241    {"no",       INC_KW_READFIFO,      "0"},
242    {"yes",      INC_KW_PORTABLE,      "p"},
243    {"no",       INC_KW_PORTABLE,      "0"},
244    {"yes",      INC_KW_MTIMEONLY,     "m"},
245    {"no",       INC_KW_MTIMEONLY,     "0"},
246    {"yes",      INC_KW_KEEPATIME,     "k"},
247    {"no",       INC_KW_KEEPATIME,     "0"},
248    {"yes",      INC_KW_EXCLUDE,       "e"},
249    {"no",       INC_KW_EXCLUDE,       "0"},
250    {"yes",      INC_KW_ACL,           "A"},
251    {"no",       INC_KW_ACL,           "0"},
252    {"yes",      INC_KW_IGNORECASE,    "i"},
253    {"no",       INC_KW_IGNORECASE,    "0"},
254    {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
255    {"no",       INC_KW_HFSPLUS,       "0"},
256    {"yes",      INC_KW_NOATIME,       "K"},
257    {"no",       INC_KW_NOATIME,       "0"},
258    {"yes",      INC_KW_ENHANCEDWILD,  "K"},
259    {"no",       INC_KW_ENHANCEDWILD,  "0"},
260    {"yes",      INC_KW_CHKCHANGES,    "c"},
261    {"no",       INC_KW_CHKCHANGES,    "0"},
262    {"yes",      INC_KW_HONOR_NODUMP,  "N"},
263    {"no",       INC_KW_HONOR_NODUMP,  "0"},
264    {NULL,       0,                      0}
265 };
266
267
268
269 /*
270  * Scan for right hand side of Include options (keyword=option) is
271  *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
272  *    Whatever is found is concatenated to the opts string.
273  * This code is also used inside an Options resource.
274  */
275 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
276 {
277    int token, i;
278    char option[3];
279    int lcopts = lc->options;
280
281    option[0] = 0;                     /* default option = none */
282    option[2] = 0;                     /* terminate options */
283    lc->options |= LOPT_STRING;        /* force string */
284    token = lex_get_token(lc, T_STRING);          /* expect at least one option */
285    if (keyword == INC_KW_VERIFY) { /* special case */
286       /* ***FIXME**** ensure these are in permitted set */
287       bstrncat(opts, "V", optlen);         /* indicate Verify */
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_ACCURATE) { /* special case */
292       /* ***FIXME**** ensure these are in permitted set */
293       bstrncat(opts, "C", optlen);         /* indicate Accurate */
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       token = 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 FInclude/FExclude 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);
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    int token;
482
483    token = lex_get_token(lc, T_NAME);
484    if (pass == 1) {
485       /*
486        * Pickup Base Job Name
487        */
488       res_incexe.current_opts->base.append(bstrdup(lc->str));
489    }
490    scan_to_eol(lc);
491 }
492
493 /* Store reader info */
494 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
495 {
496    int token;
497
498    token = lex_get_token(lc, T_NAME);
499    if (pass == 1) {
500       /*
501        * Pickup plugin command
502        */
503       res_incexe.current_opts->plugin = bstrdup(lc->str);
504    }
505    scan_to_eol(lc);
506 }
507
508
509 /* Store reader info */
510 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
511 {
512    int token;
513
514    token = lex_get_token(lc, T_NAME);
515    if (pass == 1) {
516       /*
517        * Pickup reader command
518        */
519       res_incexe.current_opts->reader = bstrdup(lc->str);
520    }
521    scan_to_eol(lc);
522 }
523
524 /* Store writer innfo */
525 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
526 {
527    int token;
528
529    token = lex_get_token(lc, T_NAME);
530    if (pass == 1) {
531       /*
532        * Pickup writer command
533        */
534       res_incexe.current_opts->writer = bstrdup(lc->str);
535    }
536    scan_to_eol(lc);
537 }
538
539
540
541 /* Store Wild-card info */
542 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
543 {
544    int token;
545    const char *type;
546    int newsize;
547
548    token = lex_get_token(lc, T_SKIP_EOL);
549    if (pass == 1) {
550       /*
551        * Pickup Wild-card string
552        */
553       switch (token) {
554       case T_IDENTIFIER:
555       case T_UNQUOTED_STRING:
556       case T_QUOTED_STRING:
557          if (item->code == 1) {
558             type = "wilddir";
559             res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
560             newsize = res_incexe.current_opts->wilddir.size();
561          } else if (item->code == 2) {
562             if (strpbrk(lc->str, "/\\") != NULL) {
563                type = "wildfile";
564                res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
565                newsize = res_incexe.current_opts->wildfile.size();
566             } else {
567                type = "wildbase";
568                res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
569                newsize = res_incexe.current_opts->wildbase.size();
570             }
571          } else {
572             type = "wild";
573             res_incexe.current_opts->wild.append(bstrdup(lc->str));
574             newsize = res_incexe.current_opts->wild.size();
575          }
576          Dmsg4(9, "set %s %p size=%d %s\n",
577             type, res_incexe.current_opts, newsize, lc->str);
578          break;
579       default:
580          scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
581       }
582    }
583    scan_to_eol(lc);
584 }
585
586 /* Store fstype info */
587 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
588 {
589    int token;
590
591    token = lex_get_token(lc, T_SKIP_EOL);
592    if (pass == 1) {
593       /* Pickup fstype string */
594       switch (token) {
595       case T_IDENTIFIER:
596       case T_UNQUOTED_STRING:
597       case T_QUOTED_STRING:
598          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
599          Dmsg3(900, "set fstype %p size=%d %s\n",
600             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
601          break;
602       default:
603          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
604       }
605    }
606    scan_to_eol(lc);
607 }
608
609 /* Store ignoredir info */
610 static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass)
611 {
612    int token;
613
614    token = lex_get_token(lc, T_NAME);
615    if (pass == 1) {
616       /*
617        * Pickup reader command
618        */
619       res_incexe.current_opts->ignoredir = bstrdup(lc->str);
620    }
621    scan_to_eol(lc);
622 }
623
624 /* Store drivetype info */
625 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
626 {
627    int token;
628
629    token = lex_get_token(lc, T_SKIP_EOL);
630    if (pass == 1) {
631       /* Pickup drivetype string */
632       switch (token) {
633       case T_IDENTIFIER:
634       case T_UNQUOTED_STRING:
635       case T_QUOTED_STRING:
636          res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
637          Dmsg3(900, "set drivetype %p size=%d %s\n",
638             res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
639          break;
640       default:
641          scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
642       }
643    }
644    scan_to_eol(lc);
645 }
646
647 /*
648  * Store Filename info. Note, for minor efficiency reasons, we
649  * always increase the name buffer by 10 items because we expect
650  * to add more entries.
651  */
652 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
653 {
654    int token;
655    INCEXE *incexe;
656
657    token = lex_get_token(lc, T_SKIP_EOL);
658    if (pass == 1) {
659       /* Pickup Filename string
660        */
661       switch (token) {
662       case T_IDENTIFIER:
663       case T_UNQUOTED_STRING:
664          if (strchr(lc->str, '\\')) {
665             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
666             /* NOT REACHED */
667          }
668       case T_QUOTED_STRING:
669          if (res_all.res_fs.have_MD5) {
670             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
671          }
672          incexe = &res_incexe;
673          if (incexe->name_list.size() == 0) {
674             incexe->name_list.init(10, true);
675          }
676          incexe->name_list.append(bstrdup(lc->str));
677          Dmsg1(900, "Add to name_list %s\n", lc->str);
678          break;
679       default:
680          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
681       }
682    }
683    scan_to_eol(lc);
684 }
685
686 /*
687  * Store Filename info. Note, for minor efficiency reasons, we
688  * always increase the name buffer by 10 items because we expect
689  * to add more entries.
690  */
691 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass)
692 {
693    int token;
694    INCEXE *incexe;
695
696    token = lex_get_token(lc, T_SKIP_EOL);
697    if (pass == 1) {
698       /* Pickup Filename string
699        */
700       switch (token) {
701       case T_IDENTIFIER:
702       case T_UNQUOTED_STRING:
703          if (strchr(lc->str, '\\')) {
704             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
705             /* NOT REACHED */
706          }
707       case T_QUOTED_STRING:
708          if (res_all.res_fs.have_MD5) {
709             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
710          }
711          incexe = &res_incexe;
712          if (incexe->plugin_list.size() == 0) {
713             incexe->plugin_list.init(10, true);
714          }
715          incexe->plugin_list.append(bstrdup(lc->str));
716          Dmsg1(900, "Add to plugin_list %s\n", lc->str);
717          break;
718       default:
719          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
720       }
721    }
722    scan_to_eol(lc);
723 }
724
725
726
727 /*
728  * Come here when Options seen in Include/Exclude
729  */
730 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
731 {
732    int token, i;
733
734    token = lex_get_token(lc, T_SKIP_EOL);
735    if (token != T_BOB) {
736       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
737    }
738
739    if (pass == 1) {
740       setup_current_opts();
741    }
742
743    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
744       if (token == T_EOL) {
745          continue;
746       }
747       if (token == T_EOB) {
748          break;
749       }
750       if (token != T_IDENTIFIER) {
751          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
752       }
753       for (i=0; options_items[i].name; i++) {
754          if (strcasecmp(options_items[i].name, lc->str) == 0) {
755             token = lex_get_token(lc, T_SKIP_EOL);
756             if (token != T_EQUALS) {
757                scan_err1(lc, _("expected an equals, got: %s"), lc->str);
758             }
759             /* Call item handler */
760             options_items[i].handler(lc, &options_items[i], i, pass);
761             i = -1;
762             break;
763          }
764       }
765       if (i >=0) {
766          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
767       }
768    }
769 }
770
771
772 /*
773  * New style options come here
774  */
775 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
776 {
777    int i;
778    int keyword;
779    char inc_opts[100];
780
781    inc_opts[0] = 0;
782    keyword = INC_KW_NONE;
783    /* Look up the keyword */
784    for (i=0; FS_option_kw[i].name; i++) {
785       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
786          keyword = FS_option_kw[i].token;
787          break;
788       }
789    }
790    if (keyword == INC_KW_NONE) {
791       scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
792    }
793    /* Now scan for the value */
794    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
795    if (pass == 1) {
796       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
797       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
798    }
799    scan_to_eol(lc);
800 }
801
802
803
804 /* If current_opts not defined, create first entry */
805 static void setup_current_opts(void)
806 {
807    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
808    memset(fo, 0, sizeof(FOPTS));
809    fo->regex.init(1, true);
810    fo->regexdir.init(1, true);
811    fo->regexfile.init(1, true);
812    fo->wild.init(1, true);
813    fo->wilddir.init(1, true);
814    fo->wildfile.init(1, true);
815    fo->wildbase.init(1, true);
816    fo->base.init(1, true);
817    fo->fstype.init(1, true);
818    fo->drivetype.init(1, true);
819    res_incexe.current_opts = fo;
820    if (res_incexe.num_opts == 0) {
821       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
822    } else {
823       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
824                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
825    }
826    res_incexe.opts_list[res_incexe.num_opts++] = fo;
827 }