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 two of the GNU 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 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 {"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 {"ignorecase", store_opts, {0}, 0, 0, 0},
123 {"fstype", store_fstype, {0}, 0, 0, 0},
124 {"hfsplussupport", store_opts, {0}, 0, 0, 0},
125 {"noatime", store_opts, {0}, 0, 0, 0},
126 {"enhancedwild", store_opts, {0}, 0, 0, 0},
127 {"drivetype", store_drivetype, {0}, 0, 0, 0},
128 {"checkfilechanges",store_opts, {0}, 0, 0, 1},
129 {"strippath", store_opts, {0}, 0, 0, 0},
130 {"honornodumpflag", store_opts, {0}, 0, 0, 0},
131 {"xattrsupport", store_opts, {0}, 0, 0, 0},
132 {NULL, NULL, {0}, 0, 0, 0}
136 /* Define FileSet KeyWord values */
148 INC_KW_REPLACE, /* restore options */
149 INC_KW_READFIFO, /* Causes fifo data to be read */
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.
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 {"xattrsupport", INC_KW_XATTR},
199 /* Options for FileSet keywords */
208 * Options permitted for each keyword and resulting value.
209 * The output goes into opts, which are then transmitted to
210 * the FD for application as options to the following list of
213 static struct s_fs_opt FS_options[] = {
214 {"md5", INC_KW_DIGEST, "M"},
215 {"sha1", INC_KW_DIGEST, "S"},
216 {"sha256", INC_KW_DIGEST, "S2"},
217 {"sha512", INC_KW_DIGEST, "S3"},
218 {"gzip", INC_KW_COMPRESSION, "Z6"},
219 {"gzip1", INC_KW_COMPRESSION, "Z1"},
220 {"gzip2", INC_KW_COMPRESSION, "Z2"},
221 {"gzip3", INC_KW_COMPRESSION, "Z3"},
222 {"gzip4", INC_KW_COMPRESSION, "Z4"},
223 {"gzip5", INC_KW_COMPRESSION, "Z5"},
224 {"gzip6", INC_KW_COMPRESSION, "Z6"},
225 {"gzip7", INC_KW_COMPRESSION, "Z7"},
226 {"gzip8", INC_KW_COMPRESSION, "Z8"},
227 {"gzip9", INC_KW_COMPRESSION, "Z9"},
228 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
229 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
230 {"yes", INC_KW_ONEFS, "0"},
231 {"no", INC_KW_ONEFS, "f"},
232 {"yes", INC_KW_RECURSE, "0"},
233 {"no", INC_KW_RECURSE, "h"},
234 {"yes", INC_KW_SPARSE, "s"},
235 {"no", INC_KW_SPARSE, "0"},
236 {"yes", INC_KW_HARDLINK, "0"},
237 {"no", INC_KW_HARDLINK, "H"},
238 {"always", INC_KW_REPLACE, "a"},
239 {"ifnewer", INC_KW_REPLACE, "w"},
240 {"never", INC_KW_REPLACE, "n"},
241 {"yes", INC_KW_READFIFO, "r"},
242 {"no", INC_KW_READFIFO, "0"},
243 {"yes", INC_KW_PORTABLE, "p"},
244 {"no", INC_KW_PORTABLE, "0"},
245 {"yes", INC_KW_MTIMEONLY, "m"},
246 {"no", INC_KW_MTIMEONLY, "0"},
247 {"yes", INC_KW_KEEPATIME, "k"},
248 {"no", INC_KW_KEEPATIME, "0"},
249 {"yes", INC_KW_EXCLUDE, "e"},
250 {"no", INC_KW_EXCLUDE, "0"},
251 {"yes", INC_KW_ACL, "A"},
252 {"no", INC_KW_ACL, "0"},
253 {"yes", INC_KW_IGNORECASE, "i"},
254 {"no", INC_KW_IGNORECASE, "0"},
255 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
256 {"no", INC_KW_HFSPLUS, "0"},
257 {"yes", INC_KW_NOATIME, "K"},
258 {"no", INC_KW_NOATIME, "0"},
259 {"yes", INC_KW_ENHANCEDWILD, "K"},
260 {"no", INC_KW_ENHANCEDWILD, "0"},
261 {"yes", INC_KW_CHKCHANGES, "c"},
262 {"no", INC_KW_CHKCHANGES, "0"},
263 {"yes", INC_KW_HONOR_NODUMP, "N"},
264 {"no", INC_KW_HONOR_NODUMP, "0"},
265 {"yes", INC_KW_XATTR, "X"},
266 {"no", INC_KW_XATTR, "0"},
273 * Scan for right hand side of Include options (keyword=option) is
274 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
275 * Whatever is found is concatenated to the opts string.
276 * This code is also used inside an Options resource.
278 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
282 int lcopts = lc->options;
284 option[0] = 0; /* default option = none */
285 option[2] = 0; /* terminate options */
286 lc->options |= LOPT_STRING; /* force string */
287 token = lex_get_token(lc, T_STRING); /* expect at least one option */
288 if (keyword == INC_KW_VERIFY) { /* special case */
289 /* ***FIXME**** ensure these are in permitted set */
290 bstrncat(opts, "V", optlen); /* indicate Verify */
291 bstrncat(opts, lc->str, optlen);
292 bstrncat(opts, ":", optlen); /* terminate it */
293 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
294 } else if (keyword == INC_KW_ACCURATE) { /* special case */
295 /* ***FIXME**** ensure these are in permitted set */
296 bstrncat(opts, "C", optlen); /* indicate Accurate */
297 bstrncat(opts, lc->str, optlen);
298 bstrncat(opts, ":", optlen); /* terminate it */
299 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
300 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
301 if (!is_an_integer(lc->str)) {
302 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
304 bstrncat(opts, "P", optlen); /* indicate strip path */
305 bstrncat(opts, lc->str, optlen);
306 bstrncat(opts, ":", optlen); /* terminate it */
307 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
309 * Standard keyword options for Include/Exclude
312 for (i=0; FS_options[i].name; i++) {
313 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
314 /* NOTE! maximum 2 letters here or increase option[3] */
315 option[0] = FS_options[i].option[0];
316 option[1] = FS_options[i].option[1];
322 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
323 } else { /* add option */
324 bstrncat(opts, option, optlen);
325 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
328 lc->options = lcopts;
330 /* If option terminated by comma, eat it */
332 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
338 * Store FileSet Include/Exclude info
339 * new style includes are handled in store_newinc()
341 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
346 * Decide if we are doing a new Include or an old include. The
347 * new Include is followed immediately by open brace, whereas the
348 * old include has options following the Include.
350 token = lex_get_token(lc, T_SKIP_EOL);
351 if (token == T_BOB) {
352 store_newinc(lc, item, index, pass);
355 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
360 * Store new style FileSet Include/Exclude info
362 * Note, when this routine is called, we are inside a FileSet
363 * resource. We treat the Include/Execlude like a sort of
364 * mini-resource within the FileSet resource.
366 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
372 if (!res_all.res_fs.have_MD5) {
373 MD5Init(&res_all.res_fs.md5c);
374 res_all.res_fs.have_MD5 = true;
376 memset(&res_incexe, 0, sizeof(INCEXE));
377 res_all.res_fs.new_include = true;
378 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
379 if (token == T_EOB) {
382 if (token != T_IDENTIFIER) {
383 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
385 for (i=0; newinc_items[i].name; i++) {
386 options = strcasecmp(lc->str, "options") == 0;
387 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
389 token = lex_get_token(lc, T_SKIP_EOL);
390 if (token != T_EQUALS) {
391 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
394 /* Call item handler */
395 newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
401 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
405 incexe = (INCEXE *)malloc(sizeof(INCEXE));
406 memcpy(incexe, &res_incexe, sizeof(INCEXE));
407 memset(&res_incexe, 0, sizeof(INCEXE));
408 if (item->code == 0) { /* include */
409 if (res_all.res_fs.num_includes == 0) {
410 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
412 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
413 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
415 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
416 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
417 } else { /* exclude */
418 if (res_all.res_fs.num_excludes == 0) {
419 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
421 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
422 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
424 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
425 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
429 set_bit(index, res_all.hdr.item_present);
433 /* Store regex info */
434 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
442 token = lex_get_token(lc, T_SKIP_EOL);
444 /* Pickup regex string
448 case T_UNQUOTED_STRING:
449 case T_QUOTED_STRING:
450 rc = regcomp(&preg, lc->str, REG_EXTENDED);
452 regerror(rc, &preg, prbuf, sizeof(prbuf));
454 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
458 if (item->code == 1) {
460 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
461 newsize = res_incexe.current_opts->regexdir.size();
462 } else if (item->code == 2) {
464 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
465 newsize = res_incexe.current_opts->regexfile.size();
468 res_incexe.current_opts->regex.append(bstrdup(lc->str));
469 newsize = res_incexe.current_opts->regex.size();
471 Dmsg4(900, "set %s %p size=%d %s\n",
472 type, res_incexe.current_opts, newsize, lc->str);
475 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
481 /* Store Base info */
482 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
486 token = lex_get_token(lc, T_NAME);
489 * Pickup Base Job Name
491 res_incexe.current_opts->base.append(bstrdup(lc->str));
496 /* Store reader info */
497 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
501 token = lex_get_token(lc, T_NAME);
504 * Pickup plugin command
506 res_incexe.current_opts->plugin = bstrdup(lc->str);
512 /* Store Wild-card info */
513 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
519 token = lex_get_token(lc, T_SKIP_EOL);
522 * Pickup Wild-card string
526 case T_UNQUOTED_STRING:
527 case T_QUOTED_STRING:
528 if (item->code == 1) {
530 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
531 newsize = res_incexe.current_opts->wilddir.size();
532 } else if (item->code == 2) {
533 if (strpbrk(lc->str, "/\\") != NULL) {
535 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
536 newsize = res_incexe.current_opts->wildfile.size();
539 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
540 newsize = res_incexe.current_opts->wildbase.size();
544 res_incexe.current_opts->wild.append(bstrdup(lc->str));
545 newsize = res_incexe.current_opts->wild.size();
547 Dmsg4(9, "set %s %p size=%d %s\n",
548 type, res_incexe.current_opts, newsize, lc->str);
551 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
557 /* Store fstype info */
558 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
562 token = lex_get_token(lc, T_SKIP_EOL);
564 /* Pickup fstype string */
567 case T_UNQUOTED_STRING:
568 case T_QUOTED_STRING:
569 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
570 Dmsg3(900, "set fstype %p size=%d %s\n",
571 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
574 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
580 /* Store exclude directory containing info */
581 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
586 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
589 token = lex_get_token(lc, T_NAME);
591 res_incexe.ignoredir = bstrdup(lc->str);
596 /* Store drivetype info */
597 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
601 token = lex_get_token(lc, T_SKIP_EOL);
603 /* Pickup drivetype string */
606 case T_UNQUOTED_STRING:
607 case T_QUOTED_STRING:
608 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
609 Dmsg3(900, "set drivetype %p size=%d %s\n",
610 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
613 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
620 * Store Filename info. Note, for minor efficiency reasons, we
621 * always increase the name buffer by 10 items because we expect
622 * to add more entries.
624 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
629 token = lex_get_token(lc, T_SKIP_EOL);
631 /* Pickup Filename string
635 case T_UNQUOTED_STRING:
636 if (strchr(lc->str, '\\')) {
637 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
640 case T_QUOTED_STRING:
641 if (res_all.res_fs.have_MD5) {
642 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
644 incexe = &res_incexe;
645 if (incexe->name_list.size() == 0) {
646 incexe->name_list.init(10, true);
648 incexe->name_list.append(bstrdup(lc->str));
649 Dmsg1(900, "Add to name_list %s\n", lc->str);
652 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
659 * Store Filename info. Note, for minor efficiency reasons, we
660 * always increase the name buffer by 10 items because we expect
661 * to add more entries.
663 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
669 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
672 token = lex_get_token(lc, T_SKIP_EOL);
674 /* Pickup Filename string
678 case T_UNQUOTED_STRING:
679 if (strchr(lc->str, '\\')) {
680 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
683 case T_QUOTED_STRING:
684 if (res_all.res_fs.have_MD5) {
685 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
687 incexe = &res_incexe;
688 if (incexe->plugin_list.size() == 0) {
689 incexe->plugin_list.init(10, true);
691 incexe->plugin_list.append(bstrdup(lc->str));
692 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
695 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
705 * Come here when Options seen in Include/Exclude
707 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
712 scan_err0(lc, _("Options section not permitted in Exclude\n"));
715 token = lex_get_token(lc, T_SKIP_EOL);
716 if (token != T_BOB) {
717 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
721 setup_current_opts();
724 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
725 if (token == T_EOL) {
728 if (token == T_EOB) {
731 if (token != T_IDENTIFIER) {
732 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
734 for (i=0; options_items[i].name; i++) {
735 if (strcasecmp(options_items[i].name, lc->str) == 0) {
736 token = lex_get_token(lc, T_SKIP_EOL);
737 if (token != T_EQUALS) {
738 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
740 /* Call item handler */
741 options_items[i].handler(lc, &options_items[i], i, pass);
747 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
754 * New style options come here
756 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
763 keyword = INC_KW_NONE;
764 /* Look up the keyword */
765 for (i=0; FS_option_kw[i].name; i++) {
766 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
767 keyword = FS_option_kw[i].token;
771 if (keyword == INC_KW_NONE) {
772 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
774 /* Now scan for the value */
775 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
777 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
778 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
785 /* If current_opts not defined, create first entry */
786 static void setup_current_opts(void)
788 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
789 memset(fo, 0, sizeof(FOPTS));
790 fo->regex.init(1, true);
791 fo->regexdir.init(1, true);
792 fo->regexfile.init(1, true);
793 fo->wild.init(1, true);
794 fo->wilddir.init(1, true);
795 fo->wildfile.init(1, true);
796 fo->wildbase.init(1, true);
797 fo->base.init(1, true);
798 fo->fstype.init(1, true);
799 fo->drivetype.init(1, true);
800 res_incexe.current_opts = fo;
801 if (res_incexe.num_opts == 0) {
802 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
804 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
805 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
807 res_incexe.opts_list[res_incexe.num_opts++] = fo;