]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
ebl use RegexWhere instead of where_use_regexp in job conf
[bacula/bacula] / bacula / src / dird / inc_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 plus additions
11    that are listed 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 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    {"checkfilechanges",store_opts,    {0},     0, 0, 0},
124    {NULL, NULL, {0}, 0, 0, 0}
125 };
126
127
128 /* Define FileSet KeyWord values */
129 enum {
130    INC_KW_NONE,
131    INC_KW_COMPRESSION,
132    INC_KW_DIGEST,
133    INC_KW_ENCRYPTION,
134    INC_KW_VERIFY,
135    INC_KW_ONEFS,
136    INC_KW_RECURSE,
137    INC_KW_SPARSE,
138    INC_KW_HARDLINK,
139    INC_KW_REPLACE,               /* restore options */
140    INC_KW_READFIFO,              /* Causes fifo data to be read */
141    INC_KW_PORTABLE,
142    INC_KW_MTIMEONLY,
143    INC_KW_KEEPATIME,
144    INC_KW_EXCLUDE,
145    INC_KW_ACL,
146    INC_KW_IGNORECASE,
147    INC_KW_HFSPLUS,
148    INC_KW_NOATIME,
149    INC_KW_ENHANCEDWILD,
150    INC_KW_CHKCHANGES
151 };
152
153 /*
154  * This is the list of options that can be stored by store_opts
155  *   Note, now that the old style Include/Exclude code is gone,
156  *   the INC_KW code could be put into the "code" field of the
157  *   options given above.
158  */
159 static struct s_kw FS_option_kw[] = {
160    {"compression", INC_KW_COMPRESSION},
161    {"signature",   INC_KW_DIGEST},
162    {"encryption",  INC_KW_ENCRYPTION},
163    {"verify",      INC_KW_VERIFY},
164    {"onefs",       INC_KW_ONEFS},
165    {"recurse",     INC_KW_RECURSE},
166    {"sparse",      INC_KW_SPARSE},
167    {"hardlinks",   INC_KW_HARDLINK},
168    {"replace",     INC_KW_REPLACE},
169    {"readfifo",    INC_KW_READFIFO},
170    {"portable",    INC_KW_PORTABLE},
171    {"mtimeonly",   INC_KW_MTIMEONLY},
172    {"keepatime",   INC_KW_KEEPATIME},
173    {"exclude",     INC_KW_EXCLUDE},
174    {"aclsupport",  INC_KW_ACL},
175    {"ignorecase",  INC_KW_IGNORECASE},
176    {"hfsplussupport", INC_KW_HFSPLUS},
177    {"noatime",     INC_KW_NOATIME},
178    {"enhancedwild", INC_KW_ENHANCEDWILD},
179    {"checkfilechanges", INC_KW_CHKCHANGES},
180    {NULL,          0}
181 };
182
183 /* Options for FileSet keywords */
184
185 struct s_fs_opt {
186    const char *name;
187    int keyword;
188    const char *option;
189 };
190
191 /*
192  * Options permitted for each keyword and resulting value.
193  * The output goes into opts, which are then transmitted to
194  * the FD for application as options to the following list of
195  * included files.
196  */
197 static struct s_fs_opt FS_options[] = {
198    {"md5",      INC_KW_DIGEST,        "M"},
199    {"sha1",     INC_KW_DIGEST,        "S"},
200    {"sha256",   INC_KW_DIGEST,       "S2"},
201    {"sha512",   INC_KW_DIGEST,       "S3"},
202    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
203    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
204    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
205    {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
206    {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
207    {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
208    {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
209    {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
210    {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
211    {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
212    {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
213    {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
214    {"yes",      INC_KW_ONEFS,         "0"},
215    {"no",       INC_KW_ONEFS,         "f"},
216    {"yes",      INC_KW_RECURSE,       "0"},
217    {"no",       INC_KW_RECURSE,       "h"},
218    {"yes",      INC_KW_SPARSE,        "s"},
219    {"no",       INC_KW_SPARSE,        "0"},
220    {"yes",      INC_KW_HARDLINK,      "0"},
221    {"no",       INC_KW_HARDLINK,      "H"},
222    {"always",   INC_KW_REPLACE,       "a"},
223    {"ifnewer",  INC_KW_REPLACE,       "w"},
224    {"never",    INC_KW_REPLACE,       "n"},
225    {"yes",      INC_KW_READFIFO,      "r"},
226    {"no",       INC_KW_READFIFO,      "0"},
227    {"yes",      INC_KW_PORTABLE,      "p"},
228    {"no",       INC_KW_PORTABLE,      "0"},
229    {"yes",      INC_KW_MTIMEONLY,     "m"},
230    {"no",       INC_KW_MTIMEONLY,     "0"},
231    {"yes",      INC_KW_KEEPATIME,     "k"},
232    {"no",       INC_KW_KEEPATIME,     "0"},
233    {"yes",      INC_KW_EXCLUDE,       "e"},
234    {"no",       INC_KW_EXCLUDE,       "0"},
235    {"yes",      INC_KW_ACL,           "A"},
236    {"no",       INC_KW_ACL,           "0"},
237    {"yes",      INC_KW_IGNORECASE,    "i"},
238    {"no",       INC_KW_IGNORECASE,    "0"},
239    {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
240    {"no",       INC_KW_HFSPLUS,       "0"},
241    {"yes",      INC_KW_NOATIME,       "K"},
242    {"no",       INC_KW_NOATIME,       "0"},
243    {"yes",      INC_KW_ENHANCEDWILD,  "K"},
244    {"no",       INC_KW_ENHANCEDWILD,  "0"},
245    {"yes",      INC_KW_CHKCHANGES,    "c"},
246    {"no",       INC_KW_CHKCHANGES,    "0"},
247    {NULL,       0,                      0}
248 };
249
250
251
252 /*
253  * Scan for right hand side of Include options (keyword=option) is
254  *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
255  *    Whatever is found is concatenated to the opts string.
256  * This code is also used inside an Options resource.
257  */
258 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
259 {
260    int token, i;
261    char option[3];
262    int lcopts = lc->options;
263
264    option[0] = 0;                     /* default option = none */
265    option[2] = 0;                     /* terminate options */
266    lc->options |= LOPT_STRING;        /* force string */
267    token = lex_get_token(lc, T_STRING);          /* expect at least one option */
268    if (keyword == INC_KW_VERIFY) { /* special case */
269       /* ***FIXME**** ensure these are in permitted set */
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
275    /*
276     * Standard keyword options for Include/Exclude
277     */
278    } else {
279       for (i=0; FS_options[i].name; i++) {
280          if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
281             /* NOTE! maximum 2 letters here or increase option[3] */
282             option[0] = FS_options[i].option[0];
283             option[1] = FS_options[i].option[1];
284             i = 0;
285             break;
286          }
287       }
288       if (i != 0) {
289          scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
290       } else { /* add option */
291          bstrncat(opts, option, optlen);
292          Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
293       }
294    }
295    lc->options = lcopts;
296
297    /* If option terminated by comma, eat it */
298    if (lc->ch == ',') {
299       token = lex_get_token(lc, T_ALL);      /* yes, eat comma */
300    }
301 }
302
303 /*
304  *
305  * Store FileSet Include/Exclude info
306  *  NEW style includes are handled in store_newinc()
307  */
308 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
309 {
310    int token;
311
312    /*
313     * Decide if we are doing a new Include or an old include. The
314     *  new Include is followed immediately by open brace, whereas the
315     *  old include has options following the Include.
316     */
317    token = lex_get_token(lc, T_SKIP_EOL);
318    if (token == T_BOB) {
319       store_newinc(lc, item, index, pass);
320       return;
321    }
322    scan_err0(lc, _("Old style Include/Exclude not supported\n"));
323 }
324
325
326 /*
327  * Store NEW style FileSet FInclude/FExclude info
328  *
329  *  Note, when this routine is called, we are inside a FileSet
330  *  resource.  We treat the Include/Execlude like a sort of
331  *  mini-resource within the FileSet resource.
332  */
333 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
334 {
335    int token, i;
336    INCEXE *incexe;
337    bool options;
338
339    if (!res_all.res_fs.have_MD5) {
340       MD5Init(&res_all.res_fs.md5c);
341       res_all.res_fs.have_MD5 = true;
342    }
343    memset(&res_incexe, 0, sizeof(INCEXE));
344    res_all.res_fs.new_include = true;
345    while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
346       if (token == T_EOB) {
347          break;
348       }
349       if (token != T_IDENTIFIER) {
350          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
351       }
352       for (i=0; newinc_items[i].name; i++) {
353          options = strcasecmp(lc->str, "options") == 0;
354          if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
355             if (!options) {
356                token = lex_get_token(lc, T_SKIP_EOL);
357                if (token != T_EQUALS) {
358                   scan_err1(lc, _("expected an equals, got: %s"), lc->str);
359                }
360             }
361             /* Call item handler */
362             newinc_items[i].handler(lc, &newinc_items[i], i, pass);
363             i = -1;
364             break;
365          }
366       }
367       if (i >=0) {
368          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
369       }
370    }
371    if (pass == 1) {
372       incexe = (INCEXE *)malloc(sizeof(INCEXE));
373       memcpy(incexe, &res_incexe, sizeof(INCEXE));
374       memset(&res_incexe, 0, sizeof(INCEXE));
375       if (item->code == 0) { /* include */
376          if (res_all.res_fs.num_includes == 0) {
377             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
378          } else {
379             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
380                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
381          }
382          res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
383          Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
384       } else {    /* exclude */
385          if (res_all.res_fs.num_excludes == 0) {
386             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
387          } else {
388             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
389                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
390          }
391          res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
392          Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
393       }
394    }
395    scan_to_eol(lc);
396    set_bit(index, res_all.hdr.item_present);
397 }
398
399
400 /* Store regex info */
401 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
402 {
403    int token, rc;
404    regex_t preg;
405    char prbuf[500];
406    const char *type;
407    int newsize;
408
409    token = lex_get_token(lc, T_SKIP_EOL);
410    if (pass == 1) {
411       /* Pickup regex string
412        */
413       switch (token) {
414       case T_IDENTIFIER:
415       case T_UNQUOTED_STRING:
416       case T_QUOTED_STRING:
417          rc = regcomp(&preg, lc->str, REG_EXTENDED);
418          if (rc != 0) {
419             regerror(rc, &preg, prbuf, sizeof(prbuf));
420             regfree(&preg);
421             scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
422             break;
423          }
424          regfree(&preg);
425          if (item->code == 1) {
426             type = "regexdir";
427             res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
428             newsize = res_incexe.current_opts->regexdir.size();
429          } else if (item->code == 2) {
430             type = "regexfile";
431             res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
432             newsize = res_incexe.current_opts->regexfile.size();
433          } else {
434             type = "regex";
435             res_incexe.current_opts->regex.append(bstrdup(lc->str));
436             newsize = res_incexe.current_opts->regex.size();
437          }
438          Dmsg4(900, "set %s %p size=%d %s\n",
439             type, res_incexe.current_opts, newsize, lc->str);
440          break;
441       default:
442          scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
443       }
444    }
445    scan_to_eol(lc);
446 }
447
448 /* Store Base info */
449 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
450 {
451    int token;
452
453    token = lex_get_token(lc, T_NAME);
454    if (pass == 1) {
455       /*
456        * Pickup Base Job Name
457        */
458       res_incexe.current_opts->base.append(bstrdup(lc->str));
459    }
460    scan_to_eol(lc);
461 }
462
463 /* Store reader info */
464 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
465 {
466    int token;
467
468    token = lex_get_token(lc, T_NAME);
469    if (pass == 1) {
470       /*
471        * Pickup reader command
472        */
473       res_incexe.current_opts->reader = bstrdup(lc->str);
474    }
475    scan_to_eol(lc);
476 }
477
478 /* Store writer innfo */
479 static void store_writer(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 writer command
487        */
488       res_incexe.current_opts->writer = bstrdup(lc->str);
489    }
490    scan_to_eol(lc);
491 }
492
493
494
495 /* Store Wild-card info */
496 static 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 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
542 {
543    int token;
544
545    token = lex_get_token(lc, T_SKIP_EOL);
546    if (pass == 1) {
547       /* Pickup fstype string */
548       switch (token) {
549       case T_IDENTIFIER:
550       case T_UNQUOTED_STRING:
551       case T_QUOTED_STRING:
552          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
553          Dmsg3(900, "set fstype %p size=%d %s\n",
554             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
555          break;
556       default:
557          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
558       }
559    }
560    scan_to_eol(lc);
561 }
562
563 /* Store drivetype info */
564 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
565 {
566    int token;
567
568    token = lex_get_token(lc, T_SKIP_EOL);
569    if (pass == 1) {
570       /* Pickup drivetype string */
571       switch (token) {
572       case T_IDENTIFIER:
573       case T_UNQUOTED_STRING:
574       case T_QUOTED_STRING:
575          res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
576          Dmsg3(900, "set drivetype %p size=%d %s\n",
577             res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
578          break;
579       default:
580          scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
581       }
582    }
583    scan_to_eol(lc);
584 }
585
586 /*
587  * Store Filename info. Note, for minor efficiency reasons, we
588  * always increase the name buffer by 10 items because we expect
589  * to add more entries.
590  */
591 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
592 {
593    int token;
594    INCEXE *incexe;
595
596    token = lex_get_token(lc, T_SKIP_EOL);
597    if (pass == 1) {
598       /* Pickup Filename string
599        */
600       switch (token) {
601       case T_IDENTIFIER:
602       case T_UNQUOTED_STRING:
603          if (strchr(lc->str, '\\')) {
604             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
605             /* NOT REACHED */
606          }
607       case T_QUOTED_STRING:
608          if (res_all.res_fs.have_MD5) {
609             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
610          }
611          incexe = &res_incexe;
612          if (incexe->name_list.size() == 0) {
613             incexe->name_list.init(10, true);
614          }
615          incexe->name_list.append(bstrdup(lc->str));
616          Dmsg1(900, "Add to name_list %s\n", lc->str);
617          break;
618       default:
619          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
620       }
621    }
622    scan_to_eol(lc);
623 }
624
625
626 /*
627  * Come here when Options seen in Include/Exclude
628  */
629 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
630 {
631    int token, i;
632
633    token = lex_get_token(lc, T_SKIP_EOL);
634    if (token != T_BOB) {
635       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
636    }
637
638    if (pass == 1) {
639       setup_current_opts();
640    }
641
642    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
643       if (token == T_EOL) {
644          continue;
645       }
646       if (token == T_EOB) {
647          break;
648       }
649       if (token != T_IDENTIFIER) {
650          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
651       }
652       for (i=0; options_items[i].name; i++) {
653          if (strcasecmp(options_items[i].name, lc->str) == 0) {
654             token = lex_get_token(lc, T_SKIP_EOL);
655             if (token != T_EQUALS) {
656                scan_err1(lc, _("expected an equals, got: %s"), lc->str);
657             }
658             /* Call item handler */
659             options_items[i].handler(lc, &options_items[i], i, pass);
660             i = -1;
661             break;
662          }
663       }
664       if (i >=0) {
665          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
666       }
667    }
668 }
669
670
671 /*
672  * New style options come here
673  */
674 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
675 {
676    int i;
677    int keyword;
678    char inc_opts[100];
679
680    inc_opts[0] = 0;
681    keyword = INC_KW_NONE;
682    /* Look up the keyword */
683    for (i=0; FS_option_kw[i].name; i++) {
684       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
685          keyword = FS_option_kw[i].token;
686          break;
687       }
688    }
689    if (keyword == INC_KW_NONE) {
690       scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
691    }
692    /* Now scan for the value */
693    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
694    if (pass == 1) {
695       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
696       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
697    }
698    scan_to_eol(lc);
699 }
700
701
702
703 /* If current_opts not defined, create first entry */
704 static void setup_current_opts(void)
705 {
706    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
707    memset(fo, 0, sizeof(FOPTS));
708    fo->regex.init(1, true);
709    fo->regexdir.init(1, true);
710    fo->regexfile.init(1, true);
711    fo->wild.init(1, true);
712    fo->wilddir.init(1, true);
713    fo->wildfile.init(1, true);
714    fo->wildbase.init(1, true);
715    fo->base.init(1, true);
716    fo->fstype.init(1, true);
717    fo->drivetype.init(1, true);
718    res_incexe.current_opts = fo;
719    if (res_incexe.num_opts == 0) {
720       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
721    } else {
722       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
723                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
724    }
725    res_incexe.opts_list[res_incexe.num_opts++] = fo;
726 }