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