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 {"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 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
232 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
233 {"yes", INC_KW_ONEFS, "0"},
234 {"no", INC_KW_ONEFS, "f"},
235 {"yes", INC_KW_RECURSE, "0"},
236 {"no", INC_KW_RECURSE, "h"},
237 {"yes", INC_KW_SPARSE, "s"},
238 {"no", INC_KW_SPARSE, "0"},
239 {"yes", INC_KW_HARDLINK, "0"},
240 {"no", INC_KW_HARDLINK, "H"},
241 {"always", INC_KW_REPLACE, "a"},
242 {"ifnewer", INC_KW_REPLACE, "w"},
243 {"never", INC_KW_REPLACE, "n"},
244 {"yes", INC_KW_READFIFO, "r"},
245 {"no", INC_KW_READFIFO, "0"},
246 {"yes", INC_KW_PORTABLE, "p"},
247 {"no", INC_KW_PORTABLE, "0"},
248 {"yes", INC_KW_MTIMEONLY, "m"},
249 {"no", INC_KW_MTIMEONLY, "0"},
250 {"yes", INC_KW_KEEPATIME, "k"},
251 {"no", INC_KW_KEEPATIME, "0"},
252 {"yes", INC_KW_EXCLUDE, "e"},
253 {"no", INC_KW_EXCLUDE, "0"},
254 {"yes", INC_KW_ACL, "A"},
255 {"no", INC_KW_ACL, "0"},
256 {"yes", INC_KW_IGNORECASE, "i"},
257 {"no", INC_KW_IGNORECASE, "0"},
258 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
259 {"no", INC_KW_HFSPLUS, "0"},
260 {"yes", INC_KW_NOATIME, "K"},
261 {"no", INC_KW_NOATIME, "0"},
262 {"yes", INC_KW_ENHANCEDWILD, "K"},
263 {"no", INC_KW_ENHANCEDWILD, "0"},
264 {"yes", INC_KW_CHKCHANGES, "c"},
265 {"no", INC_KW_CHKCHANGES, "0"},
266 {"yes", INC_KW_HONOR_NODUMP, "N"},
267 {"no", INC_KW_HONOR_NODUMP, "0"},
268 {"yes", INC_KW_XATTR, "X"},
269 {"no", INC_KW_XATTR, "0"},
276 * Scan for right hand side of Include options (keyword=option) is
277 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
278 * Whatever is found is concatenated to the opts string.
279 * This code is also used inside an Options resource.
281 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
285 int lcopts = lc->options;
287 option[0] = 0; /* default option = none */
288 option[2] = 0; /* terminate options */
289 lc->options |= LOPT_STRING; /* force string */
290 token = lex_get_token(lc, T_STRING); /* expect at least one option */
291 if (keyword == INC_KW_VERIFY) { /* special case */
292 /* ***FIXME**** ensure these are in permitted set */
293 bstrncat(opts, "V", optlen); /* indicate Verify */
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_ACCURATE) { /* special case */
298 /* ***FIXME**** ensure these are in permitted set */
299 bstrncat(opts, "C", optlen); /* indicate Accurate */
300 bstrncat(opts, lc->str, optlen);
301 bstrncat(opts, ":", optlen); /* terminate it */
302 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
303 } else if (keyword == INC_KW_BASEJOB) { /* special case */
304 /* ***FIXME**** ensure these are in permitted set */
305 bstrncat(opts, "J", optlen); /* indicate BaseJob */
306 bstrncat(opts, lc->str, optlen);
307 bstrncat(opts, ":", optlen); /* terminate it */
308 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
309 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
310 if (!is_an_integer(lc->str)) {
311 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
313 bstrncat(opts, "P", optlen); /* indicate strip path */
314 bstrncat(opts, lc->str, optlen);
315 bstrncat(opts, ":", optlen); /* terminate it */
316 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
318 * Standard keyword options for Include/Exclude
321 for (i=0; FS_options[i].name; i++) {
322 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
323 /* NOTE! maximum 2 letters here or increase option[3] */
324 option[0] = FS_options[i].option[0];
325 option[1] = FS_options[i].option[1];
331 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
332 } else { /* add option */
333 bstrncat(opts, option, optlen);
334 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
337 lc->options = lcopts;
339 /* If option terminated by comma, eat it */
341 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
347 * Store FileSet Include/Exclude info
348 * new style includes are handled in store_newinc()
350 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
355 * Decide if we are doing a new Include or an old include. The
356 * new Include is followed immediately by open brace, whereas the
357 * old include has options following the Include.
359 token = lex_get_token(lc, T_SKIP_EOL);
360 if (token == T_BOB) {
361 store_newinc(lc, item, index, pass);
364 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
369 * Store new style FileSet Include/Exclude info
371 * Note, when this routine is called, we are inside a FileSet
372 * resource. We treat the Include/Execlude like a sort of
373 * mini-resource within the FileSet resource.
375 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
381 if (!res_all.res_fs.have_MD5) {
382 MD5Init(&res_all.res_fs.md5c);
383 res_all.res_fs.have_MD5 = true;
385 memset(&res_incexe, 0, sizeof(INCEXE));
386 res_all.res_fs.new_include = true;
387 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
388 if (token == T_EOB) {
391 if (token != T_IDENTIFIER) {
392 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
394 for (i=0; newinc_items[i].name; i++) {
395 options = strcasecmp(lc->str, "options") == 0;
396 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
398 token = lex_get_token(lc, T_SKIP_EOL);
399 if (token != T_EQUALS) {
400 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
403 /* Call item handler */
404 newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
410 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
414 incexe = (INCEXE *)malloc(sizeof(INCEXE));
415 memcpy(incexe, &res_incexe, sizeof(INCEXE));
416 memset(&res_incexe, 0, sizeof(INCEXE));
417 if (item->code == 0) { /* include */
418 if (res_all.res_fs.num_includes == 0) {
419 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
421 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
422 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
424 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
425 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
426 } else { /* exclude */
427 if (res_all.res_fs.num_excludes == 0) {
428 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
430 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
431 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
433 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
434 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
438 set_bit(index, res_all.hdr.item_present);
442 /* Store regex info */
443 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
451 token = lex_get_token(lc, T_SKIP_EOL);
453 /* Pickup regex string
457 case T_UNQUOTED_STRING:
458 case T_QUOTED_STRING:
459 rc = regcomp(&preg, lc->str, REG_EXTENDED);
461 regerror(rc, &preg, prbuf, sizeof(prbuf));
463 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
467 if (item->code == 1) {
469 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
470 newsize = res_incexe.current_opts->regexdir.size();
471 } else if (item->code == 2) {
473 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
474 newsize = res_incexe.current_opts->regexfile.size();
477 res_incexe.current_opts->regex.append(bstrdup(lc->str));
478 newsize = res_incexe.current_opts->regex.size();
480 Dmsg4(900, "set %s %p size=%d %s\n",
481 type, res_incexe.current_opts, newsize, lc->str);
484 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
490 /* Store Base info */
491 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
495 token = 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)
510 token = lex_get_token(lc, T_NAME);
513 * Pickup plugin command
515 res_incexe.current_opts->plugin = bstrdup(lc->str);
521 /* Store Wild-card info */
522 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
528 token = lex_get_token(lc, T_SKIP_EOL);
531 * Pickup Wild-card string
535 case T_UNQUOTED_STRING:
536 case T_QUOTED_STRING:
537 if (item->code == 1) {
539 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
540 newsize = res_incexe.current_opts->wilddir.size();
541 } else if (item->code == 2) {
542 if (strpbrk(lc->str, "/\\") != NULL) {
544 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
545 newsize = res_incexe.current_opts->wildfile.size();
548 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
549 newsize = res_incexe.current_opts->wildbase.size();
553 res_incexe.current_opts->wild.append(bstrdup(lc->str));
554 newsize = res_incexe.current_opts->wild.size();
556 Dmsg4(9, "set %s %p size=%d %s\n",
557 type, res_incexe.current_opts, newsize, lc->str);
560 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
566 /* Store fstype info */
567 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
571 token = lex_get_token(lc, T_SKIP_EOL);
573 /* Pickup fstype string */
576 case T_UNQUOTED_STRING:
577 case T_QUOTED_STRING:
578 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
579 Dmsg3(900, "set fstype %p size=%d %s\n",
580 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
583 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
589 /* Store exclude directory containing info */
590 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
595 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
598 token = lex_get_token(lc, T_NAME);
600 res_incexe.ignoredir = bstrdup(lc->str);
605 /* Store drivetype info */
606 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
610 token = lex_get_token(lc, T_SKIP_EOL);
612 /* Pickup drivetype string */
615 case T_UNQUOTED_STRING:
616 case T_QUOTED_STRING:
617 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
618 Dmsg3(900, "set drivetype %p size=%d %s\n",
619 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
622 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
629 * Store Filename info. Note, for minor efficiency reasons, we
630 * always increase the name buffer by 10 items because we expect
631 * to add more entries.
633 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
638 token = lex_get_token(lc, T_SKIP_EOL);
640 /* Pickup Filename string
644 case T_UNQUOTED_STRING:
645 if (strchr(lc->str, '\\')) {
646 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
649 case T_QUOTED_STRING:
650 if (res_all.res_fs.have_MD5) {
651 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
653 incexe = &res_incexe;
654 if (incexe->name_list.size() == 0) {
655 incexe->name_list.init(10, true);
657 incexe->name_list.append(bstrdup(lc->str));
658 Dmsg1(900, "Add to name_list %s\n", lc->str);
661 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
668 * Store Filename info. Note, for minor efficiency reasons, we
669 * always increase the name buffer by 10 items because we expect
670 * to add more entries.
672 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
678 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
681 token = lex_get_token(lc, T_SKIP_EOL);
683 /* Pickup Filename string
687 case T_UNQUOTED_STRING:
688 if (strchr(lc->str, '\\')) {
689 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
692 case T_QUOTED_STRING:
693 if (res_all.res_fs.have_MD5) {
694 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
696 incexe = &res_incexe;
697 if (incexe->plugin_list.size() == 0) {
698 incexe->plugin_list.init(10, true);
700 incexe->plugin_list.append(bstrdup(lc->str));
701 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
704 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
714 * Come here when Options seen in Include/Exclude
716 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
721 scan_err0(lc, _("Options section not permitted in Exclude\n"));
724 token = lex_get_token(lc, T_SKIP_EOL);
725 if (token != T_BOB) {
726 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
730 setup_current_opts();
733 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
734 if (token == T_EOL) {
737 if (token == T_EOB) {
740 if (token != T_IDENTIFIER) {
741 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
743 for (i=0; options_items[i].name; i++) {
744 if (strcasecmp(options_items[i].name, lc->str) == 0) {
745 token = lex_get_token(lc, T_SKIP_EOL);
746 if (token != T_EQUALS) {
747 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
749 /* Call item handler */
750 options_items[i].handler(lc, &options_items[i], i, pass);
756 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
763 * New style options come here
765 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
772 keyword = INC_KW_NONE;
773 /* Look up the keyword */
774 for (i=0; FS_option_kw[i].name; i++) {
775 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
776 keyword = FS_option_kw[i].token;
780 if (keyword == INC_KW_NONE) {
781 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
783 /* Now scan for the value */
784 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
786 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
787 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
794 /* If current_opts not defined, create first entry */
795 static void setup_current_opts(void)
797 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
798 memset(fo, 0, sizeof(FOPTS));
799 fo->regex.init(1, true);
800 fo->regexdir.init(1, true);
801 fo->regexfile.init(1, true);
802 fo->wild.init(1, true);
803 fo->wilddir.init(1, true);
804 fo->wildfile.init(1, true);
805 fo->wildbase.init(1, true);
806 fo->base.init(1, true);
807 fo->fstype.init(1, true);
808 fo->drivetype.init(1, true);
809 res_incexe.current_opts = fo;
810 if (res_incexe.num_opts == 0) {
811 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
813 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
814 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
816 res_incexe.opts_list[res_incexe.num_opts++] = fo;