2 * Configuration file parser for new and old Include and
5 * Kern Sibbald, March MMIII
10 Copyright (C) 2000-2003 Kern Sibbald and John Walker
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of
15 the License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public
23 License along with this program; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32 /* Forward referenced subroutines */
34 void store_inc(LEX *lc, struct res_items *item, int index, int pass);
36 static void store_newinc(LEX *lc, struct res_items *item, int index, int pass);
37 static void store_match(LEX *lc, struct res_items *item, int index, int pass);
38 static void store_opts(LEX *lc, struct res_items *item, int index, int pass);
39 static void store_fname(LEX *lc, struct res_items *item, int index, int pass);
40 static void store_base(LEX *lc, struct res_items *item, int index, int pass);
41 static void setup_current_opts(void);
44 /* We build the current resource here as we are
45 * scanning the resource configuration definition,
46 * then move it to allocated memory when the resource
50 extern int res_all_size;
52 /* We build the current new Include and Exclude items here */
53 static INCEXE res_incexe;
56 * new Include/Exclude items
57 * name handler value code flags default_value
59 static struct res_items newinc_items[] = {
60 {"compression", store_opts, NULL, 0, 0, 0},
61 {"signature", store_opts, NULL, 0, 0, 0},
62 {"verify", store_opts, NULL, 0, 0, 0},
63 {"onefs", store_opts, NULL, 0, 0, 0},
64 {"recurse", store_opts, NULL, 0, 0, 0},
65 {"sparse", store_opts, NULL, 0, 0, 0},
66 {"readfifo", store_opts, NULL, 0, 0, 0},
67 {"replace", store_opts, NULL, 0, 0, 0},
68 {"portable", store_opts, NULL, 0, 0, 0},
69 {"match", store_match, NULL, 0, 0, 0},
70 {"file", store_fname, NULL, 0, 0, 0},
71 {"base", store_base, NULL, 0, 0, 0},
72 {NULL, NULL, NULL, 0, 0, 0}
75 /* Define FileSet KeyWord values */
78 #define INC_KW_COMPRESSION 1
79 #define INC_KW_SIGNATURE 2
80 #define INC_KW_ENCRYPTION 3
81 #define INC_KW_VERIFY 4
82 #define INC_KW_ONEFS 5
83 #define INC_KW_RECURSE 6
84 #define INC_KW_SPARSE 7
85 #define INC_KW_REPLACE 8 /* restore options */
86 #define INC_KW_READFIFO 9 /* Causes fifo data to be read */
87 #define INC_KW_PORTABLE 10
89 /* Include keywords -- these are keywords that can appear
90 * in the options lists of an old include ( Include = compression= ...)
92 static struct s_kw FS_option_kw[] = {
93 {"compression", INC_KW_COMPRESSION},
94 {"signature", INC_KW_SIGNATURE},
95 {"encryption", INC_KW_ENCRYPTION},
96 {"verify", INC_KW_VERIFY},
97 {"onefs", INC_KW_ONEFS},
98 {"recurse", INC_KW_RECURSE},
99 {"sparse", INC_KW_SPARSE},
100 {"replace", INC_KW_REPLACE},
101 {"readfifo", INC_KW_READFIFO},
102 {"portable", INC_KW_PORTABLE},
106 /* Options for FileSet keywords */
115 * Options permitted for each keyword and resulting value.
116 * The output goes into opts, which are then transmitted to
117 * the FD for application as options to the following list of
120 static struct s_fs_opt FS_options[] = {
121 {"md5", INC_KW_SIGNATURE, "M"},
122 {"sha1", INC_KW_SIGNATURE, "S"},
123 {"gzip", INC_KW_COMPRESSION, "Z6"},
124 {"gzip1", INC_KW_COMPRESSION, "Z1"},
125 {"gzip2", INC_KW_COMPRESSION, "Z2"},
126 {"gzip3", INC_KW_COMPRESSION, "Z3"},
127 {"gzip4", INC_KW_COMPRESSION, "Z4"},
128 {"gzip5", INC_KW_COMPRESSION, "Z5"},
129 {"gzip6", INC_KW_COMPRESSION, "Z6"},
130 {"gzip7", INC_KW_COMPRESSION, "Z7"},
131 {"gzip8", INC_KW_COMPRESSION, "Z8"},
132 {"gzip9", INC_KW_COMPRESSION, "Z9"},
133 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
134 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
135 {"yes", INC_KW_ONEFS, "0"},
136 {"no", INC_KW_ONEFS, "f"},
137 {"yes", INC_KW_RECURSE, "0"},
138 {"no", INC_KW_RECURSE, "h"},
139 {"yes", INC_KW_SPARSE, "s"},
140 {"no", INC_KW_SPARSE, "0"},
141 {"always", INC_KW_REPLACE, "a"},
142 {"ifnewer", INC_KW_REPLACE, "w"},
143 {"never", INC_KW_REPLACE, "n"},
144 {"yes", INC_KW_READFIFO, "r"},
145 {"no", INC_KW_READFIFO, "0"},
146 {"yes", INC_KW_PORTABLE, "p"},
147 {"no", INC_KW_PORTABLE, "0"},
154 * Scan for right hand side of Include options (keyword=option) is
155 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
156 * Whatever is found is concatenated to the opts string.
158 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
163 option[0] = 0; /* default option = none */
164 option[2] = 0; /* terminate options */
165 token = lex_get_token(lc, T_NAME); /* expect at least one option */
166 if (keyword == INC_KW_VERIFY) { /* special case */
167 /* ***FIXME**** ensure these are in permitted set */
168 bstrncat(opts, "V", optlen); /* indicate Verify */
169 bstrncat(opts, lc->str, optlen);
170 bstrncat(opts, ":", optlen); /* terminate it */
171 Dmsg3(100, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
174 * Standard keyword options for Include/Exclude
177 for (i=0; FS_options[i].name; i++) {
178 if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
179 /* NOTE! maximum 2 letters here or increase option[3] */
180 option[0] = FS_options[i].option[0];
181 option[1] = FS_options[i].option[1];
187 scan_err1(lc, "Expected a FileSet option keyword, got:%s:", lc->str);
188 } else { /* add option */
189 bstrncat(opts, option, optlen);
190 Dmsg3(100, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
194 /* If option terminated by comma, eat it */
196 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
200 /* Store FileSet Include/Exclude info */
201 void store_inc(LEX *lc, struct res_items *item, int index, int pass)
204 int options = lc->options;
210 * Decide if we are doing a new Include or an old include. The
211 * new Include is followed immediately by {, whereas the
212 * old include has options following the Include.
214 token = lex_get_token(lc, T_ALL);
215 if (token == T_BOB) {
216 store_newinc(lc, item, index, pass);
219 if (token != T_EQUALS) {
220 scan_err1(lc, _("Expecting an equals sign, got: %s\n"), lc->str);
222 lc->options |= LOPT_NO_IDENT; /* make spaces significant */
223 memset(&res_incexe, 0, sizeof(INCEXE));
225 /* Get include options */
227 while ((token=lex_get_token(lc, T_ALL)) != T_BOB) {
229 keyword = INC_KW_NONE;
230 for (i=0; FS_option_kw[i].name; i++) {
231 if (strcasecmp(lc->str, FS_option_kw[i].name) == 0) {
232 keyword = FS_option_kw[i].token;
236 if (keyword == INC_KW_NONE) {
237 scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
239 /* Option keyword should be following by = <option> */
240 if ((token=lex_get_token(lc, T_ALL)) != T_EQUALS) {
241 scan_err1(lc, _("expected an = following keyword, got: %s"), lc->str);
243 /* Scan right hand side of option */
244 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
246 if (token == T_BOB) {
252 strcat(inc_opts, "0"); /* set no options */
254 inc_opts_len = strlen(inc_opts);
258 if (!res_all.res_fs.have_MD5) {
259 MD5Init(&res_all.res_fs.md5c);
260 res_all.res_fs.have_MD5 = TRUE;
262 setup_current_opts();
263 bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
264 Dmsg2(100, "old pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
266 /* Create incexe structure */
267 Dmsg0(200, "Create INCEXE structure\n");
268 incexe = (INCEXE *)malloc(sizeof(INCEXE));
269 memcpy(incexe, &res_incexe, sizeof(INCEXE));
270 memset(&res_incexe, 0, sizeof(INCEXE));
271 if (item->code == 0) { /* include */
272 if (res_all.res_fs.num_includes == 0) {
273 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
275 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
276 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
278 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
279 Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
280 } else { /* exclude */
281 if (res_all.res_fs.num_excludes == 0) {
282 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
284 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
285 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
287 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
288 Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
291 /* Pickup include/exclude names. They are stored in INCEXE
292 * structures which contains the options and the name.
294 while ((token = lex_get_token(lc, T_ALL)) != T_EOB) {
301 case T_UNQUOTED_STRING:
302 case T_QUOTED_STRING:
303 if (res_all.res_fs.have_MD5) {
304 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
306 if (incexe->name_list.size() == 0) {
307 incexe->name_list.init(10, true);
309 incexe->name_list.append(bstrdup(lc->str));
310 Dmsg1(200, "Add to name_list %s\n", lc->str);
313 scan_err1(lc, "Expected a filename, got: %s", lc->str);
316 /* Note, MD5Final is done in backup.c */
317 } else { /* pass 2 */
318 while (lex_get_token(lc, T_ALL) != T_EOB)
322 lc->options = options;
323 set_bit(index, res_all.hdr.item_present);
328 * Store FileSet FInclude/FExclude info
329 * Note, when this routine is called, we are inside a FileSet
330 * resource. We treat the Finclude/Fexeclude like a sort of
331 * mini-resource within the FileSet resource.
333 static void store_newinc(LEX *lc, struct res_items *item, int index, int pass)
338 if (!res_all.res_fs.have_MD5) {
339 MD5Init(&res_all.res_fs.md5c);
340 res_all.res_fs.have_MD5 = TRUE;
342 memset(&res_incexe, 0, sizeof(INCEXE));
343 res_all.res_fs.new_include = TRUE;
344 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
345 if (token == T_EOL) {
348 if (token == T_EOB) {
351 if (token != T_IDENTIFIER) {
352 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
354 for (i=0; newinc_items[i].name; i++) {
355 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
356 token = lex_get_token(lc, T_ALL);
357 if (token != T_EQUALS) {
358 scan_err1(lc, "expected an equals, got: %s", lc->str);
360 /* Call item handler */
361 newinc_items[i].handler(lc, &newinc_items[i], i, pass);
367 scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
371 incexe = (INCEXE *)malloc(sizeof(INCEXE));
372 memcpy(incexe, &res_incexe, sizeof(INCEXE));
373 memset(&res_incexe, 0, sizeof(INCEXE));
374 if (item->code == 0) { /* include */
375 if (res_all.res_fs.num_includes == 0) {
376 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
378 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
379 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
381 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
382 Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
383 } else { /* exclude */
384 if (res_all.res_fs.num_excludes == 0) {
385 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
387 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
388 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
390 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
391 Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
395 set_bit(index, res_all.hdr.item_present);
399 /* Store Match info */
400 static void store_match(LEX *lc, struct res_items *item, int index, int pass)
405 /* Pickup Match string
407 token = lex_get_token(lc, T_ALL);
410 case T_UNQUOTED_STRING:
411 case T_QUOTED_STRING:
412 setup_current_opts();
413 res_incexe.current_opts->match.append(bstrdup(lc->str));
416 scan_err1(lc, _("Expected a filename, got: %s\n"), lc->str);
418 } else { /* pass 2 */
419 lex_get_token(lc, T_ALL);
424 /* Store Base info */
425 static void store_base(LEX *lc, struct res_items *item, int index, int pass)
430 setup_current_opts();
432 * Pickup Base Job Name
434 token = lex_get_token(lc, T_NAME);
435 res_incexe.current_opts->base_list.append(bstrdup(lc->str));
436 } else { /* pass 2 */
437 lex_get_token(lc, T_ALL);
442 * Store Filename info. Note, for minor efficiency reasons, we
443 * always increase the name buffer by 10 items because we expect
444 * to add more entries.
446 static void store_fname(LEX *lc, struct res_items *item, int index, int pass)
452 /* Pickup Filename string
454 token = lex_get_token(lc, T_ALL);
457 case T_UNQUOTED_STRING:
458 case T_QUOTED_STRING:
459 if (res_all.res_fs.have_MD5) {
460 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
462 incexe = &res_incexe;
463 if (incexe->name_list.size() == 0) {
464 incexe->name_list.init(10, true);
466 incexe->name_list.append(bstrdup(lc->str));
467 Dmsg1(200, "Add to name_list %s\n", lc->str);
470 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
472 } else { /* pass 2 */
473 lex_get_token(lc, T_ALL);
479 * New style options come here
481 static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
488 keyword = INC_KW_NONE;
489 /* Look up the keyword */
490 for (i=0; FS_option_kw[i].name; i++) {
491 if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
492 keyword = FS_option_kw[i].token;
496 if (keyword == INC_KW_NONE) {
497 scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
499 /* Now scan for the value */
500 scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
502 setup_current_opts();
503 bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
504 Dmsg2(100, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
511 /* If current_opts not defined, create first entry */
512 static void setup_current_opts(void)
514 if (res_incexe.current_opts == NULL) {
515 res_incexe.current_opts = (FOPTS *)malloc(sizeof(FOPTS));
516 memset(res_incexe.current_opts, 0, sizeof(FOPTS));
517 res_incexe.current_opts->match.init(1, true);
518 res_incexe.current_opts->base_list.init(1, true);
519 res_incexe.num_opts = 1;
520 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
521 res_incexe.opts_list[0] = res_incexe.current_opts;