2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
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 three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
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.
18 You should have received a copy of the GNU Affero 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
23 Bacula® is a registered trademark of Kern Sibbald.
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.
29 * Configuration file parser for new and old Include and
32 * Kern Sibbald, March MMIII
40 #include "lib/bregex.h"
45 /* Forward referenced subroutines */
47 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
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_base(LEX *lc, RES_ITEM *item, int index, int pass);
56 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
57 static void setup_current_opts(void);
59 /* Include and Exclude items */
60 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
61 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
62 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
63 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
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
72 extern "C" { // work around visual compiler mangling variables
78 extern int32_t res_all_size;
80 /* We build the current new Include and Exclude items here */
81 static INCEXE res_incexe;
84 * new Include/Exclude items
85 * name handler value code flags default_value
87 static RES_ITEM2 newinc_items[] = {
88 {"file", store_fname, {0}, 0, 0, 0},
89 {"plugin", store_plugin_name, {0}, 0, 0, 0},
90 {"excludedircontaining", store_excludedir, {0}, 0, 0, 0},
91 {"options", options_res, {0}, 0, 0, 0},
92 {NULL, NULL, {0}, 0, 0, 0}
96 * Items that are valid in an Options resource
98 static RES_ITEM options_items[] = {
99 {"compression", store_opts, {0}, 0, 0, 0},
100 {"signature", store_opts, {0}, 0, 0, 0},
101 {"basejob", store_opts, {0}, 0, 0, 0},
102 {"accurate", store_opts, {0}, 0, 0, 0},
103 {"verify", store_opts, {0}, 0, 0, 0},
104 {"onefs", store_opts, {0}, 0, 0, 0},
105 {"recurse", store_opts, {0}, 0, 0, 0},
106 {"sparse", store_opts, {0}, 0, 0, 0},
107 {"hardlinks", store_opts, {0}, 0, 0, 0},
108 {"readfifo", store_opts, {0}, 0, 0, 0},
109 {"replace", store_opts, {0}, 0, 0, 0},
110 {"portable", store_opts, {0}, 0, 0, 0},
111 {"mtimeonly", store_opts, {0}, 0, 0, 0},
112 {"keepatime", store_opts, {0}, 0, 0, 0},
113 {"regex", store_regex, {0}, 0, 0, 0},
114 {"regexdir", store_regex, {0}, 1, 0, 0},
115 {"regexfile", store_regex, {0}, 2, 0, 0},
116 {"base", store_base, {0}, 0, 0, 0},
117 {"wild", store_wild, {0}, 0, 0, 0},
118 {"wilddir", store_wild, {0}, 1, 0, 0},
119 {"wildfile", store_wild, {0}, 2, 0, 0},
120 {"exclude", store_opts, {0}, 0, 0, 0},
121 {"aclsupport", store_opts, {0}, 0, 0, 0},
122 {"plugin", store_plugin, {0}, 0, 0, 0},
123 {"ignorecase", store_opts, {0}, 0, 0, 0},
124 {"fstype", store_fstype, {0}, 0, 0, 0},
125 {"hfsplussupport", store_opts, {0}, 0, 0, 0},
126 {"noatime", store_opts, {0}, 0, 0, 0},
127 {"enhancedwild", store_opts, {0}, 0, 0, 0},
128 {"drivetype", store_drivetype, {0}, 0, 0, 0},
129 {"checkfilechanges",store_opts, {0}, 0, 0, 1},
130 {"strippath", store_opts, {0}, 0, 0, 0},
131 {"honornodumpflag", store_opts, {0}, 0, 0, 0},
132 {"xattrsupport", store_opts, {0}, 0, 0, 0},
133 {NULL, NULL, {0}, 0, 0, 0}
137 /* Define FileSet KeyWord values */
150 INC_KW_REPLACE, /* restore options */
151 INC_KW_READFIFO, /* Causes fifo data to be read */
168 * This is the list of options that can be stored by store_opts
169 * Note, now that the old style Include/Exclude code is gone,
170 * the INC_KW code could be put into the "code" field of the
171 * options given above.
173 static struct s_kw FS_option_kw[] = {
174 {"compression", INC_KW_COMPRESSION},
175 {"signature", INC_KW_DIGEST},
176 {"encryption", INC_KW_ENCRYPTION},
177 {"verify", INC_KW_VERIFY},
178 {"basejob", INC_KW_BASEJOB},
179 {"accurate", INC_KW_ACCURATE},
180 {"onefs", INC_KW_ONEFS},
181 {"recurse", INC_KW_RECURSE},
182 {"sparse", INC_KW_SPARSE},
183 {"hardlinks", INC_KW_HARDLINK},
184 {"replace", INC_KW_REPLACE},
185 {"readfifo", INC_KW_READFIFO},
186 {"portable", INC_KW_PORTABLE},
187 {"mtimeonly", INC_KW_MTIMEONLY},
188 {"keepatime", INC_KW_KEEPATIME},
189 {"exclude", INC_KW_EXCLUDE},
190 {"aclsupport", INC_KW_ACL},
191 {"ignorecase", INC_KW_IGNORECASE},
192 {"hfsplussupport", INC_KW_HFSPLUS},
193 {"noatime", INC_KW_NOATIME},
194 {"enhancedwild", INC_KW_ENHANCEDWILD},
195 {"checkfilechanges", INC_KW_CHKCHANGES},
196 {"strippath", INC_KW_STRIPPATH},
197 {"honornodumpflag", INC_KW_HONOR_NODUMP},
198 {"xattrsupport", INC_KW_XATTR},
202 /* Options for FileSet keywords */
211 * Options permitted for each keyword and resulting value.
212 * The output goes into opts, which are then transmitted to
213 * the FD for application as options to the following list of
216 static struct s_fs_opt FS_options[] = {
217 {"md5", INC_KW_DIGEST, "M"},
218 {"sha1", INC_KW_DIGEST, "S"},
219 {"sha256", INC_KW_DIGEST, "S2"},
220 {"sha512", INC_KW_DIGEST, "S3"},
221 {"gzip", INC_KW_COMPRESSION, "Z6"},
222 {"gzip1", INC_KW_COMPRESSION, "Z1"},
223 {"gzip2", INC_KW_COMPRESSION, "Z2"},
224 {"gzip3", INC_KW_COMPRESSION, "Z3"},
225 {"gzip4", INC_KW_COMPRESSION, "Z4"},
226 {"gzip5", INC_KW_COMPRESSION, "Z5"},
227 {"gzip6", INC_KW_COMPRESSION, "Z6"},
228 {"gzip7", INC_KW_COMPRESSION, "Z7"},
229 {"gzip8", INC_KW_COMPRESSION, "Z8"},
230 {"gzip9", INC_KW_COMPRESSION, "Z9"},
231 {"lzo", INC_KW_COMPRESSION, "Zo"},
232 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
233 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
234 {"yes", INC_KW_ONEFS, "0"},
235 {"no", INC_KW_ONEFS, "f"},
236 {"yes", INC_KW_RECURSE, "0"},
237 {"no", INC_KW_RECURSE, "h"},
238 {"yes", INC_KW_SPARSE, "s"},
239 {"no", INC_KW_SPARSE, "0"},
240 {"yes", INC_KW_HARDLINK, "0"},
241 {"no", INC_KW_HARDLINK, "H"},
242 {"always", INC_KW_REPLACE, "a"},
243 {"ifnewer", INC_KW_REPLACE, "w"},
244 {"never", INC_KW_REPLACE, "n"},
245 {"yes", INC_KW_READFIFO, "r"},
246 {"no", INC_KW_READFIFO, "0"},
247 {"yes", INC_KW_PORTABLE, "p"},
248 {"no", INC_KW_PORTABLE, "0"},
249 {"yes", INC_KW_MTIMEONLY, "m"},
250 {"no", INC_KW_MTIMEONLY, "0"},
251 {"yes", INC_KW_KEEPATIME, "k"},
252 {"no", INC_KW_KEEPATIME, "0"},
253 {"yes", INC_KW_EXCLUDE, "e"},
254 {"no", INC_KW_EXCLUDE, "0"},
255 {"yes", INC_KW_ACL, "A"},
256 {"no", INC_KW_ACL, "0"},
257 {"yes", INC_KW_IGNORECASE, "i"},
258 {"no", INC_KW_IGNORECASE, "0"},
259 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
260 {"no", INC_KW_HFSPLUS, "0"},
261 {"yes", INC_KW_NOATIME, "K"},
262 {"no", INC_KW_NOATIME, "0"},
263 {"yes", INC_KW_ENHANCEDWILD, "K"},
264 {"no", INC_KW_ENHANCEDWILD, "0"},
265 {"yes", INC_KW_CHKCHANGES, "c"},
266 {"no", INC_KW_CHKCHANGES, "0"},
267 {"yes", INC_KW_HONOR_NODUMP, "N"},
268 {"no", INC_KW_HONOR_NODUMP, "0"},
269 {"yes", INC_KW_XATTR, "X"},
270 {"no", INC_KW_XATTR, "0"},
277 * Scan for right hand side of Include options (keyword=option) is
278 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
279 * Whatever is found is concatenated to the opts string.
280 * This code is also used inside an Options resource.
282 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
286 int lcopts = lc->options;
288 option[0] = 0; /* default option = none */
289 option[2] = 0; /* terminate options */
290 lc->options |= LOPT_STRING; /* force string */
291 lex_get_token(lc, T_STRING); /* expect at least one option */
292 if (keyword == INC_KW_VERIFY) { /* special case */
293 /* ***FIXME**** ensure these are in permitted set */
294 bstrncat(opts, "V", optlen); /* indicate Verify */
295 bstrncat(opts, lc->str, optlen);
296 bstrncat(opts, ":", optlen); /* terminate it */
297 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
298 } else if (keyword == INC_KW_ACCURATE) { /* special case */
299 /* ***FIXME**** ensure these are in permitted set */
300 bstrncat(opts, "C", optlen); /* indicate Accurate */
301 bstrncat(opts, lc->str, optlen);
302 bstrncat(opts, ":", optlen); /* terminate it */
303 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
304 } else if (keyword == INC_KW_BASEJOB) { /* special case */
305 /* ***FIXME**** ensure these are in permitted set */
306 bstrncat(opts, "J", optlen); /* indicate BaseJob */
307 bstrncat(opts, lc->str, optlen);
308 bstrncat(opts, ":", optlen); /* terminate it */
309 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
310 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
311 if (!is_an_integer(lc->str)) {
312 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
314 bstrncat(opts, "P", optlen); /* indicate strip path */
315 bstrncat(opts, lc->str, optlen);
316 bstrncat(opts, ":", optlen); /* terminate it */
317 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
319 * Standard keyword options for Include/Exclude
322 for (i=0; FS_options[i].name; i++) {
323 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
324 /* NOTE! maximum 2 letters here or increase option[3] */
325 option[0] = FS_options[i].option[0];
326 option[1] = FS_options[i].option[1];
332 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
333 } else { /* add option */
334 bstrncat(opts, option, optlen);
335 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
338 lc->options = lcopts;
340 /* If option terminated by comma, eat it */
342 lex_get_token(lc, T_ALL); /* yes, eat comma */
348 * Store FileSet Include/Exclude info
349 * new style includes are handled in store_newinc()
351 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
356 * Decide if we are doing a new Include or an old include. The
357 * new Include is followed immediately by open brace, whereas the
358 * old include has options following the Include.
360 token = lex_get_token(lc, T_SKIP_EOL);
361 if (token == T_BOB) {
362 store_newinc(lc, item, index, pass);
365 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
370 * Store new style FileSet Include/Exclude info
372 * Note, when this routine is called, we are inside a FileSet
373 * resource. We treat the Include/Execlude like a sort of
374 * mini-resource within the FileSet resource.
376 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
382 if (!res_all.res_fs.have_MD5) {
383 MD5Init(&res_all.res_fs.md5c);
384 res_all.res_fs.have_MD5 = true;
386 memset(&res_incexe, 0, sizeof(INCEXE));
387 res_all.res_fs.new_include = true;
388 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
389 if (token == T_EOB) {
392 if (token != T_IDENTIFIER) {
393 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
395 for (i=0; newinc_items[i].name; i++) {
396 options = strcasecmp(lc->str, "options") == 0;
397 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
399 token = lex_get_token(lc, T_SKIP_EOL);
400 if (token != T_EQUALS) {
401 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
404 /* Call item handler */
405 newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
411 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
415 incexe = (INCEXE *)malloc(sizeof(INCEXE));
416 memcpy(incexe, &res_incexe, sizeof(INCEXE));
417 memset(&res_incexe, 0, sizeof(INCEXE));
418 if (item->code == 0) { /* include */
419 if (res_all.res_fs.num_includes == 0) {
420 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
422 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
423 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
425 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
426 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
427 } else { /* exclude */
428 if (res_all.res_fs.num_excludes == 0) {
429 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
431 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
432 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
434 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
435 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
439 set_bit(index, res_all.hdr.item_present);
443 /* Store regex info */
444 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
452 token = lex_get_token(lc, T_SKIP_EOL);
454 /* Pickup regex string
458 case T_UNQUOTED_STRING:
459 case T_QUOTED_STRING:
460 rc = regcomp(&preg, lc->str, REG_EXTENDED);
462 regerror(rc, &preg, prbuf, sizeof(prbuf));
464 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
468 if (item->code == 1) {
470 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
471 newsize = res_incexe.current_opts->regexdir.size();
472 } else if (item->code == 2) {
474 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
475 newsize = res_incexe.current_opts->regexfile.size();
478 res_incexe.current_opts->regex.append(bstrdup(lc->str));
479 newsize = res_incexe.current_opts->regex.size();
481 Dmsg4(900, "set %s %p size=%d %s\n",
482 type, res_incexe.current_opts, newsize, lc->str);
485 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
491 /* Store Base info */
492 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
495 lex_get_token(lc, T_NAME);
498 * Pickup Base Job Name
500 res_incexe.current_opts->base.append(bstrdup(lc->str));
505 /* Store reader info */
506 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
509 lex_get_token(lc, T_NAME);
512 * Pickup plugin command
514 res_incexe.current_opts->plugin = bstrdup(lc->str);
520 /* Store Wild-card info */
521 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
527 token = lex_get_token(lc, T_SKIP_EOL);
530 * Pickup Wild-card string
534 case T_UNQUOTED_STRING:
535 case T_QUOTED_STRING:
536 if (item->code == 1) {
538 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
539 newsize = res_incexe.current_opts->wilddir.size();
540 } else if (item->code == 2) {
541 if (strpbrk(lc->str, "/\\") != NULL) {
543 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
544 newsize = res_incexe.current_opts->wildfile.size();
547 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
548 newsize = res_incexe.current_opts->wildbase.size();
552 res_incexe.current_opts->wild.append(bstrdup(lc->str));
553 newsize = res_incexe.current_opts->wild.size();
555 Dmsg4(9, "set %s %p size=%d %s\n",
556 type, res_incexe.current_opts, newsize, lc->str);
559 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
565 /* Store fstype info */
566 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
570 token = lex_get_token(lc, T_SKIP_EOL);
572 /* Pickup fstype string */
575 case T_UNQUOTED_STRING:
576 case T_QUOTED_STRING:
577 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
578 Dmsg3(900, "set fstype %p size=%d %s\n",
579 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
582 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
588 /* Store exclude directory containing info */
589 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
593 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
596 lex_get_token(lc, T_NAME);
598 res_incexe.ignoredir = bstrdup(lc->str);
603 /* Store drivetype info */
604 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
608 token = lex_get_token(lc, T_SKIP_EOL);
610 /* Pickup drivetype string */
613 case T_UNQUOTED_STRING:
614 case T_QUOTED_STRING:
615 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
616 Dmsg3(900, "set drivetype %p size=%d %s\n",
617 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
620 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
627 * Store Filename info. Note, for minor efficiency reasons, we
628 * always increase the name buffer by 10 items because we expect
629 * to add more entries.
631 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
636 token = lex_get_token(lc, T_SKIP_EOL);
638 /* Pickup Filename string
642 case T_UNQUOTED_STRING:
643 if (strchr(lc->str, '\\')) {
644 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
647 case T_QUOTED_STRING:
648 if (res_all.res_fs.have_MD5) {
649 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
651 incexe = &res_incexe;
652 if (incexe->name_list.size() == 0) {
653 incexe->name_list.init(10, true);
655 incexe->name_list.append(bstrdup(lc->str));
656 Dmsg1(900, "Add to name_list %s\n", lc->str);
659 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
666 * Store Filename info. Note, for minor efficiency reasons, we
667 * always increase the name buffer by 10 items because we expect
668 * to add more entries.
670 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
676 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
679 token = lex_get_token(lc, T_SKIP_EOL);
681 /* Pickup Filename string
685 case T_UNQUOTED_STRING:
686 if (strchr(lc->str, '\\')) {
687 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
690 case T_QUOTED_STRING:
691 if (res_all.res_fs.have_MD5) {
692 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
694 incexe = &res_incexe;
695 if (incexe->plugin_list.size() == 0) {
696 incexe->plugin_list.init(10, true);
698 incexe->plugin_list.append(bstrdup(lc->str));
699 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
702 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
712 * Come here when Options seen in Include/Exclude
714 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
719 scan_err0(lc, _("Options section not permitted in Exclude\n"));
722 token = lex_get_token(lc, T_SKIP_EOL);
723 if (token != T_BOB) {
724 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
728 setup_current_opts();
731 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
732 if (token == T_EOL) {
735 if (token == T_EOB) {
738 if (token != T_IDENTIFIER) {
739 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
741 for (i=0; options_items[i].name; i++) {
742 if (strcasecmp(options_items[i].name, lc->str) == 0) {
743 token = lex_get_token(lc, T_SKIP_EOL);
744 if (token != T_EQUALS) {
745 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
747 /* Call item handler */
748 options_items[i].handler(lc, &options_items[i], i, pass);
754 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
761 * New style options come here
763 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
770 keyword = INC_KW_NONE;
771 /* Look up the keyword */
772 for (i=0; FS_option_kw[i].name; i++) {
773 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
774 keyword = FS_option_kw[i].token;
778 if (keyword == INC_KW_NONE) {
779 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
781 /* Now scan for the value */
782 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
784 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
785 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
792 /* If current_opts not defined, create first entry */
793 static void setup_current_opts(void)
795 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
796 memset(fo, 0, sizeof(FOPTS));
797 fo->regex.init(1, true);
798 fo->regexdir.init(1, true);
799 fo->regexfile.init(1, true);
800 fo->wild.init(1, true);
801 fo->wilddir.init(1, true);
802 fo->wildfile.init(1, true);
803 fo->wildbase.init(1, true);
804 fo->base.init(1, true);
805 fo->fstype.init(1, true);
806 fo->drivetype.init(1, true);
807 res_incexe.current_opts = fo;
808 if (res_incexe.num_opts == 0) {
809 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
811 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
812 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
814 res_incexe.opts_list[res_incexe.num_opts++] = fo;