2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Configuration file parser for new and old Include and
24 * Kern Sibbald, March MMIII
31 #include "lib/bregex.h"
36 /* Forward referenced subroutines */
38 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
40 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
41 void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
42 void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
43 void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
44 void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass);
45 void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
46 void store_lopts(LEX *lc, RES_ITEM *item, int index, int pass);
47 void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
48 void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
49 static void setup_current_opts(void);
51 /* Include and Exclude items */
52 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
53 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
54 static void store_options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
55 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
58 /* We build the current resource here as we are
59 * scanning the resource configuration definition,
60 * then move it to allocated memory when the resource
64 extern "C" { // work around visual compiler mangling variables
70 extern int32_t res_all_size;
72 /* We build the current new Include and Exclude items here */
73 static INCEXE res_incexe;
76 * new Include/Exclude items
77 * name handler value code flags default_value
79 RES_ITEM2 newinc_items[] = {
80 {"File", store_fname, {0}, 0, 0, 0},
81 {"Plugin", store_plugin_name, {0}, 0, 0, 0},
82 {"ExcludeDirContaining", store_excludedir, {0}, 0, 0, 0},
83 {"Options", store_options_res, {0}, 0, 0, 0},
84 {NULL, NULL, {0}, 0, 0, 0}
88 * Items that are valid in an Options resource
90 * name handler value code flags default_value
92 * Encryption in FS_option_kw table ???
93 * ReadFifo not in FS_option_kw table ???
96 RES_ITEM options_items[] = {
97 {"Compression", store_opts, {0}, 0, INC_KW_COMPRESSION, 0},
98 {"Signature", store_opts, {0}, 0, INC_KW_DIGEST, 0},
99 {"OneFs", store_opts, {0}, 0, INC_KW_ONEFS, 0},
100 {"Recurse", store_opts, {0}, 0, INC_KW_RECURSE, 0},
101 {"Sparse", store_opts, {0}, 0, INC_KW_SPARSE, 0},
102 {"HardLinks", store_opts, {0}, 0, INC_KW_HARDLINK, 0},
103 {"Replace", store_opts, {0}, 0, INC_KW_REPLACE, 0},
104 {"Portable", store_opts, {0}, 0, INC_KW_PORTABLE, 0},
105 {"MtimeOnly", store_opts, {0}, 0, INC_KW_MTIMEONLY, 0},
106 {"KeepAtime", store_opts, {0}, 0, INC_KW_KEEPATIME, 0},
107 {"Exclude", store_opts, {0}, 0, INC_KW_EXCLUDE, 0},
108 {"AclSupport", store_opts, {0}, 0, INC_KW_ACL, 0},
109 {"IgnoreCase", store_opts, {0}, 0, INC_KW_IGNORECASE, 0},
110 {"HfsPlusSupport", store_opts, {0}, 0, INC_KW_HFSPLUS, 0},
111 {"NoAtime", store_opts, {0}, 0, INC_KW_NOATIME, 0},
112 {"EnhancedWild", store_opts, {0}, 0, INC_KW_ENHANCEDWILD, 0},
113 {"CheckFileChanges",store_opts, {0}, 0, INC_KW_CHKCHANGES, 1},
114 {"HonorNoDumpFlag", store_opts, {0}, 0, INC_KW_HONOR_NODUMP, 0},
115 {"XattrSupport", store_opts, {0}, 0, INC_KW_XATTR, 0},
116 {"ReadFifo", store_opts, {0}, 0, INC_KW_READFIFO, 0},
117 {"BaseJob", store_lopts, {0}, 'J', INC_KW_BASEJOB, 0},
118 {"Accurate", store_lopts, {0}, 'C', INC_KW_ACCURATE, 0},
119 {"Verify", store_lopts, {0}, 'V', INC_KW_VERIFY, 0},
120 {"StripPath", store_lopts, {0}, 'P', INC_KW_STRIPPATH, 0},
121 {"Regex", store_regex, {0}, 0, 0, 0},
122 {"RegexDir", store_regex, {0}, 1, 0, 0},
123 {"RegexFile", store_regex, {0}, 2, 0, 0},
124 {"Base", store_base, {0}, 0, 0, 0},
125 {"Wild", store_wild, {0}, 0, 0, 0},
126 {"WildDir", store_wild, {0}, 1, 0, 0},
127 {"WildFile", store_wild, {0}, 2, 0, 0},
128 {"Plugin", store_plugin, {0}, 0, 0, 0},
129 {"FsType", store_fstype, {0}, 0, 0, 0},
130 {"DriveType", store_drivetype, {0}, 0, 0, 0},
131 {NULL, NULL, {0}, 0, 0, 0}
135 * This is the list of options that can be stored by store_opts
136 * Note, now that the old style Include/Exclude code is gone,
137 * the INC_KW code could be put into the "code" field of the
138 * options given above.
142 s_kw FS_option_kw[] = {
143 {"Compression", INC_KW_COMPRESSION},
144 {"Signature", INC_KW_DIGEST},
145 {"Encryption", INC_KW_ENCRYPTION},
146 {"Verify", INC_KW_VERIFY},
147 {"BaseJob", INC_KW_BASEJOB},
148 {"Accurate", INC_KW_ACCURATE},
149 {"OneFs", INC_KW_ONEFS},
150 {"Recurse", INC_KW_RECURSE},
151 {"Sparse", INC_KW_SPARSE},
152 {"HardLinks", INC_KW_HARDLINK},
153 {"Replace", INC_KW_REPLACE},
154 {"ReadFifo", INC_KW_READFIFO},
155 {"Portable", INC_KW_PORTABLE},
156 {"MtimeOnly", INC_KW_MTIMEONLY},
157 {"KeepAtime", INC_KW_KEEPATIME},
158 {"Exclude", INC_KW_EXCLUDE},
159 {"AclSupport", INC_KW_ACL},
160 {"IgnoreCase", INC_KW_IGNORECASE},
161 {"HfsPlusSupport", INC_KW_HFSPLUS},
162 {"NoAtime", INC_KW_NOATIME},
163 {"EnhancedWild", INC_KW_ENHANCEDWILD},
164 {"CheckFileChanges", INC_KW_CHKCHANGES},
165 {"StripPath", INC_KW_STRIPPATH},
166 {"HonorNoDumpFlag", INC_KW_HONOR_NODUMP},
167 {"XattrSupport", INC_KW_XATTR},
172 * Options permitted for each keyword and resulting value.
173 * The output goes into opts, which are then transmitted to
174 * the FD for application as options to the following list of
177 * Note! all 0's in options must come after the value that
180 * NOTE!! The following long options (see scan_include_options())
186 * name keyword option
188 struct s_fs_opt FS_options[] = {
189 {"Md5", INC_KW_DIGEST, "M"},
190 {"Sha1", INC_KW_DIGEST, "S"},
191 {"Sha256", INC_KW_DIGEST, "S2"},
192 {"Sha512", INC_KW_DIGEST, "S3"},
193 {"Gzip", INC_KW_COMPRESSION, "Z6"},
194 {"Gzip1", INC_KW_COMPRESSION, "Z1"},
195 {"Gzip2", INC_KW_COMPRESSION, "Z2"},
196 {"Gzip3", INC_KW_COMPRESSION, "Z3"},
197 {"Gzip4", INC_KW_COMPRESSION, "Z4"},
198 {"Gzip5", INC_KW_COMPRESSION, "Z5"},
199 {"Gzip6", INC_KW_COMPRESSION, "Z6"},
200 {"Gzip7", INC_KW_COMPRESSION, "Z7"},
201 {"Gzip8", INC_KW_COMPRESSION, "Z8"},
202 {"Gzip9", INC_KW_COMPRESSION, "Z9"},
203 {"Lzo", INC_KW_COMPRESSION, "Zo"},
204 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
205 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
206 {"No", INC_KW_ONEFS, "f"},
207 {"Yes", INC_KW_ONEFS, "0"},
208 {"No", INC_KW_RECURSE, "h"},
209 {"Yes", INC_KW_RECURSE, "0"},
210 {"Yes", INC_KW_SPARSE, "s"},
211 {"No", INC_KW_SPARSE, "0"},
212 {"No", INC_KW_HARDLINK, "H"},
213 {"Yes", INC_KW_HARDLINK, "0"},
214 {"Always", INC_KW_REPLACE, "a"},
215 {"IfNewer", INC_KW_REPLACE, "w"},
216 {"Never", INC_KW_REPLACE, "n"},
217 {"Yes", INC_KW_READFIFO, "r"},
218 {"No", INC_KW_READFIFO, "0"},
219 {"Yes", INC_KW_PORTABLE, "p"},
220 {"No", INC_KW_PORTABLE, "0"},
221 {"Yes", INC_KW_MTIMEONLY, "m"},
222 {"No", INC_KW_MTIMEONLY, "0"},
223 {"Yes", INC_KW_KEEPATIME, "k"},
224 {"No", INC_KW_KEEPATIME, "0"},
225 {"Yes", INC_KW_EXCLUDE, "e"},
226 {"No", INC_KW_EXCLUDE, "0"},
227 {"Yes", INC_KW_ACL, "A"},
228 {"No", INC_KW_ACL, "0"},
229 {"Yes", INC_KW_IGNORECASE, "i"},
230 {"No", INC_KW_IGNORECASE, "0"},
231 {"Yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
232 {"No", INC_KW_HFSPLUS, "0"},
233 {"Yes", INC_KW_NOATIME, "K"},
234 {"No", INC_KW_NOATIME, "0"},
235 {"Yes", INC_KW_ENHANCEDWILD, "K"},
236 {"No", INC_KW_ENHANCEDWILD, "0"},
237 {"Yes", INC_KW_CHKCHANGES, "c"},
238 {"No", INC_KW_CHKCHANGES, "0"},
239 {"Yes", INC_KW_HONOR_NODUMP, "N"},
240 {"No", INC_KW_HONOR_NODUMP, "0"},
241 {"Yes", INC_KW_XATTR, "X"},
242 {"No", INC_KW_XATTR, "0"},
249 * Scan for right hand side of Include options (keyword=option) is
250 * converted into one or two characters. Verify=xxxx is Vxxxx:
251 * Whatever is found is concatenated to the opts string.
252 * This code is also used inside an Options resource.
254 * This function returns true for a long option (terminates with :)
255 * and false for a normal 1 or 2 character option.
257 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
261 int lcopts = lc->options;
263 option[0] = 0; /* default option = none */
264 option[2] = 0; /* terminate options */
265 lc->options |= LOPT_STRING; /* force string */
266 lex_get_token(lc, T_STRING); /* expect at least one option */
268 * ***FIXME**** ensure these are in permitted set
270 if (keyword == INC_KW_VERIFY) { /* special case */
271 bstrncat(opts, "V", optlen); /* indicate Verify */
272 bstrncat(opts, lc->str, optlen);
273 bstrncat(opts, ":", optlen); /* terminate it */
274 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
275 } else if (keyword == INC_KW_ACCURATE) { /* special case */
276 bstrncat(opts, "C", optlen); /* indicate Accurate */
277 bstrncat(opts, lc->str, optlen);
278 bstrncat(opts, ":", optlen); /* terminate it */
279 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
280 } else if (keyword == INC_KW_BASEJOB) { /* special case */
281 bstrncat(opts, "J", optlen); /* indicate BaseJob */
282 bstrncat(opts, lc->str, optlen);
283 bstrncat(opts, ":", optlen); /* terminate it */
284 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
285 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
286 if (!is_an_integer(lc->str)) {
287 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
289 bstrncat(opts, "P", optlen); /* indicate strip path */
290 bstrncat(opts, lc->str, optlen);
291 bstrncat(opts, ":", optlen); /* terminate it */
292 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
294 * Standard keyword options for Include/Exclude
297 for (i=0; FS_options[i].name; i++) {
298 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
299 /* NOTE! maximum 2 letters here or increase option[3] */
300 option[0] = FS_options[i].option[0];
301 option[1] = FS_options[i].option[1];
307 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
308 } else { /* add option */
309 bstrncat(opts, option, optlen);
310 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
313 lc->options = lcopts;
315 /* If option terminated by comma, eat it */
317 lex_get_token(lc, T_ALL); /* yes, eat comma */
323 * Store FileSet Include/Exclude info
324 * new style includes are handled in store_newinc()
326 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
331 * Decide if we are doing a new Include or an old include. The
332 * new Include is followed immediately by open brace, whereas the
333 * old include has options following the Include.
335 token = lex_get_token(lc, T_SKIP_EOL);
336 if (token == T_BOB) {
337 store_newinc(lc, item, index, pass);
340 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
345 * Store new style FileSet Include/Exclude info
347 * Note, when this routine is called, we are inside a FileSet
348 * resource. We treat the Include/Execlude like a sort of
349 * mini-resource within the FileSet resource.
351 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
357 if (!res_all.res_fs.have_MD5) {
358 MD5Init(&res_all.res_fs.md5c);
359 res_all.res_fs.have_MD5 = true;
361 memset(&res_incexe, 0, sizeof(INCEXE));
362 res_all.res_fs.new_include = true;
363 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
364 if (token == T_EOB) {
367 if (token != T_IDENTIFIER) {
368 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
370 for (i=0; newinc_items[i].name; i++) {
371 options = strcasecmp(lc->str, "options") == 0;
372 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
374 token = lex_get_token(lc, T_SKIP_EOL);
375 if (token != T_EQUALS) {
376 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
379 /* Call item handler */
380 newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
386 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
390 incexe = (INCEXE *)malloc(sizeof(INCEXE));
391 memcpy(incexe, &res_incexe, sizeof(INCEXE));
392 memset(&res_incexe, 0, sizeof(INCEXE));
393 if (item->code == 0) { /* include */
394 if (res_all.res_fs.num_includes == 0) {
395 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
397 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
398 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
400 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
401 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
402 } else { /* exclude */
403 if (res_all.res_fs.num_excludes == 0) {
404 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
406 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
407 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
409 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
410 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
414 set_bit(index, res_all.hdr.item_present);
418 /* Store regex info */
419 void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
427 token = lex_get_token(lc, T_SKIP_EOL);
429 /* Pickup regex string
433 case T_UNQUOTED_STRING:
434 case T_QUOTED_STRING:
435 rc = regcomp(&preg, lc->str, REG_EXTENDED);
437 regerror(rc, &preg, prbuf, sizeof(prbuf));
439 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
443 if (item->code == 1) {
445 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
446 newsize = res_incexe.current_opts->regexdir.size();
447 } else if (item->code == 2) {
449 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
450 newsize = res_incexe.current_opts->regexfile.size();
453 res_incexe.current_opts->regex.append(bstrdup(lc->str));
454 newsize = res_incexe.current_opts->regex.size();
456 Dmsg4(900, "set %s %p size=%d %s\n",
457 type, res_incexe.current_opts, newsize, lc->str);
460 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
466 /* Store Base info */
467 void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
470 lex_get_token(lc, T_NAME);
473 * Pickup Base Job Name
475 res_incexe.current_opts->base.append(bstrdup(lc->str));
480 /* Store reader info */
481 void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
484 lex_get_token(lc, T_NAME);
487 * Pickup plugin command
489 res_incexe.current_opts->plugin = bstrdup(lc->str);
495 /* Store Wild-card info */
496 void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
502 token = lex_get_token(lc, T_SKIP_EOL);
505 * Pickup Wild-card string
509 case T_UNQUOTED_STRING:
510 case T_QUOTED_STRING:
511 if (item->code == 1) {
513 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
514 newsize = res_incexe.current_opts->wilddir.size();
515 } else if (item->code == 2) {
516 if (strpbrk(lc->str, "/\\") != NULL) {
518 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
519 newsize = res_incexe.current_opts->wildfile.size();
522 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
523 newsize = res_incexe.current_opts->wildbase.size();
527 res_incexe.current_opts->wild.append(bstrdup(lc->str));
528 newsize = res_incexe.current_opts->wild.size();
530 Dmsg4(9, "set %s %p size=%d %s\n",
531 type, res_incexe.current_opts, newsize, lc->str);
534 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
540 /* Store fstype info */
541 void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
546 token = lex_get_token(lc, T_STRING); /* scan next item */
547 if (token == T_ERROR) {
550 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
552 Dmsg3(900, "set fstype %p size=%d %s\n",
553 res_incexe.current_opts, res_incexe.current_opts->fstype.size(),lc->str);
555 if (lc->ch != ',') { /* if no other item follows */
558 lex_get_token(lc, T_ALL); /* eat comma */
564 /* Store exclude directory containing info */
565 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
569 scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
572 lex_get_token(lc, T_NAME);
574 res_incexe.ignoredir = bstrdup(lc->str);
579 /* Store drivetype info */
580 void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
585 token = lex_get_token(lc, T_STRING); /* scan next item */
586 if (token == T_ERROR) {
589 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
590 Dmsg3(900, "set drivetype %p size=%d %s\n",
591 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(),lc->str);
592 if (lc->ch != ',') { /* if no other item follows */
595 lex_get_token(lc, T_ALL); /* eat comma */
602 * Store Filename info. Note, for minor efficiency reasons, we
603 * always increase the name buffer by 10 items because we expect
604 * to add more entries.
606 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
611 token = lex_get_token(lc, T_SKIP_EOL);
613 /* Pickup Filename string
617 case T_UNQUOTED_STRING:
618 if (strchr(lc->str, '\\')) {
619 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
622 case T_QUOTED_STRING:
623 if (res_all.res_fs.have_MD5) {
624 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
626 incexe = &res_incexe;
627 if (incexe->name_list.size() == 0) {
628 incexe->name_list.init(10, true);
630 incexe->name_list.append(bstrdup(lc->str));
631 Dmsg1(900, "Add to name_list %s\n", lc->str);
634 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
641 * Store Filename info. Note, for minor efficiency reasons, we
642 * always increase the name buffer by 10 items because we expect
643 * to add more entries.
645 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
651 scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
654 token = lex_get_token(lc, T_SKIP_EOL);
656 /* Pickup Filename string
660 case T_UNQUOTED_STRING:
661 if (strchr(lc->str, '\\')) {
662 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
665 case T_QUOTED_STRING:
666 if (res_all.res_fs.have_MD5) {
667 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
669 incexe = &res_incexe;
670 if (incexe->plugin_list.size() == 0) {
671 incexe->plugin_list.init(10, true);
673 incexe->plugin_list.append(bstrdup(lc->str));
674 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
677 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
687 * Come here when Options seen in Include/Exclude
689 static void store_options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
694 scan_err0(lc, _("Options section not permitted in Exclude\n"));
697 token = lex_get_token(lc, T_SKIP_EOL);
698 if (token != T_BOB) {
699 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
703 setup_current_opts();
706 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
707 if (token == T_EOL) {
710 if (token == T_EOB) {
713 if (token != T_IDENTIFIER) {
714 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
716 for (i=0; options_items[i].name; i++) {
717 if (strcasecmp(options_items[i].name, lc->str) == 0) {
718 token = lex_get_token(lc, T_SKIP_EOL);
719 if (token != T_EQUALS) {
720 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
722 /* Call item handler */
723 options_items[i].handler(lc, &options_items[i], i, pass);
729 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
735 * Different subroutine, but uses store_opts
737 void store_lopts(LEX *lc, RES_ITEM *item, int index, int pass)
739 store_opts(lc, item, index, pass);
743 * New style options come here
745 void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
752 keyword = INC_KW_NONE;
753 /* Look up the keyword */
754 for (i=0; FS_option_kw[i].name; i++) {
755 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
756 keyword = FS_option_kw[i].token;
760 if (keyword == INC_KW_NONE) {
761 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
763 /* Now scan for the value */
764 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
766 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
767 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
770 set_bit(keyword, res_incexe.opt_present);
776 /* If current_opts not defined, create first entry */
777 static void setup_current_opts(void)
779 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
780 memset(fo, 0, sizeof(FOPTS));
781 fo->regex.init(1, true);
782 fo->regexdir.init(1, true);
783 fo->regexfile.init(1, true);
784 fo->wild.init(1, true);
785 fo->wilddir.init(1, true);
786 fo->wildfile.init(1, true);
787 fo->wildbase.init(1, true);
788 fo->base.init(1, true);
789 fo->fstype.init(1, true);
790 fo->drivetype.init(1, true);
791 res_incexe.current_opts = fo;
792 if (res_incexe.num_opts == 0) {
793 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
795 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
796 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
798 res_incexe.opts_list[res_incexe.num_opts++] = fo;