2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 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.
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_fname(LEX *lc, RES_ITEM *item, int index, int pass);
56 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass);
57 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
58 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
59 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
60 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
61 static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass);
62 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
63 static void setup_current_opts(void);
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 int 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_ITEM newinc_items[] = {
88 {"file", store_fname, {0}, 0, 0, 0},
89 {"plugin", store_plugin_name, {0}, 0, 0, 0},
90 {"ignoredir", store_ignoredir, {0}, 0, 0, 0},
91 {"options", options_res, {0}, 0, 0, 0},
92 {NULL, NULL, {0}, 0, 0, 0}
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 {"reader", store_reader, {0}, 0, 0, 0},
123 {"writer", store_writer, {0}, 0, 0, 0},
124 {"ignorecase", store_opts, {0}, 0, 0, 0},
125 {"fstype", store_fstype, {0}, 0, 0, 0},
126 {"hfsplussupport", store_opts, {0}, 0, 0, 0},
127 {"noatime", store_opts, {0}, 0, 0, 0},
128 {"enhancedwild", store_opts, {0}, 0, 0, 0},
129 {"drivetype", store_drivetype, {0}, 0, 0, 0},
130 {"checkfilechanges",store_opts, {0}, 0, 0, 0},
131 {"strippath", store_opts, {0}, 0, 0, 0},
132 {"honornodumpflag", store_opts, {0}, 0, 0, 0},
133 {NULL, NULL, {0}, 0, 0, 0}
137 /* Define FileSet KeyWord values */
149 INC_KW_REPLACE, /* restore options */
150 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},
198 /* Options for FileSet keywords */
207 * Options permitted for each keyword and resulting value.
208 * The output goes into opts, which are then transmitted to
209 * the FD for application as options to the following list of
212 static struct s_fs_opt FS_options[] = {
213 {"md5", INC_KW_DIGEST, "M"},
214 {"sha1", INC_KW_DIGEST, "S"},
215 {"sha256", INC_KW_DIGEST, "S2"},
216 {"sha512", INC_KW_DIGEST, "S3"},
217 {"gzip", INC_KW_COMPRESSION, "Z6"},
218 {"gzip1", INC_KW_COMPRESSION, "Z1"},
219 {"gzip2", INC_KW_COMPRESSION, "Z2"},
220 {"gzip3", INC_KW_COMPRESSION, "Z3"},
221 {"gzip4", INC_KW_COMPRESSION, "Z4"},
222 {"gzip5", INC_KW_COMPRESSION, "Z5"},
223 {"gzip6", INC_KW_COMPRESSION, "Z6"},
224 {"gzip7", INC_KW_COMPRESSION, "Z7"},
225 {"gzip8", INC_KW_COMPRESSION, "Z8"},
226 {"gzip9", INC_KW_COMPRESSION, "Z9"},
227 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
228 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
229 {"yes", INC_KW_ONEFS, "0"},
230 {"no", INC_KW_ONEFS, "f"},
231 {"yes", INC_KW_RECURSE, "0"},
232 {"no", INC_KW_RECURSE, "h"},
233 {"yes", INC_KW_SPARSE, "s"},
234 {"no", INC_KW_SPARSE, "0"},
235 {"yes", INC_KW_HARDLINK, "0"},
236 {"no", INC_KW_HARDLINK, "H"},
237 {"always", INC_KW_REPLACE, "a"},
238 {"ifnewer", INC_KW_REPLACE, "w"},
239 {"never", INC_KW_REPLACE, "n"},
240 {"yes", INC_KW_READFIFO, "r"},
241 {"no", INC_KW_READFIFO, "0"},
242 {"yes", INC_KW_PORTABLE, "p"},
243 {"no", INC_KW_PORTABLE, "0"},
244 {"yes", INC_KW_MTIMEONLY, "m"},
245 {"no", INC_KW_MTIMEONLY, "0"},
246 {"yes", INC_KW_KEEPATIME, "k"},
247 {"no", INC_KW_KEEPATIME, "0"},
248 {"yes", INC_KW_EXCLUDE, "e"},
249 {"no", INC_KW_EXCLUDE, "0"},
250 {"yes", INC_KW_ACL, "A"},
251 {"no", INC_KW_ACL, "0"},
252 {"yes", INC_KW_IGNORECASE, "i"},
253 {"no", INC_KW_IGNORECASE, "0"},
254 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
255 {"no", INC_KW_HFSPLUS, "0"},
256 {"yes", INC_KW_NOATIME, "K"},
257 {"no", INC_KW_NOATIME, "0"},
258 {"yes", INC_KW_ENHANCEDWILD, "K"},
259 {"no", INC_KW_ENHANCEDWILD, "0"},
260 {"yes", INC_KW_CHKCHANGES, "c"},
261 {"no", INC_KW_CHKCHANGES, "0"},
262 {"yes", INC_KW_HONOR_NODUMP, "N"},
263 {"no", INC_KW_HONOR_NODUMP, "0"},
270 * Scan for right hand side of Include options (keyword=option) is
271 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
272 * Whatever is found is concatenated to the opts string.
273 * This code is also used inside an Options resource.
275 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
279 int lcopts = lc->options;
281 option[0] = 0; /* default option = none */
282 option[2] = 0; /* terminate options */
283 lc->options |= LOPT_STRING; /* force string */
284 token = lex_get_token(lc, T_STRING); /* expect at least one option */
285 if (keyword == INC_KW_VERIFY) { /* special case */
286 /* ***FIXME**** ensure these are in permitted set */
287 bstrncat(opts, "V", optlen); /* indicate Verify */
288 bstrncat(opts, lc->str, optlen);
289 bstrncat(opts, ":", optlen); /* terminate it */
290 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
291 } else if (keyword == INC_KW_ACCURATE) { /* special case */
292 /* ***FIXME**** ensure these are in permitted set */
293 bstrncat(opts, "C", optlen); /* indicate Accurate */
294 bstrncat(opts, lc->str, optlen);
295 bstrncat(opts, ":", optlen); /* terminate it */
296 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
297 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
298 if (!is_an_integer(lc->str)) {
299 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
301 bstrncat(opts, "P", optlen); /* indicate strip path */
302 bstrncat(opts, lc->str, optlen);
303 bstrncat(opts, ":", optlen); /* terminate it */
304 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
306 * Standard keyword options for Include/Exclude
309 for (i=0; FS_options[i].name; i++) {
310 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
311 /* NOTE! maximum 2 letters here or increase option[3] */
312 option[0] = FS_options[i].option[0];
313 option[1] = FS_options[i].option[1];
319 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
320 } else { /* add option */
321 bstrncat(opts, option, optlen);
322 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
325 lc->options = lcopts;
327 /* If option terminated by comma, eat it */
329 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
335 * Store FileSet Include/Exclude info
336 * NEW style includes are handled in store_newinc()
338 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
343 * Decide if we are doing a new Include or an old include. The
344 * new Include is followed immediately by open brace, whereas the
345 * old include has options following the Include.
347 token = lex_get_token(lc, T_SKIP_EOL);
348 if (token == T_BOB) {
349 store_newinc(lc, item, index, pass);
352 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
357 * Store NEW style FileSet FInclude/FExclude info
359 * Note, when this routine is called, we are inside a FileSet
360 * resource. We treat the Include/Execlude like a sort of
361 * mini-resource within the FileSet resource.
363 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
369 if (!res_all.res_fs.have_MD5) {
370 MD5Init(&res_all.res_fs.md5c);
371 res_all.res_fs.have_MD5 = true;
373 memset(&res_incexe, 0, sizeof(INCEXE));
374 res_all.res_fs.new_include = true;
375 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
376 if (token == T_EOB) {
379 if (token != T_IDENTIFIER) {
380 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
382 for (i=0; newinc_items[i].name; i++) {
383 options = strcasecmp(lc->str, "options") == 0;
384 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
386 token = lex_get_token(lc, T_SKIP_EOL);
387 if (token != T_EQUALS) {
388 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
391 /* Call item handler */
392 newinc_items[i].handler(lc, &newinc_items[i], i, pass);
398 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
402 incexe = (INCEXE *)malloc(sizeof(INCEXE));
403 memcpy(incexe, &res_incexe, sizeof(INCEXE));
404 memset(&res_incexe, 0, sizeof(INCEXE));
405 if (item->code == 0) { /* include */
406 if (res_all.res_fs.num_includes == 0) {
407 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
409 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
410 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
412 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
413 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
414 } else { /* exclude */
415 if (res_all.res_fs.num_excludes == 0) {
416 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
418 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
419 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
421 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
422 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
426 set_bit(index, res_all.hdr.item_present);
430 /* Store regex info */
431 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
439 token = lex_get_token(lc, T_SKIP_EOL);
441 /* Pickup regex string
445 case T_UNQUOTED_STRING:
446 case T_QUOTED_STRING:
447 rc = regcomp(&preg, lc->str, REG_EXTENDED);
449 regerror(rc, &preg, prbuf, sizeof(prbuf));
451 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
455 if (item->code == 1) {
457 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
458 newsize = res_incexe.current_opts->regexdir.size();
459 } else if (item->code == 2) {
461 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
462 newsize = res_incexe.current_opts->regexfile.size();
465 res_incexe.current_opts->regex.append(bstrdup(lc->str));
466 newsize = res_incexe.current_opts->regex.size();
468 Dmsg4(900, "set %s %p size=%d %s\n",
469 type, res_incexe.current_opts, newsize, lc->str);
472 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
478 /* Store Base info */
479 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
483 token = lex_get_token(lc, T_NAME);
486 * Pickup Base Job Name
488 res_incexe.current_opts->base.append(bstrdup(lc->str));
493 /* Store reader info */
494 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
498 token = lex_get_token(lc, T_NAME);
501 * Pickup plugin command
503 res_incexe.current_opts->plugin = bstrdup(lc->str);
509 /* Store reader info */
510 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
514 token = lex_get_token(lc, T_NAME);
517 * Pickup reader command
519 res_incexe.current_opts->reader = bstrdup(lc->str);
524 /* Store writer innfo */
525 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
529 token = lex_get_token(lc, T_NAME);
532 * Pickup writer command
534 res_incexe.current_opts->writer = bstrdup(lc->str);
541 /* Store Wild-card info */
542 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
548 token = lex_get_token(lc, T_SKIP_EOL);
551 * Pickup Wild-card string
555 case T_UNQUOTED_STRING:
556 case T_QUOTED_STRING:
557 if (item->code == 1) {
559 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
560 newsize = res_incexe.current_opts->wilddir.size();
561 } else if (item->code == 2) {
562 if (strpbrk(lc->str, "/\\") != NULL) {
564 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
565 newsize = res_incexe.current_opts->wildfile.size();
568 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
569 newsize = res_incexe.current_opts->wildbase.size();
573 res_incexe.current_opts->wild.append(bstrdup(lc->str));
574 newsize = res_incexe.current_opts->wild.size();
576 Dmsg4(9, "set %s %p size=%d %s\n",
577 type, res_incexe.current_opts, newsize, lc->str);
580 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
586 /* Store fstype info */
587 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
591 token = lex_get_token(lc, T_SKIP_EOL);
593 /* Pickup fstype string */
596 case T_UNQUOTED_STRING:
597 case T_QUOTED_STRING:
598 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
599 Dmsg3(900, "set fstype %p size=%d %s\n",
600 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
603 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
609 /* Store ignoredir info */
610 static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass)
614 token = lex_get_token(lc, T_NAME);
617 * Pickup reader command
619 res_incexe.current_opts->ignoredir = bstrdup(lc->str);
624 /* Store drivetype info */
625 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
629 token = lex_get_token(lc, T_SKIP_EOL);
631 /* Pickup drivetype string */
634 case T_UNQUOTED_STRING:
635 case T_QUOTED_STRING:
636 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
637 Dmsg3(900, "set drivetype %p size=%d %s\n",
638 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
641 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
648 * Store Filename info. Note, for minor efficiency reasons, we
649 * always increase the name buffer by 10 items because we expect
650 * to add more entries.
652 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
657 token = lex_get_token(lc, T_SKIP_EOL);
659 /* Pickup Filename string
663 case T_UNQUOTED_STRING:
664 if (strchr(lc->str, '\\')) {
665 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
668 case T_QUOTED_STRING:
669 if (res_all.res_fs.have_MD5) {
670 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
672 incexe = &res_incexe;
673 if (incexe->name_list.size() == 0) {
674 incexe->name_list.init(10, true);
676 incexe->name_list.append(bstrdup(lc->str));
677 Dmsg1(900, "Add to name_list %s\n", lc->str);
680 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
687 * Store Filename info. Note, for minor efficiency reasons, we
688 * always increase the name buffer by 10 items because we expect
689 * to add more entries.
691 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass)
696 token = lex_get_token(lc, T_SKIP_EOL);
698 /* Pickup Filename string
702 case T_UNQUOTED_STRING:
703 if (strchr(lc->str, '\\')) {
704 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
707 case T_QUOTED_STRING:
708 if (res_all.res_fs.have_MD5) {
709 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
711 incexe = &res_incexe;
712 if (incexe->plugin_list.size() == 0) {
713 incexe->plugin_list.init(10, true);
715 incexe->plugin_list.append(bstrdup(lc->str));
716 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
719 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
728 * Come here when Options seen in Include/Exclude
730 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
734 token = lex_get_token(lc, T_SKIP_EOL);
735 if (token != T_BOB) {
736 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
740 setup_current_opts();
743 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
744 if (token == T_EOL) {
747 if (token == T_EOB) {
750 if (token != T_IDENTIFIER) {
751 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
753 for (i=0; options_items[i].name; i++) {
754 if (strcasecmp(options_items[i].name, lc->str) == 0) {
755 token = lex_get_token(lc, T_SKIP_EOL);
756 if (token != T_EQUALS) {
757 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
759 /* Call item handler */
760 options_items[i].handler(lc, &options_items[i], i, pass);
766 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
773 * New style options come here
775 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
782 keyword = INC_KW_NONE;
783 /* Look up the keyword */
784 for (i=0; FS_option_kw[i].name; i++) {
785 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
786 keyword = FS_option_kw[i].token;
790 if (keyword == INC_KW_NONE) {
791 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
793 /* Now scan for the value */
794 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
796 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
797 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
804 /* If current_opts not defined, create first entry */
805 static void setup_current_opts(void)
807 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
808 memset(fo, 0, sizeof(FOPTS));
809 fo->regex.init(1, true);
810 fo->regexdir.init(1, true);
811 fo->regexfile.init(1, true);
812 fo->wild.init(1, true);
813 fo->wilddir.init(1, true);
814 fo->wildfile.init(1, true);
815 fo->wildbase.init(1, true);
816 fo->base.init(1, true);
817 fo->fstype.init(1, true);
818 fo->drivetype.init(1, true);
819 res_incexe.current_opts = fo;
820 if (res_incexe.num_opts == 0) {
821 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
823 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
824 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
826 res_incexe.opts_list[res_incexe.num_opts++] = fo;