2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Configuration file parser for new and old Include and
23 * Kern Sibbald, March MMIII
30 #include "lib/bregex.h"
35 /* Forward referenced subroutines */
37 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
39 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
40 void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
41 void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
42 void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
43 void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass);
44 void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
45 void store_lopts(LEX *lc, RES_ITEM *item, int index, int pass);
46 void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
47 void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
48 static void setup_current_opts(void);
50 /* Include and Exclude items */
51 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
52 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
53 static void store_options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
54 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
57 /* We build the current resource here as we are
58 * scanning the resource configuration definition,
59 * then move it to allocated memory when the resource
63 extern "C" { // work around visual compiler mangling variables
69 extern int32_t res_all_size;
71 /* We build the current new Include and Exclude items here */
72 static INCEXE res_incexe;
75 * new Include/Exclude items
76 * name handler value code flags default_value
78 RES_ITEM2 newinc_items[] = {
79 {"File", store_fname, {0}, 0, 0, 0},
80 {"Plugin", store_plugin_name, {0}, 0, 0, 0},
81 {"ExcludeDirContaining", store_excludedir, {0}, 0, 0, 0},
82 {"Options", store_options_res, {0}, 0, 0, 0},
83 {NULL, NULL, {0}, 0, 0, 0}
87 * Items that are valid in an Options resource
89 * name handler value code flags default_value
91 * Encryption in FS_option_kw table ???
92 * ReadFifo not in FS_option_kw table ???
95 RES_ITEM options_items[] = {
96 {"Compression", store_opts, {0}, 0, INC_KW_COMPRESSION, 0},
97 {"Signature", store_opts, {0}, 0, INC_KW_DIGEST, 0},
98 {"OneFs", store_opts, {0}, 0, INC_KW_ONEFS, 0},
99 {"Recurse", store_opts, {0}, 0, INC_KW_RECURSE, 0},
100 {"Sparse", store_opts, {0}, 0, INC_KW_SPARSE, 0},
101 {"HardLinks", store_opts, {0}, 0, INC_KW_HARDLINK, 0},
102 {"Replace", store_opts, {0}, 0, INC_KW_REPLACE, 0},
103 {"Portable", store_opts, {0}, 0, INC_KW_PORTABLE, 0},
104 {"MtimeOnly", store_opts, {0}, 0, INC_KW_MTIMEONLY, 0},
105 {"KeepAtime", store_opts, {0}, 0, INC_KW_KEEPATIME, 0},
106 {"Exclude", store_opts, {0}, 0, INC_KW_EXCLUDE, 0},
107 {"AclSupport", store_opts, {0}, 0, INC_KW_ACL, 0},
108 {"IgnoreCase", store_opts, {0}, 0, INC_KW_IGNORECASE, 0},
109 {"HfsPlusSupport", store_opts, {0}, 0, INC_KW_HFSPLUS, 0},
110 {"NoAtime", store_opts, {0}, 0, INC_KW_NOATIME, 0},
111 {"EnhancedWild", store_opts, {0}, 0, INC_KW_ENHANCEDWILD, 0},
112 {"CheckFileChanges",store_opts, {0}, 0, INC_KW_CHKCHANGES, 1},
113 {"HonorNoDumpFlag", store_opts, {0}, 0, INC_KW_HONOR_NODUMP, 0},
114 {"XattrSupport", store_opts, {0}, 0, INC_KW_XATTR, 0},
115 {"ReadFifo", store_opts, {0}, 0, INC_KW_READFIFO, 0},
116 {"BaseJob", store_lopts, {0}, 'J', INC_KW_BASEJOB, 0},
117 {"Accurate", store_lopts, {0}, 'C', INC_KW_ACCURATE, 0},
118 {"Verify", store_lopts, {0}, 'V', INC_KW_VERIFY, 0},
119 {"StripPath", store_lopts, {0}, 'P', INC_KW_STRIPPATH, 0},
120 {"Regex", store_regex, {0}, 0, 0, 0},
121 {"RegexDir", store_regex, {0}, 1, 0, 0},
122 {"RegexFile", store_regex, {0}, 2, 0, 0},
123 {"Base", store_base, {0}, 0, 0, 0},
124 {"Wild", store_wild, {0}, 0, 0, 0},
125 {"WildDir", store_wild, {0}, 1, 0, 0},
126 {"WildFile", store_wild, {0}, 2, 0, 0},
127 {"Plugin", store_plugin, {0}, 0, 0, 0},
128 {"FsType", store_fstype, {0}, 0, 0, 0},
129 {"DriveType", store_drivetype, {0}, 0, 0, 0},
130 {NULL, NULL, {0}, 0, 0, 0}
134 * This is the list of options that can be stored by store_opts
135 * Note, now that the old style Include/Exclude code is gone,
136 * the INC_KW code could be put into the "code" field of the
137 * options given above.
141 s_kw FS_option_kw[] = {
142 {"Compression", INC_KW_COMPRESSION},
143 {"Signature", INC_KW_DIGEST},
144 {"Encryption", INC_KW_ENCRYPTION},
145 {"Verify", INC_KW_VERIFY},
146 {"BaseJob", INC_KW_BASEJOB},
147 {"Accurate", INC_KW_ACCURATE},
148 {"OneFs", INC_KW_ONEFS},
149 {"Recurse", INC_KW_RECURSE},
150 {"Sparse", INC_KW_SPARSE},
151 {"HardLinks", INC_KW_HARDLINK},
152 {"Replace", INC_KW_REPLACE},
153 {"ReadFifo", INC_KW_READFIFO},
154 {"Portable", INC_KW_PORTABLE},
155 {"MtimeOnly", INC_KW_MTIMEONLY},
156 {"KeepAtime", INC_KW_KEEPATIME},
157 {"Exclude", INC_KW_EXCLUDE},
158 {"AclSupport", INC_KW_ACL},
159 {"IgnoreCase", INC_KW_IGNORECASE},
160 {"HfsPlusSupport", INC_KW_HFSPLUS},
161 {"NoAtime", INC_KW_NOATIME},
162 {"EnhancedWild", INC_KW_ENHANCEDWILD},
163 {"CheckFileChanges", INC_KW_CHKCHANGES},
164 {"StripPath", INC_KW_STRIPPATH},
165 {"HonorNoDumpFlag", INC_KW_HONOR_NODUMP},
166 {"XattrSupport", INC_KW_XATTR},
171 * Options permitted for each keyword and resulting value.
172 * The output goes into opts, which are then transmitted to
173 * the FD for application as options to the following list of
176 * Note! all 0's in options must come after the value that
179 * NOTE!! The following long options (see scan_include_options())
185 * name keyword option
187 struct s_fs_opt FS_options[] = {
188 {"Md5", INC_KW_DIGEST, "M"},
189 {"Sha1", INC_KW_DIGEST, "S"},
190 {"Sha256", INC_KW_DIGEST, "S2"},
191 {"Sha512", INC_KW_DIGEST, "S3"},
192 {"Gzip", INC_KW_COMPRESSION, "Z6"},
193 {"Gzip1", INC_KW_COMPRESSION, "Z1"},
194 {"Gzip2", INC_KW_COMPRESSION, "Z2"},
195 {"Gzip3", INC_KW_COMPRESSION, "Z3"},
196 {"Gzip4", INC_KW_COMPRESSION, "Z4"},
197 {"Gzip5", INC_KW_COMPRESSION, "Z5"},
198 {"Gzip6", INC_KW_COMPRESSION, "Z6"},
199 {"Gzip7", INC_KW_COMPRESSION, "Z7"},
200 {"Gzip8", INC_KW_COMPRESSION, "Z8"},
201 {"Gzip9", INC_KW_COMPRESSION, "Z9"},
202 {"Lzo", INC_KW_COMPRESSION, "Zo"},
203 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
204 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
205 {"No", INC_KW_ONEFS, "f"},
206 {"Yes", INC_KW_ONEFS, "0"},
207 {"No", INC_KW_RECURSE, "h"},
208 {"Yes", INC_KW_RECURSE, "0"},
209 {"Yes", INC_KW_SPARSE, "s"},
210 {"No", INC_KW_SPARSE, "0"},
211 {"No", INC_KW_HARDLINK, "H"},
212 {"Yes", INC_KW_HARDLINK, "0"},
213 {"Always", INC_KW_REPLACE, "a"},
214 {"IfNewer", INC_KW_REPLACE, "w"},
215 {"Never", INC_KW_REPLACE, "n"},
216 {"Yes", INC_KW_READFIFO, "r"},
217 {"No", INC_KW_READFIFO, "0"},
218 {"Yes", INC_KW_PORTABLE, "p"},
219 {"No", INC_KW_PORTABLE, "0"},
220 {"Yes", INC_KW_MTIMEONLY, "m"},
221 {"No", INC_KW_MTIMEONLY, "0"},
222 {"Yes", INC_KW_KEEPATIME, "k"},
223 {"No", INC_KW_KEEPATIME, "0"},
224 {"Yes", INC_KW_EXCLUDE, "e"},
225 {"No", INC_KW_EXCLUDE, "0"},
226 {"Yes", INC_KW_ACL, "A"},
227 {"No", INC_KW_ACL, "0"},
228 {"Yes", INC_KW_IGNORECASE, "i"},
229 {"No", INC_KW_IGNORECASE, "0"},
230 {"Yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
231 {"No", INC_KW_HFSPLUS, "0"},
232 {"Yes", INC_KW_NOATIME, "K"},
233 {"No", INC_KW_NOATIME, "0"},
234 {"Yes", INC_KW_ENHANCEDWILD, "K"},
235 {"No", INC_KW_ENHANCEDWILD, "0"},
236 {"Yes", INC_KW_CHKCHANGES, "c"},
237 {"No", INC_KW_CHKCHANGES, "0"},
238 {"Yes", INC_KW_HONOR_NODUMP, "N"},
239 {"No", INC_KW_HONOR_NODUMP, "0"},
240 {"Yes", INC_KW_XATTR, "X"},
241 {"No", INC_KW_XATTR, "0"},
248 * Scan for right hand side of Include options (keyword=option) is
249 * converted into one or two characters. Verify=xxxx is Vxxxx:
250 * Whatever is found is concatenated to the opts string.
251 * This code is also used inside an Options resource.
253 * This function returns true for a long option (terminates with :)
254 * and false for a normal 1 or 2 character option.
256 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
260 int lcopts = lc->options;
262 option[0] = 0; /* default option = none */
263 option[2] = 0; /* terminate options */
264 lc->options |= LOPT_STRING; /* force string */
265 lex_get_token(lc, T_STRING); /* expect at least one option */
267 * ***FIXME**** ensure these are in permitted set
269 if (keyword == INC_KW_VERIFY) { /* special case */
270 bstrncat(opts, "V", optlen); /* indicate Verify */
271 bstrncat(opts, lc->str, optlen);
272 bstrncat(opts, ":", optlen); /* terminate it */
273 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
274 } else if (keyword == INC_KW_ACCURATE) { /* special case */
275 bstrncat(opts, "C", optlen); /* indicate Accurate */
276 bstrncat(opts, lc->str, optlen);
277 bstrncat(opts, ":", optlen); /* terminate it */
278 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
279 } else if (keyword == INC_KW_BASEJOB) { /* special case */
280 bstrncat(opts, "J", optlen); /* indicate BaseJob */
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_STRIPPATH) { /* another special case */
285 if (!is_an_integer(lc->str)) {
286 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
288 bstrncat(opts, "P", optlen); /* indicate strip path */
289 bstrncat(opts, lc->str, optlen);
290 bstrncat(opts, ":", optlen); /* terminate it */
291 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
293 * Standard keyword options for Include/Exclude
296 for (i=0; FS_options[i].name; i++) {
297 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
298 /* NOTE! maximum 2 letters here or increase option[3] */
299 option[0] = FS_options[i].option[0];
300 option[1] = FS_options[i].option[1];
306 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
307 } else { /* add option */
308 bstrncat(opts, option, optlen);
309 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
312 lc->options = lcopts;
314 /* If option terminated by comma, eat it */
316 lex_get_token(lc, T_ALL); /* yes, eat comma */
322 * Store FileSet Include/Exclude info
323 * new style includes are handled in store_newinc()
325 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
330 * Decide if we are doing a new Include or an old include. The
331 * new Include is followed immediately by open brace, whereas the
332 * old include has options following the Include.
334 token = lex_get_token(lc, T_SKIP_EOL);
335 if (token == T_BOB) {
336 store_newinc(lc, item, index, pass);
339 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
344 * Store new style FileSet Include/Exclude info
346 * Note, when this routine is called, we are inside a FileSet
347 * resource. We treat the Include/Execlude like a sort of
348 * mini-resource within the FileSet resource.
350 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
356 if (!res_all.res_fs.have_MD5) {
357 MD5Init(&res_all.res_fs.md5c);
358 res_all.res_fs.have_MD5 = true;
360 memset(&res_incexe, 0, sizeof(INCEXE));
361 res_all.res_fs.new_include = true;
362 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
363 if (token == T_EOB) {
366 if (token != T_IDENTIFIER) {
367 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
369 for (i=0; newinc_items[i].name; i++) {
370 options = strcasecmp(lc->str, "options") == 0;
371 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
373 token = lex_get_token(lc, T_SKIP_EOL);
374 if (token != T_EQUALS) {
375 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
378 /* Call item handler */
379 newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
385 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
389 incexe = (INCEXE *)malloc(sizeof(INCEXE));
390 memcpy(incexe, &res_incexe, sizeof(INCEXE));
391 memset(&res_incexe, 0, sizeof(INCEXE));
392 if (item->code == 0) { /* include */
393 if (res_all.res_fs.num_includes == 0) {
394 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
396 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
397 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
399 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
400 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
401 } else { /* exclude */
402 if (res_all.res_fs.num_excludes == 0) {
403 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
405 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
406 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
408 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
409 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
413 set_bit(index, res_all.hdr.item_present);
417 /* Store regex info */
418 void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
426 token = lex_get_token(lc, T_SKIP_EOL);
428 /* Pickup regex string
432 case T_UNQUOTED_STRING:
433 case T_QUOTED_STRING:
434 rc = regcomp(&preg, lc->str, REG_EXTENDED);
436 regerror(rc, &preg, prbuf, sizeof(prbuf));
438 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
442 if (item->code == 1) {
444 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
445 newsize = res_incexe.current_opts->regexdir.size();
446 } else if (item->code == 2) {
448 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
449 newsize = res_incexe.current_opts->regexfile.size();
452 res_incexe.current_opts->regex.append(bstrdup(lc->str));
453 newsize = res_incexe.current_opts->regex.size();
455 Dmsg4(900, "set %s %p size=%d %s\n",
456 type, res_incexe.current_opts, newsize, lc->str);
459 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
465 /* Store Base info */
466 void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
469 lex_get_token(lc, T_NAME);
472 * Pickup Base Job Name
474 res_incexe.current_opts->base.append(bstrdup(lc->str));
479 /* Store reader info */
480 void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
483 lex_get_token(lc, T_NAME);
486 * Pickup plugin command
488 res_incexe.current_opts->plugin = bstrdup(lc->str);
494 /* Store Wild-card info */
495 void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
501 token = lex_get_token(lc, T_SKIP_EOL);
504 * Pickup Wild-card string
508 case T_UNQUOTED_STRING:
509 case T_QUOTED_STRING:
510 if (item->code == 1) {
512 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
513 newsize = res_incexe.current_opts->wilddir.size();
514 } else if (item->code == 2) {
515 if (strpbrk(lc->str, "/\\") != NULL) {
517 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
518 newsize = res_incexe.current_opts->wildfile.size();
521 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
522 newsize = res_incexe.current_opts->wildbase.size();
526 res_incexe.current_opts->wild.append(bstrdup(lc->str));
527 newsize = res_incexe.current_opts->wild.size();
529 Dmsg4(9, "set %s %p size=%d %s\n",
530 type, res_incexe.current_opts, newsize, lc->str);
533 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
539 /* Store fstype info */
540 void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
545 token = lex_get_token(lc, T_STRING); /* scan next item */
546 if (token == T_ERROR) {
549 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
551 Dmsg3(900, "set fstype %p size=%d %s\n",
552 res_incexe.current_opts, res_incexe.current_opts->fstype.size(),lc->str);
554 if (lc->ch != ',') { /* if no other item follows */
557 lex_get_token(lc, T_ALL); /* eat comma */
563 /* Store exclude directory containing info */
564 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
568 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
571 lex_get_token(lc, T_NAME);
573 res_incexe.ignoredir = bstrdup(lc->str);
578 /* Store drivetype info */
579 void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
584 token = lex_get_token(lc, T_STRING); /* scan next item */
585 if (token == T_ERROR) {
588 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
589 Dmsg3(900, "set drivetype %p size=%d %s\n",
590 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(),lc->str);
591 if (lc->ch != ',') { /* if no other item follows */
594 lex_get_token(lc, T_ALL); /* eat comma */
601 * Store Filename info. Note, for minor efficiency reasons, we
602 * always increase the name buffer by 10 items because we expect
603 * to add more entries.
605 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
610 token = lex_get_token(lc, T_SKIP_EOL);
612 /* Pickup Filename string
616 case T_UNQUOTED_STRING:
617 if (strchr(lc->str, '\\')) {
618 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
621 case T_QUOTED_STRING:
622 if (res_all.res_fs.have_MD5) {
623 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
625 incexe = &res_incexe;
626 if (incexe->name_list.size() == 0) {
627 incexe->name_list.init(10, true);
629 incexe->name_list.append(bstrdup(lc->str));
630 Dmsg1(900, "Add to name_list %s\n", lc->str);
633 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
640 * Store Filename info. Note, for minor efficiency reasons, we
641 * always increase the name buffer by 10 items because we expect
642 * to add more entries.
644 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
650 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
653 token = lex_get_token(lc, T_SKIP_EOL);
655 /* Pickup Filename string
659 case T_UNQUOTED_STRING:
660 if (strchr(lc->str, '\\')) {
661 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
664 case T_QUOTED_STRING:
665 if (res_all.res_fs.have_MD5) {
666 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
668 incexe = &res_incexe;
669 if (incexe->plugin_list.size() == 0) {
670 incexe->plugin_list.init(10, true);
672 incexe->plugin_list.append(bstrdup(lc->str));
673 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
676 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
686 * Come here when Options seen in Include/Exclude
688 static void store_options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
693 scan_err0(lc, _("Options section not permitted in Exclude\n"));
696 token = lex_get_token(lc, T_SKIP_EOL);
697 if (token != T_BOB) {
698 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
702 setup_current_opts();
705 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
706 if (token == T_EOL) {
709 if (token == T_EOB) {
712 if (token != T_IDENTIFIER) {
713 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
715 for (i=0; options_items[i].name; i++) {
716 if (strcasecmp(options_items[i].name, lc->str) == 0) {
717 token = lex_get_token(lc, T_SKIP_EOL);
718 if (token != T_EQUALS) {
719 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
721 /* Call item handler */
722 options_items[i].handler(lc, &options_items[i], i, pass);
728 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
734 * Different subroutine, but uses store_opts
736 void store_lopts(LEX *lc, RES_ITEM *item, int index, int pass)
738 store_opts(lc, item, index, pass);
742 * New style options come here
744 void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
751 keyword = INC_KW_NONE;
752 /* Look up the keyword */
753 for (i=0; FS_option_kw[i].name; i++) {
754 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
755 keyword = FS_option_kw[i].token;
759 if (keyword == INC_KW_NONE) {
760 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
762 /* Now scan for the value */
763 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
765 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
766 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
769 set_bit(keyword, res_incexe.opt_present);
775 /* If current_opts not defined, create first entry */
776 static void setup_current_opts(void)
778 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
779 memset(fo, 0, sizeof(FOPTS));
780 fo->regex.init(1, true);
781 fo->regexdir.init(1, true);
782 fo->regexfile.init(1, true);
783 fo->wild.init(1, true);
784 fo->wilddir.init(1, true);
785 fo->wildfile.init(1, true);
786 fo->wildbase.init(1, true);
787 fo->base.init(1, true);
788 fo->fstype.init(1, true);
789 fo->drivetype.init(1, true);
790 res_incexe.current_opts = fo;
791 if (res_incexe.num_opts == 0) {
792 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
794 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
795 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
797 res_incexe.opts_list[res_incexe.num_opts++] = fo;