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_writer(LEX *lc, RES_ITEM *item, int index, int pass);
62 static void setup_current_opts(void);
65 /* We build the current resource here as we are
66 * scanning the resource configuration definition,
67 * then move it to allocated memory when the resource
71 extern "C" { // work around visual compiler mangling variables
77 extern int res_all_size;
79 /* We build the current new Include and Exclude items here */
80 static INCEXE res_incexe;
83 * new Include/Exclude items
84 * name handler value code flags default_value
86 static RES_ITEM newinc_items[] = {
87 {"file", store_fname, {0}, 0, 0, 0},
88 {"plugin", store_plugin_name, {0}, 0, 0, 0},
89 {"options", options_res, {0}, 0, 0, 0},
90 {NULL, NULL, {0}, 0, 0, 0}
94 * Items that are valid in an Options resource
96 static RES_ITEM options_items[] = {
97 {"compression", store_opts, {0}, 0, 0, 0},
98 {"signature", store_opts, {0}, 0, 0, 0},
99 {"accurate", store_opts, {0}, 0, 0, 0},
100 {"verify", store_opts, {0}, 0, 0, 0},
101 {"onefs", store_opts, {0}, 0, 0, 0},
102 {"recurse", store_opts, {0}, 0, 0, 0},
103 {"sparse", store_opts, {0}, 0, 0, 0},
104 {"hardlinks", store_opts, {0}, 0, 0, 0},
105 {"readfifo", store_opts, {0}, 0, 0, 0},
106 {"replace", store_opts, {0}, 0, 0, 0},
107 {"portable", store_opts, {0}, 0, 0, 0},
108 {"mtimeonly", store_opts, {0}, 0, 0, 0},
109 {"keepatime", store_opts, {0}, 0, 0, 0},
110 {"regex", store_regex, {0}, 0, 0, 0},
111 {"regexdir", store_regex, {0}, 1, 0, 0},
112 {"regexfile", store_regex, {0}, 2, 0, 0},
113 {"base", store_base, {0}, 0, 0, 0},
114 {"wild", store_wild, {0}, 0, 0, 0},
115 {"wilddir", store_wild, {0}, 1, 0, 0},
116 {"wildfile", store_wild, {0}, 2, 0, 0},
117 {"exclude", store_opts, {0}, 0, 0, 0},
118 {"aclsupport", store_opts, {0}, 0, 0, 0},
119 {"plugin", store_plugin, {0}, 0, 0, 0},
120 {"reader", store_reader, {0}, 0, 0, 0},
121 {"writer", store_writer, {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, 0},
129 {"strippath", store_opts, {0}, 0, 0, 0},
130 {NULL, NULL, {0}, 0, 0, 0}
134 /* Define FileSet KeyWord values */
146 INC_KW_REPLACE, /* restore options */
147 INC_KW_READFIFO, /* Causes fifo data to be read */
162 * This is the list of options that can be stored by store_opts
163 * Note, now that the old style Include/Exclude code is gone,
164 * the INC_KW code could be put into the "code" field of the
165 * options given above.
167 static struct s_kw FS_option_kw[] = {
168 {"compression", INC_KW_COMPRESSION},
169 {"signature", INC_KW_DIGEST},
170 {"encryption", INC_KW_ENCRYPTION},
171 {"verify", INC_KW_VERIFY},
172 {"accurate", INC_KW_ACCURATE},
173 {"onefs", INC_KW_ONEFS},
174 {"recurse", INC_KW_RECURSE},
175 {"sparse", INC_KW_SPARSE},
176 {"hardlinks", INC_KW_HARDLINK},
177 {"replace", INC_KW_REPLACE},
178 {"readfifo", INC_KW_READFIFO},
179 {"portable", INC_KW_PORTABLE},
180 {"mtimeonly", INC_KW_MTIMEONLY},
181 {"keepatime", INC_KW_KEEPATIME},
182 {"exclude", INC_KW_EXCLUDE},
183 {"aclsupport", INC_KW_ACL},
184 {"ignorecase", INC_KW_IGNORECASE},
185 {"hfsplussupport", INC_KW_HFSPLUS},
186 {"noatime", INC_KW_NOATIME},
187 {"enhancedwild", INC_KW_ENHANCEDWILD},
188 {"checkfilechanges", INC_KW_CHKCHANGES},
189 {"strippath", INC_KW_STRIPPATH},
193 /* Options for FileSet keywords */
202 * Options permitted for each keyword and resulting value.
203 * The output goes into opts, which are then transmitted to
204 * the FD for application as options to the following list of
207 static struct s_fs_opt FS_options[] = {
208 {"md5", INC_KW_DIGEST, "M"},
209 {"sha1", INC_KW_DIGEST, "S"},
210 {"sha256", INC_KW_DIGEST, "S2"},
211 {"sha512", INC_KW_DIGEST, "S3"},
212 {"gzip", INC_KW_COMPRESSION, "Z6"},
213 {"gzip1", INC_KW_COMPRESSION, "Z1"},
214 {"gzip2", INC_KW_COMPRESSION, "Z2"},
215 {"gzip3", INC_KW_COMPRESSION, "Z3"},
216 {"gzip4", INC_KW_COMPRESSION, "Z4"},
217 {"gzip5", INC_KW_COMPRESSION, "Z5"},
218 {"gzip6", INC_KW_COMPRESSION, "Z6"},
219 {"gzip7", INC_KW_COMPRESSION, "Z7"},
220 {"gzip8", INC_KW_COMPRESSION, "Z8"},
221 {"gzip9", INC_KW_COMPRESSION, "Z9"},
222 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
223 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
224 {"yes", INC_KW_ONEFS, "0"},
225 {"no", INC_KW_ONEFS, "f"},
226 {"yes", INC_KW_RECURSE, "0"},
227 {"no", INC_KW_RECURSE, "h"},
228 {"yes", INC_KW_SPARSE, "s"},
229 {"no", INC_KW_SPARSE, "0"},
230 {"yes", INC_KW_HARDLINK, "0"},
231 {"no", INC_KW_HARDLINK, "H"},
232 {"always", INC_KW_REPLACE, "a"},
233 {"ifnewer", INC_KW_REPLACE, "w"},
234 {"never", INC_KW_REPLACE, "n"},
235 {"yes", INC_KW_READFIFO, "r"},
236 {"no", INC_KW_READFIFO, "0"},
237 {"yes", INC_KW_PORTABLE, "p"},
238 {"no", INC_KW_PORTABLE, "0"},
239 {"yes", INC_KW_MTIMEONLY, "m"},
240 {"no", INC_KW_MTIMEONLY, "0"},
241 {"yes", INC_KW_KEEPATIME, "k"},
242 {"no", INC_KW_KEEPATIME, "0"},
243 {"yes", INC_KW_EXCLUDE, "e"},
244 {"no", INC_KW_EXCLUDE, "0"},
245 {"yes", INC_KW_ACL, "A"},
246 {"no", INC_KW_ACL, "0"},
247 {"yes", INC_KW_IGNORECASE, "i"},
248 {"no", INC_KW_IGNORECASE, "0"},
249 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
250 {"no", INC_KW_HFSPLUS, "0"},
251 {"yes", INC_KW_NOATIME, "K"},
252 {"no", INC_KW_NOATIME, "0"},
253 {"yes", INC_KW_ENHANCEDWILD, "K"},
254 {"no", INC_KW_ENHANCEDWILD, "0"},
255 {"yes", INC_KW_CHKCHANGES, "c"},
256 {"no", INC_KW_CHKCHANGES, "0"},
263 * Scan for right hand side of Include options (keyword=option) is
264 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
265 * Whatever is found is concatenated to the opts string.
266 * This code is also used inside an Options resource.
268 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
272 int lcopts = lc->options;
274 option[0] = 0; /* default option = none */
275 option[2] = 0; /* terminate options */
276 lc->options |= LOPT_STRING; /* force string */
277 token = lex_get_token(lc, T_STRING); /* expect at least one option */
278 if (keyword == INC_KW_VERIFY) { /* special case */
279 /* ***FIXME**** ensure these are in permitted set */
280 bstrncat(opts, "V", optlen); /* indicate Verify */
281 bstrncat(opts, lc->str, optlen);
282 bstrncat(opts, ":", optlen); /* terminate it */
283 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
284 } else if (keyword == INC_KW_ACCURATE) { /* special case */
285 /* ***FIXME**** ensure these are in permitted set */
286 bstrncat(opts, "C", optlen); /* indicate Accurate */
287 bstrncat(opts, lc->str, optlen);
288 bstrncat(opts, ":", optlen); /* terminate it */
289 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
290 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
291 if (!is_an_integer(lc->str)) {
292 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
294 bstrncat(opts, "P", optlen); /* indicate strip path */
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);
299 * Standard keyword options for Include/Exclude
302 for (i=0; FS_options[i].name; i++) {
303 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
304 /* NOTE! maximum 2 letters here or increase option[3] */
305 option[0] = FS_options[i].option[0];
306 option[1] = FS_options[i].option[1];
312 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
313 } else { /* add option */
314 bstrncat(opts, option, optlen);
315 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
318 lc->options = lcopts;
320 /* If option terminated by comma, eat it */
322 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
328 * Store FileSet Include/Exclude info
329 * NEW style includes are handled in store_newinc()
331 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
336 * Decide if we are doing a new Include or an old include. The
337 * new Include is followed immediately by open brace, whereas the
338 * old include has options following the Include.
340 token = lex_get_token(lc, T_SKIP_EOL);
341 if (token == T_BOB) {
342 store_newinc(lc, item, index, pass);
345 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
350 * Store NEW style FileSet FInclude/FExclude info
352 * Note, when this routine is called, we are inside a FileSet
353 * resource. We treat the Include/Execlude like a sort of
354 * mini-resource within the FileSet resource.
356 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
362 if (!res_all.res_fs.have_MD5) {
363 MD5Init(&res_all.res_fs.md5c);
364 res_all.res_fs.have_MD5 = true;
366 memset(&res_incexe, 0, sizeof(INCEXE));
367 res_all.res_fs.new_include = true;
368 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
369 if (token == T_EOB) {
372 if (token != T_IDENTIFIER) {
373 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
375 for (i=0; newinc_items[i].name; i++) {
376 options = strcasecmp(lc->str, "options") == 0;
377 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
379 token = lex_get_token(lc, T_SKIP_EOL);
380 if (token != T_EQUALS) {
381 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
384 /* Call item handler */
385 newinc_items[i].handler(lc, &newinc_items[i], i, pass);
391 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
395 incexe = (INCEXE *)malloc(sizeof(INCEXE));
396 memcpy(incexe, &res_incexe, sizeof(INCEXE));
397 memset(&res_incexe, 0, sizeof(INCEXE));
398 if (item->code == 0) { /* include */
399 if (res_all.res_fs.num_includes == 0) {
400 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
402 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
403 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
405 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
406 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
407 } else { /* exclude */
408 if (res_all.res_fs.num_excludes == 0) {
409 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
411 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
412 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
414 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
415 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
419 set_bit(index, res_all.hdr.item_present);
423 /* Store regex info */
424 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
432 token = lex_get_token(lc, T_SKIP_EOL);
434 /* Pickup regex string
438 case T_UNQUOTED_STRING:
439 case T_QUOTED_STRING:
440 rc = regcomp(&preg, lc->str, REG_EXTENDED);
442 regerror(rc, &preg, prbuf, sizeof(prbuf));
444 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
448 if (item->code == 1) {
450 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
451 newsize = res_incexe.current_opts->regexdir.size();
452 } else if (item->code == 2) {
454 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
455 newsize = res_incexe.current_opts->regexfile.size();
458 res_incexe.current_opts->regex.append(bstrdup(lc->str));
459 newsize = res_incexe.current_opts->regex.size();
461 Dmsg4(900, "set %s %p size=%d %s\n",
462 type, res_incexe.current_opts, newsize, lc->str);
465 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
471 /* Store Base info */
472 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
476 token = lex_get_token(lc, T_NAME);
479 * Pickup Base Job Name
481 res_incexe.current_opts->base.append(bstrdup(lc->str));
486 /* Store reader info */
487 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
491 token = lex_get_token(lc, T_NAME);
494 * Pickup plugin command
496 res_incexe.current_opts->plugin = bstrdup(lc->str);
502 /* Store reader info */
503 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
507 token = lex_get_token(lc, T_NAME);
510 * Pickup reader command
512 res_incexe.current_opts->reader = bstrdup(lc->str);
517 /* Store writer innfo */
518 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
522 token = lex_get_token(lc, T_NAME);
525 * Pickup writer command
527 res_incexe.current_opts->writer = bstrdup(lc->str);
534 /* Store Wild-card info */
535 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
541 token = lex_get_token(lc, T_SKIP_EOL);
544 * Pickup Wild-card string
548 case T_UNQUOTED_STRING:
549 case T_QUOTED_STRING:
550 if (item->code == 1) {
552 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
553 newsize = res_incexe.current_opts->wilddir.size();
554 } else if (item->code == 2) {
555 if (strpbrk(lc->str, "/\\") != NULL) {
557 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
558 newsize = res_incexe.current_opts->wildfile.size();
561 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
562 newsize = res_incexe.current_opts->wildbase.size();
566 res_incexe.current_opts->wild.append(bstrdup(lc->str));
567 newsize = res_incexe.current_opts->wild.size();
569 Dmsg4(9, "set %s %p size=%d %s\n",
570 type, res_incexe.current_opts, newsize, lc->str);
573 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
579 /* Store fstype info */
580 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
584 token = lex_get_token(lc, T_SKIP_EOL);
586 /* Pickup fstype string */
589 case T_UNQUOTED_STRING:
590 case T_QUOTED_STRING:
591 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
592 Dmsg3(900, "set fstype %p size=%d %s\n",
593 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
596 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
602 /* Store drivetype info */
603 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
607 token = lex_get_token(lc, T_SKIP_EOL);
609 /* Pickup drivetype string */
612 case T_UNQUOTED_STRING:
613 case T_QUOTED_STRING:
614 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
615 Dmsg3(900, "set drivetype %p size=%d %s\n",
616 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
619 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
626 * Store Filename info. Note, for minor efficiency reasons, we
627 * always increase the name buffer by 10 items because we expect
628 * to add more entries.
630 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
635 token = lex_get_token(lc, T_SKIP_EOL);
637 /* Pickup Filename string
641 case T_UNQUOTED_STRING:
642 if (strchr(lc->str, '\\')) {
643 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
646 case T_QUOTED_STRING:
647 if (res_all.res_fs.have_MD5) {
648 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
650 incexe = &res_incexe;
651 if (incexe->name_list.size() == 0) {
652 incexe->name_list.init(10, true);
654 incexe->name_list.append(bstrdup(lc->str));
655 Dmsg1(900, "Add to name_list %s\n", lc->str);
658 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
665 * Store Filename info. Note, for minor efficiency reasons, we
666 * always increase the name buffer by 10 items because we expect
667 * to add more entries.
669 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass)
674 token = lex_get_token(lc, T_SKIP_EOL);
676 /* Pickup Filename string
680 case T_UNQUOTED_STRING:
681 if (strchr(lc->str, '\\')) {
682 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
685 case T_QUOTED_STRING:
686 if (res_all.res_fs.have_MD5) {
687 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
689 incexe = &res_incexe;
690 if (incexe->plugin_list.size() == 0) {
691 incexe->plugin_list.init(10, true);
693 incexe->plugin_list.append(bstrdup(lc->str));
694 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
697 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
706 * Come here when Options seen in Include/Exclude
708 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
712 token = lex_get_token(lc, T_SKIP_EOL);
713 if (token != T_BOB) {
714 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
718 setup_current_opts();
721 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
722 if (token == T_EOL) {
725 if (token == T_EOB) {
728 if (token != T_IDENTIFIER) {
729 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
731 for (i=0; options_items[i].name; i++) {
732 if (strcasecmp(options_items[i].name, lc->str) == 0) {
733 token = lex_get_token(lc, T_SKIP_EOL);
734 if (token != T_EQUALS) {
735 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
737 /* Call item handler */
738 options_items[i].handler(lc, &options_items[i], i, pass);
744 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
751 * New style options come here
753 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
760 keyword = INC_KW_NONE;
761 /* Look up the keyword */
762 for (i=0; FS_option_kw[i].name; i++) {
763 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
764 keyword = FS_option_kw[i].token;
768 if (keyword == INC_KW_NONE) {
769 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
771 /* Now scan for the value */
772 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
774 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
775 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
782 /* If current_opts not defined, create first entry */
783 static void setup_current_opts(void)
785 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
786 memset(fo, 0, sizeof(FOPTS));
787 fo->regex.init(1, true);
788 fo->regexdir.init(1, true);
789 fo->regexfile.init(1, true);
790 fo->wild.init(1, true);
791 fo->wilddir.init(1, true);
792 fo->wildfile.init(1, true);
793 fo->wildbase.init(1, true);
794 fo->base.init(1, true);
795 fo->fstype.init(1, true);
796 fo->drivetype.init(1, true);
797 res_incexe.current_opts = fo;
798 if (res_incexe.num_opts == 0) {
799 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
801 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
802 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
804 res_incexe.opts_list[res_incexe.num_opts++] = fo;