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 token = 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 token = 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)
496 token = lex_get_token(lc, T_NAME);
499 * Pickup Base Job Name
501 res_incexe.current_opts->base.append(bstrdup(lc->str));
506 /* Store reader info */
507 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
511 token = lex_get_token(lc, T_NAME);
514 * Pickup plugin command
516 res_incexe.current_opts->plugin = bstrdup(lc->str);
522 /* Store Wild-card info */
523 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
529 token = lex_get_token(lc, T_SKIP_EOL);
532 * Pickup Wild-card string
536 case T_UNQUOTED_STRING:
537 case T_QUOTED_STRING:
538 if (item->code == 1) {
540 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
541 newsize = res_incexe.current_opts->wilddir.size();
542 } else if (item->code == 2) {
543 if (strpbrk(lc->str, "/\\") != NULL) {
545 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
546 newsize = res_incexe.current_opts->wildfile.size();
549 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
550 newsize = res_incexe.current_opts->wildbase.size();
554 res_incexe.current_opts->wild.append(bstrdup(lc->str));
555 newsize = res_incexe.current_opts->wild.size();
557 Dmsg4(9, "set %s %p size=%d %s\n",
558 type, res_incexe.current_opts, newsize, lc->str);
561 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
567 /* Store fstype info */
568 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
572 token = lex_get_token(lc, T_SKIP_EOL);
574 /* Pickup fstype string */
577 case T_UNQUOTED_STRING:
578 case T_QUOTED_STRING:
579 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
580 Dmsg3(900, "set fstype %p size=%d %s\n",
581 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
584 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
590 /* Store exclude directory containing info */
591 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
596 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
599 token = lex_get_token(lc, T_NAME);
601 res_incexe.ignoredir = bstrdup(lc->str);
606 /* Store drivetype info */
607 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
611 token = lex_get_token(lc, T_SKIP_EOL);
613 /* Pickup drivetype string */
616 case T_UNQUOTED_STRING:
617 case T_QUOTED_STRING:
618 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
619 Dmsg3(900, "set drivetype %p size=%d %s\n",
620 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
623 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
630 * Store Filename info. Note, for minor efficiency reasons, we
631 * always increase the name buffer by 10 items because we expect
632 * to add more entries.
634 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
639 token = lex_get_token(lc, T_SKIP_EOL);
641 /* Pickup Filename string
645 case T_UNQUOTED_STRING:
646 if (strchr(lc->str, '\\')) {
647 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
650 case T_QUOTED_STRING:
651 if (res_all.res_fs.have_MD5) {
652 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
654 incexe = &res_incexe;
655 if (incexe->name_list.size() == 0) {
656 incexe->name_list.init(10, true);
658 incexe->name_list.append(bstrdup(lc->str));
659 Dmsg1(900, "Add to name_list %s\n", lc->str);
662 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
669 * Store Filename info. Note, for minor efficiency reasons, we
670 * always increase the name buffer by 10 items because we expect
671 * to add more entries.
673 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
679 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
682 token = lex_get_token(lc, T_SKIP_EOL);
684 /* Pickup Filename string
688 case T_UNQUOTED_STRING:
689 if (strchr(lc->str, '\\')) {
690 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
693 case T_QUOTED_STRING:
694 if (res_all.res_fs.have_MD5) {
695 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
697 incexe = &res_incexe;
698 if (incexe->plugin_list.size() == 0) {
699 incexe->plugin_list.init(10, true);
701 incexe->plugin_list.append(bstrdup(lc->str));
702 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
705 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
715 * Come here when Options seen in Include/Exclude
717 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
722 scan_err0(lc, _("Options section not permitted in Exclude\n"));
725 token = lex_get_token(lc, T_SKIP_EOL);
726 if (token != T_BOB) {
727 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
731 setup_current_opts();
734 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
735 if (token == T_EOL) {
738 if (token == T_EOB) {
741 if (token != T_IDENTIFIER) {
742 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
744 for (i=0; options_items[i].name; i++) {
745 if (strcasecmp(options_items[i].name, lc->str) == 0) {
746 token = lex_get_token(lc, T_SKIP_EOL);
747 if (token != T_EQUALS) {
748 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
750 /* Call item handler */
751 options_items[i].handler(lc, &options_items[i], i, pass);
757 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
764 * New style options come here
766 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
773 keyword = INC_KW_NONE;
774 /* Look up the keyword */
775 for (i=0; FS_option_kw[i].name; i++) {
776 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
777 keyword = FS_option_kw[i].token;
781 if (keyword == INC_KW_NONE) {
782 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
784 /* Now scan for the value */
785 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
787 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
788 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
795 /* If current_opts not defined, create first entry */
796 static void setup_current_opts(void)
798 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
799 memset(fo, 0, sizeof(FOPTS));
800 fo->regex.init(1, true);
801 fo->regexdir.init(1, true);
802 fo->regexfile.init(1, true);
803 fo->wild.init(1, true);
804 fo->wilddir.init(1, true);
805 fo->wildfile.init(1, true);
806 fo->wildbase.init(1, true);
807 fo->base.init(1, true);
808 fo->fstype.init(1, true);
809 fo->drivetype.init(1, true);
810 res_incexe.current_opts = fo;
811 if (res_incexe.num_opts == 0) {
812 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
814 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
815 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
817 res_incexe.opts_list[res_incexe.num_opts++] = fo;