2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 plus additions
11 that are listed in the file LICENSE.
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 options_res(LEX *lc, RES_ITEM *item, int index, int pass);
57 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
58 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
59 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
60 static void setup_current_opts(void);
63 /* We build the current resource here as we are
64 * scanning the resource configuration definition,
65 * then move it to allocated memory when the resource
69 extern "C" { // work around visual compiler mangling variables
75 extern int res_all_size;
77 /* We build the current new Include and Exclude items here */
78 static INCEXE res_incexe;
81 * new Include/Exclude items
82 * name handler value code flags default_value
84 static RES_ITEM newinc_items[] = {
85 {"file", store_fname, {0}, 0, 0, 0},
86 {"options", options_res, {0}, 0, 0, 0},
87 {NULL, NULL, {0}, 0, 0, 0}
91 * Items that are valid in an Options resource
93 static RES_ITEM options_items[] = {
94 {"compression", store_opts, {0}, 0, 0, 0},
95 {"signature", store_opts, {0}, 0, 0, 0},
96 {"verify", store_opts, {0}, 0, 0, 0},
97 {"onefs", store_opts, {0}, 0, 0, 0},
98 {"recurse", store_opts, {0}, 0, 0, 0},
99 {"sparse", store_opts, {0}, 0, 0, 0},
100 {"hardlinks", store_opts, {0}, 0, 0, 0},
101 {"readfifo", store_opts, {0}, 0, 0, 0},
102 {"replace", store_opts, {0}, 0, 0, 0},
103 {"portable", store_opts, {0}, 0, 0, 0},
104 {"mtimeonly", store_opts, {0}, 0, 0, 0},
105 {"keepatime", store_opts, {0}, 0, 0, 0},
106 {"regex", store_regex, {0}, 0, 0, 0},
107 {"regexdir", store_regex, {0}, 1, 0, 0},
108 {"regexfile", store_regex, {0}, 2, 0, 0},
109 {"base", store_base, {0}, 0, 0, 0},
110 {"wild", store_wild, {0}, 0, 0, 0},
111 {"wilddir", store_wild, {0}, 1, 0, 0},
112 {"wildfile", store_wild, {0}, 2, 0, 0},
113 {"exclude", store_opts, {0}, 0, 0, 0},
114 {"aclsupport", store_opts, {0}, 0, 0, 0},
115 {"reader", store_reader, {0}, 0, 0, 0},
116 {"writer", store_writer, {0}, 0, 0, 0},
117 {"ignorecase", store_opts, {0}, 0, 0, 0},
118 {"fstype", store_fstype, {0}, 0, 0, 0},
119 {"hfsplussupport", store_opts, {0}, 0, 0, 0},
120 {"noatime", store_opts, {0}, 0, 0, 0},
121 {"enhancedwild", store_opts, {0}, 0, 0, 0},
122 {"drivetype", store_drivetype, {0}, 0, 0, 0},
123 {"checkfilechanges",store_opts, {0}, 0, 0, 0},
124 {NULL, NULL, {0}, 0, 0, 0}
128 /* Define FileSet KeyWord values */
139 INC_KW_REPLACE, /* restore options */
140 INC_KW_READFIFO, /* Causes fifo data to be read */
154 * This is the list of options that can be stored by store_opts
155 * Note, now that the old style Include/Exclude code is gone,
156 * the INC_KW code could be put into the "code" field of the
157 * options given above.
159 static struct s_kw FS_option_kw[] = {
160 {"compression", INC_KW_COMPRESSION},
161 {"signature", INC_KW_DIGEST},
162 {"encryption", INC_KW_ENCRYPTION},
163 {"verify", INC_KW_VERIFY},
164 {"onefs", INC_KW_ONEFS},
165 {"recurse", INC_KW_RECURSE},
166 {"sparse", INC_KW_SPARSE},
167 {"hardlinks", INC_KW_HARDLINK},
168 {"replace", INC_KW_REPLACE},
169 {"readfifo", INC_KW_READFIFO},
170 {"portable", INC_KW_PORTABLE},
171 {"mtimeonly", INC_KW_MTIMEONLY},
172 {"keepatime", INC_KW_KEEPATIME},
173 {"exclude", INC_KW_EXCLUDE},
174 {"aclsupport", INC_KW_ACL},
175 {"ignorecase", INC_KW_IGNORECASE},
176 {"hfsplussupport", INC_KW_HFSPLUS},
177 {"noatime", INC_KW_NOATIME},
178 {"enhancedwild", INC_KW_ENHANCEDWILD},
179 {"checkfilechanges", INC_KW_CHKCHANGES},
183 /* Options for FileSet keywords */
192 * Options permitted for each keyword and resulting value.
193 * The output goes into opts, which are then transmitted to
194 * the FD for application as options to the following list of
197 static struct s_fs_opt FS_options[] = {
198 {"md5", INC_KW_DIGEST, "M"},
199 {"sha1", INC_KW_DIGEST, "S"},
200 {"sha256", INC_KW_DIGEST, "S2"},
201 {"sha512", INC_KW_DIGEST, "S3"},
202 {"gzip", INC_KW_COMPRESSION, "Z6"},
203 {"gzip1", INC_KW_COMPRESSION, "Z1"},
204 {"gzip2", INC_KW_COMPRESSION, "Z2"},
205 {"gzip3", INC_KW_COMPRESSION, "Z3"},
206 {"gzip4", INC_KW_COMPRESSION, "Z4"},
207 {"gzip5", INC_KW_COMPRESSION, "Z5"},
208 {"gzip6", INC_KW_COMPRESSION, "Z6"},
209 {"gzip7", INC_KW_COMPRESSION, "Z7"},
210 {"gzip8", INC_KW_COMPRESSION, "Z8"},
211 {"gzip9", INC_KW_COMPRESSION, "Z9"},
212 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
213 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
214 {"yes", INC_KW_ONEFS, "0"},
215 {"no", INC_KW_ONEFS, "f"},
216 {"yes", INC_KW_RECURSE, "0"},
217 {"no", INC_KW_RECURSE, "h"},
218 {"yes", INC_KW_SPARSE, "s"},
219 {"no", INC_KW_SPARSE, "0"},
220 {"yes", INC_KW_HARDLINK, "0"},
221 {"no", INC_KW_HARDLINK, "H"},
222 {"always", INC_KW_REPLACE, "a"},
223 {"ifnewer", INC_KW_REPLACE, "w"},
224 {"never", INC_KW_REPLACE, "n"},
225 {"yes", INC_KW_READFIFO, "r"},
226 {"no", INC_KW_READFIFO, "0"},
227 {"yes", INC_KW_PORTABLE, "p"},
228 {"no", INC_KW_PORTABLE, "0"},
229 {"yes", INC_KW_MTIMEONLY, "m"},
230 {"no", INC_KW_MTIMEONLY, "0"},
231 {"yes", INC_KW_KEEPATIME, "k"},
232 {"no", INC_KW_KEEPATIME, "0"},
233 {"yes", INC_KW_EXCLUDE, "e"},
234 {"no", INC_KW_EXCLUDE, "0"},
235 {"yes", INC_KW_ACL, "A"},
236 {"no", INC_KW_ACL, "0"},
237 {"yes", INC_KW_IGNORECASE, "i"},
238 {"no", INC_KW_IGNORECASE, "0"},
239 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
240 {"no", INC_KW_HFSPLUS, "0"},
241 {"yes", INC_KW_NOATIME, "K"},
242 {"no", INC_KW_NOATIME, "0"},
243 {"yes", INC_KW_ENHANCEDWILD, "K"},
244 {"no", INC_KW_ENHANCEDWILD, "0"},
245 {"yes", INC_KW_CHKCHANGES, "c"},
246 {"no", INC_KW_CHKCHANGES, "0"},
253 * Scan for right hand side of Include options (keyword=option) is
254 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
255 * Whatever is found is concatenated to the opts string.
256 * This code is also used inside an Options resource.
258 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
262 int lcopts = lc->options;
264 option[0] = 0; /* default option = none */
265 option[2] = 0; /* terminate options */
266 lc->options |= LOPT_STRING; /* force string */
267 token = lex_get_token(lc, T_STRING); /* expect at least one option */
268 if (keyword == INC_KW_VERIFY) { /* special case */
269 /* ***FIXME**** ensure these are in permitted set */
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);
276 * Standard keyword options for Include/Exclude
279 for (i=0; FS_options[i].name; i++) {
280 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
281 /* NOTE! maximum 2 letters here or increase option[3] */
282 option[0] = FS_options[i].option[0];
283 option[1] = FS_options[i].option[1];
289 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
290 } else { /* add option */
291 bstrncat(opts, option, optlen);
292 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
295 lc->options = lcopts;
297 /* If option terminated by comma, eat it */
299 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
305 * Store FileSet Include/Exclude info
306 * NEW style includes are handled in store_newinc()
308 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
313 * Decide if we are doing a new Include or an old include. The
314 * new Include is followed immediately by open brace, whereas the
315 * old include has options following the Include.
317 token = lex_get_token(lc, T_SKIP_EOL);
318 if (token == T_BOB) {
319 store_newinc(lc, item, index, pass);
322 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
327 * Store NEW style FileSet FInclude/FExclude info
329 * Note, when this routine is called, we are inside a FileSet
330 * resource. We treat the Include/Execlude like a sort of
331 * mini-resource within the FileSet resource.
333 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
339 if (!res_all.res_fs.have_MD5) {
340 MD5Init(&res_all.res_fs.md5c);
341 res_all.res_fs.have_MD5 = true;
343 memset(&res_incexe, 0, sizeof(INCEXE));
344 res_all.res_fs.new_include = true;
345 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
346 if (token == T_EOB) {
349 if (token != T_IDENTIFIER) {
350 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
352 for (i=0; newinc_items[i].name; i++) {
353 options = strcasecmp(lc->str, "options") == 0;
354 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
356 token = lex_get_token(lc, T_SKIP_EOL);
357 if (token != T_EQUALS) {
358 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
361 /* Call item handler */
362 newinc_items[i].handler(lc, &newinc_items[i], i, pass);
368 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
372 incexe = (INCEXE *)malloc(sizeof(INCEXE));
373 memcpy(incexe, &res_incexe, sizeof(INCEXE));
374 memset(&res_incexe, 0, sizeof(INCEXE));
375 if (item->code == 0) { /* include */
376 if (res_all.res_fs.num_includes == 0) {
377 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
379 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
380 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
382 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
383 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
384 } else { /* exclude */
385 if (res_all.res_fs.num_excludes == 0) {
386 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
388 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
389 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
391 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
392 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
396 set_bit(index, res_all.hdr.item_present);
400 /* Store regex info */
401 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
409 token = lex_get_token(lc, T_SKIP_EOL);
411 /* Pickup regex string
415 case T_UNQUOTED_STRING:
416 case T_QUOTED_STRING:
417 rc = regcomp(&preg, lc->str, REG_EXTENDED);
419 regerror(rc, &preg, prbuf, sizeof(prbuf));
421 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
425 if (item->code == 1) {
427 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
428 newsize = res_incexe.current_opts->regexdir.size();
429 } else if (item->code == 2) {
431 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
432 newsize = res_incexe.current_opts->regexfile.size();
435 res_incexe.current_opts->regex.append(bstrdup(lc->str));
436 newsize = res_incexe.current_opts->regex.size();
438 Dmsg4(900, "set %s %p size=%d %s\n",
439 type, res_incexe.current_opts, newsize, lc->str);
442 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
448 /* Store Base info */
449 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
453 token = lex_get_token(lc, T_NAME);
456 * Pickup Base Job Name
458 res_incexe.current_opts->base.append(bstrdup(lc->str));
463 /* Store reader info */
464 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
468 token = lex_get_token(lc, T_NAME);
471 * Pickup reader command
473 res_incexe.current_opts->reader = bstrdup(lc->str);
478 /* Store writer innfo */
479 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
483 token = lex_get_token(lc, T_NAME);
486 * Pickup writer command
488 res_incexe.current_opts->writer = bstrdup(lc->str);
495 /* Store Wild-card info */
496 static 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 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
545 token = lex_get_token(lc, T_SKIP_EOL);
547 /* Pickup fstype string */
550 case T_UNQUOTED_STRING:
551 case T_QUOTED_STRING:
552 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
553 Dmsg3(900, "set fstype %p size=%d %s\n",
554 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
557 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
563 /* Store drivetype info */
564 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
568 token = lex_get_token(lc, T_SKIP_EOL);
570 /* Pickup drivetype string */
573 case T_UNQUOTED_STRING:
574 case T_QUOTED_STRING:
575 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
576 Dmsg3(900, "set drivetype %p size=%d %s\n",
577 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
580 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
587 * Store Filename info. Note, for minor efficiency reasons, we
588 * always increase the name buffer by 10 items because we expect
589 * to add more entries.
591 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
596 token = lex_get_token(lc, T_SKIP_EOL);
598 /* Pickup Filename string
602 case T_UNQUOTED_STRING:
603 if (strchr(lc->str, '\\')) {
604 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
607 case T_QUOTED_STRING:
608 if (res_all.res_fs.have_MD5) {
609 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
611 incexe = &res_incexe;
612 if (incexe->name_list.size() == 0) {
613 incexe->name_list.init(10, true);
615 incexe->name_list.append(bstrdup(lc->str));
616 Dmsg1(900, "Add to name_list %s\n", lc->str);
619 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
627 * Come here when Options seen in Include/Exclude
629 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
633 token = lex_get_token(lc, T_SKIP_EOL);
634 if (token != T_BOB) {
635 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
639 setup_current_opts();
642 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
643 if (token == T_EOL) {
646 if (token == T_EOB) {
649 if (token != T_IDENTIFIER) {
650 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
652 for (i=0; options_items[i].name; i++) {
653 if (strcasecmp(options_items[i].name, lc->str) == 0) {
654 token = lex_get_token(lc, T_SKIP_EOL);
655 if (token != T_EQUALS) {
656 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
658 /* Call item handler */
659 options_items[i].handler(lc, &options_items[i], i, pass);
665 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
672 * New style options come here
674 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
681 keyword = INC_KW_NONE;
682 /* Look up the keyword */
683 for (i=0; FS_option_kw[i].name; i++) {
684 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
685 keyword = FS_option_kw[i].token;
689 if (keyword == INC_KW_NONE) {
690 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
692 /* Now scan for the value */
693 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
695 bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
696 Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
703 /* If current_opts not defined, create first entry */
704 static void setup_current_opts(void)
706 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
707 memset(fo, 0, sizeof(FOPTS));
708 fo->regex.init(1, true);
709 fo->regexdir.init(1, true);
710 fo->regexfile.init(1, true);
711 fo->wild.init(1, true);
712 fo->wilddir.init(1, true);
713 fo->wildfile.init(1, true);
714 fo->wildbase.init(1, true);
715 fo->base.init(1, true);
716 fo->fstype.init(1, true);
717 fo->drivetype.init(1, true);
718 res_incexe.current_opts = fo;
719 if (res_incexe.num_opts == 0) {
720 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
722 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
723 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
725 res_incexe.opts_list[res_incexe.num_opts++] = fo;