2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 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 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 store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass);
57 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
58 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
59 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
60 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
61 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
62 static void setup_current_opts(void);
65 /* We build the current resource here as we are
66 * scanning the resource configuration definition,
67 * then move it to allocated memory when the resource
71 extern "C" { // work around visual compiler mangling variables
77 extern int res_all_size;
79 /* We build the current new Include and Exclude items here */
80 static INCEXE res_incexe;
83 * new Include/Exclude items
84 * name handler value code flags default_value
86 static RES_ITEM newinc_items[] = {
87 {"file", store_fname, {0}, 0, 0, 0},
88 {"plugin", store_plugin_name, {0}, 0, 0, 0},
89 {"options", options_res, {0}, 0, 0, 0},
90 {NULL, NULL, {0}, 0, 0, 0}
94 * Items that are valid in an Options resource
96 static RES_ITEM options_items[] = {
97 {"compression", store_opts, {0}, 0, 0, 0},
98 {"signature", store_opts, {0}, 0, 0, 0},
99 {"verify", store_opts, {0}, 0, 0, 0},
100 {"onefs", store_opts, {0}, 0, 0, 0},
101 {"recurse", store_opts, {0}, 0, 0, 0},
102 {"sparse", store_opts, {0}, 0, 0, 0},
103 {"hardlinks", store_opts, {0}, 0, 0, 0},
104 {"readfifo", store_opts, {0}, 0, 0, 0},
105 {"replace", store_opts, {0}, 0, 0, 0},
106 {"portable", store_opts, {0}, 0, 0, 0},
107 {"mtimeonly", store_opts, {0}, 0, 0, 0},
108 {"keepatime", store_opts, {0}, 0, 0, 0},
109 {"regex", store_regex, {0}, 0, 0, 0},
110 {"regexdir", store_regex, {0}, 1, 0, 0},
111 {"regexfile", store_regex, {0}, 2, 0, 0},
112 {"base", store_base, {0}, 0, 0, 0},
113 {"wild", store_wild, {0}, 0, 0, 0},
114 {"wilddir", store_wild, {0}, 1, 0, 0},
115 {"wildfile", store_wild, {0}, 2, 0, 0},
116 {"exclude", store_opts, {0}, 0, 0, 0},
117 {"aclsupport", store_opts, {0}, 0, 0, 0},
118 {"plugin", store_plugin, {0}, 0, 0, 0},
119 {"reader", store_reader, {0}, 0, 0, 0},
120 {"writer", store_writer, {0}, 0, 0, 0},
121 {"ignorecase", store_opts, {0}, 0, 0, 0},
122 {"fstype", store_fstype, {0}, 0, 0, 0},
123 {"hfsplussupport", store_opts, {0}, 0, 0, 0},
124 {"noatime", store_opts, {0}, 0, 0, 0},
125 {"enhancedwild", store_opts, {0}, 0, 0, 0},
126 {"drivetype", store_drivetype, {0}, 0, 0, 0},
127 {"checkfilechanges",store_opts, {0}, 0, 0, 0},
128 {"strippath", store_opts, {0}, 0, 0, 0},
129 {NULL, NULL, {0}, 0, 0, 0}
133 /* Define FileSet KeyWord values */
144 INC_KW_REPLACE, /* restore options */
145 INC_KW_READFIFO, /* Causes fifo data to be read */
160 * This is the list of options that can be stored by store_opts
161 * Note, now that the old style Include/Exclude code is gone,
162 * the INC_KW code could be put into the "code" field of the
163 * options given above.
165 static struct s_kw FS_option_kw[] = {
166 {"compression", INC_KW_COMPRESSION},
167 {"signature", INC_KW_DIGEST},
168 {"encryption", INC_KW_ENCRYPTION},
169 {"verify", INC_KW_VERIFY},
170 {"onefs", INC_KW_ONEFS},
171 {"recurse", INC_KW_RECURSE},
172 {"sparse", INC_KW_SPARSE},
173 {"hardlinks", INC_KW_HARDLINK},
174 {"replace", INC_KW_REPLACE},
175 {"readfifo", INC_KW_READFIFO},
176 {"portable", INC_KW_PORTABLE},
177 {"mtimeonly", INC_KW_MTIMEONLY},
178 {"keepatime", INC_KW_KEEPATIME},
179 {"exclude", INC_KW_EXCLUDE},
180 {"aclsupport", INC_KW_ACL},
181 {"ignorecase", INC_KW_IGNORECASE},
182 {"hfsplussupport", INC_KW_HFSPLUS},
183 {"noatime", INC_KW_NOATIME},
184 {"enhancedwild", INC_KW_ENHANCEDWILD},
185 {"checkfilechanges", INC_KW_CHKCHANGES},
186 {"strippath", INC_KW_STRIPPATH},
190 /* Options for FileSet keywords */
199 * Options permitted for each keyword and resulting value.
200 * The output goes into opts, which are then transmitted to
201 * the FD for application as options to the following list of
204 static struct s_fs_opt FS_options[] = {
205 {"md5", INC_KW_DIGEST, "M"},
206 {"sha1", INC_KW_DIGEST, "S"},
207 {"sha256", INC_KW_DIGEST, "S2"},
208 {"sha512", INC_KW_DIGEST, "S3"},
209 {"gzip", INC_KW_COMPRESSION, "Z6"},
210 {"gzip1", INC_KW_COMPRESSION, "Z1"},
211 {"gzip2", INC_KW_COMPRESSION, "Z2"},
212 {"gzip3", INC_KW_COMPRESSION, "Z3"},
213 {"gzip4", INC_KW_COMPRESSION, "Z4"},
214 {"gzip5", INC_KW_COMPRESSION, "Z5"},
215 {"gzip6", INC_KW_COMPRESSION, "Z6"},
216 {"gzip7", INC_KW_COMPRESSION, "Z7"},
217 {"gzip8", INC_KW_COMPRESSION, "Z8"},
218 {"gzip9", INC_KW_COMPRESSION, "Z9"},
219 {"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
220 {"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
221 {"yes", INC_KW_ONEFS, "0"},
222 {"no", INC_KW_ONEFS, "f"},
223 {"yes", INC_KW_RECURSE, "0"},
224 {"no", INC_KW_RECURSE, "h"},
225 {"yes", INC_KW_SPARSE, "s"},
226 {"no", INC_KW_SPARSE, "0"},
227 {"yes", INC_KW_HARDLINK, "0"},
228 {"no", INC_KW_HARDLINK, "H"},
229 {"always", INC_KW_REPLACE, "a"},
230 {"ifnewer", INC_KW_REPLACE, "w"},
231 {"never", INC_KW_REPLACE, "n"},
232 {"yes", INC_KW_READFIFO, "r"},
233 {"no", INC_KW_READFIFO, "0"},
234 {"yes", INC_KW_PORTABLE, "p"},
235 {"no", INC_KW_PORTABLE, "0"},
236 {"yes", INC_KW_MTIMEONLY, "m"},
237 {"no", INC_KW_MTIMEONLY, "0"},
238 {"yes", INC_KW_KEEPATIME, "k"},
239 {"no", INC_KW_KEEPATIME, "0"},
240 {"yes", INC_KW_EXCLUDE, "e"},
241 {"no", INC_KW_EXCLUDE, "0"},
242 {"yes", INC_KW_ACL, "A"},
243 {"no", INC_KW_ACL, "0"},
244 {"yes", INC_KW_IGNORECASE, "i"},
245 {"no", INC_KW_IGNORECASE, "0"},
246 {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */
247 {"no", INC_KW_HFSPLUS, "0"},
248 {"yes", INC_KW_NOATIME, "K"},
249 {"no", INC_KW_NOATIME, "0"},
250 {"yes", INC_KW_ENHANCEDWILD, "K"},
251 {"no", INC_KW_ENHANCEDWILD, "0"},
252 {"yes", INC_KW_CHKCHANGES, "c"},
253 {"no", INC_KW_CHKCHANGES, "0"},
260 * Scan for right hand side of Include options (keyword=option) is
261 * converted into one or two characters. Verifyopts=xxxx is Vxxxx:
262 * Whatever is found is concatenated to the opts string.
263 * This code is also used inside an Options resource.
265 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
269 int lcopts = lc->options;
271 option[0] = 0; /* default option = none */
272 option[2] = 0; /* terminate options */
273 lc->options |= LOPT_STRING; /* force string */
274 token = lex_get_token(lc, T_STRING); /* expect at least one option */
275 if (keyword == INC_KW_VERIFY) { /* special case */
276 /* ***FIXME**** ensure these are in permitted set */
277 bstrncat(opts, "V", optlen); /* indicate Verify */
278 bstrncat(opts, lc->str, optlen);
279 bstrncat(opts, ":", optlen); /* terminate it */
280 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
281 } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
282 if (!is_an_integer(lc->str)) {
283 scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
285 bstrncat(opts, "P", optlen); /* indicate strip path */
286 bstrncat(opts, lc->str, optlen);
287 bstrncat(opts, ":", optlen); /* terminate it */
288 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
290 * Standard keyword options for Include/Exclude
293 for (i=0; FS_options[i].name; i++) {
294 if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
295 /* NOTE! maximum 2 letters here or increase option[3] */
296 option[0] = FS_options[i].option[0];
297 option[1] = FS_options[i].option[1];
303 scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
304 } else { /* add option */
305 bstrncat(opts, option, optlen);
306 Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
309 lc->options = lcopts;
311 /* If option terminated by comma, eat it */
313 token = lex_get_token(lc, T_ALL); /* yes, eat comma */
319 * Store FileSet Include/Exclude info
320 * NEW style includes are handled in store_newinc()
322 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
327 * Decide if we are doing a new Include or an old include. The
328 * new Include is followed immediately by open brace, whereas the
329 * old include has options following the Include.
331 token = lex_get_token(lc, T_SKIP_EOL);
332 if (token == T_BOB) {
333 store_newinc(lc, item, index, pass);
336 scan_err0(lc, _("Old style Include/Exclude not supported\n"));
341 * Store NEW style FileSet FInclude/FExclude info
343 * Note, when this routine is called, we are inside a FileSet
344 * resource. We treat the Include/Execlude like a sort of
345 * mini-resource within the FileSet resource.
347 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
353 if (!res_all.res_fs.have_MD5) {
354 MD5Init(&res_all.res_fs.md5c);
355 res_all.res_fs.have_MD5 = true;
357 memset(&res_incexe, 0, sizeof(INCEXE));
358 res_all.res_fs.new_include = true;
359 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
360 if (token == T_EOB) {
363 if (token != T_IDENTIFIER) {
364 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
366 for (i=0; newinc_items[i].name; i++) {
367 options = strcasecmp(lc->str, "options") == 0;
368 if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
370 token = lex_get_token(lc, T_SKIP_EOL);
371 if (token != T_EQUALS) {
372 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
375 /* Call item handler */
376 newinc_items[i].handler(lc, &newinc_items[i], i, pass);
382 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
386 incexe = (INCEXE *)malloc(sizeof(INCEXE));
387 memcpy(incexe, &res_incexe, sizeof(INCEXE));
388 memset(&res_incexe, 0, sizeof(INCEXE));
389 if (item->code == 0) { /* include */
390 if (res_all.res_fs.num_includes == 0) {
391 res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
393 res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
394 sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
396 res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
397 Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
398 } else { /* exclude */
399 if (res_all.res_fs.num_excludes == 0) {
400 res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
402 res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
403 sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
405 res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
406 Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
410 set_bit(index, res_all.hdr.item_present);
414 /* Store regex info */
415 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
423 token = lex_get_token(lc, T_SKIP_EOL);
425 /* Pickup regex string
429 case T_UNQUOTED_STRING:
430 case T_QUOTED_STRING:
431 rc = regcomp(&preg, lc->str, REG_EXTENDED);
433 regerror(rc, &preg, prbuf, sizeof(prbuf));
435 scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
439 if (item->code == 1) {
441 res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
442 newsize = res_incexe.current_opts->regexdir.size();
443 } else if (item->code == 2) {
445 res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
446 newsize = res_incexe.current_opts->regexfile.size();
449 res_incexe.current_opts->regex.append(bstrdup(lc->str));
450 newsize = res_incexe.current_opts->regex.size();
452 Dmsg4(900, "set %s %p size=%d %s\n",
453 type, res_incexe.current_opts, newsize, lc->str);
456 scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
462 /* Store Base info */
463 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
467 token = lex_get_token(lc, T_NAME);
470 * Pickup Base Job Name
472 res_incexe.current_opts->base.append(bstrdup(lc->str));
477 /* Store reader info */
478 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
482 token = lex_get_token(lc, T_NAME);
485 * Pickup plugin command
487 res_incexe.current_opts->plugin = bstrdup(lc->str);
493 /* Store reader info */
494 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
498 token = lex_get_token(lc, T_NAME);
501 * Pickup reader command
503 res_incexe.current_opts->reader = bstrdup(lc->str);
508 /* Store writer innfo */
509 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
513 token = lex_get_token(lc, T_NAME);
516 * Pickup writer command
518 res_incexe.current_opts->writer = bstrdup(lc->str);
525 /* Store Wild-card info */
526 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
532 token = lex_get_token(lc, T_SKIP_EOL);
535 * Pickup Wild-card string
539 case T_UNQUOTED_STRING:
540 case T_QUOTED_STRING:
541 if (item->code == 1) {
543 res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
544 newsize = res_incexe.current_opts->wilddir.size();
545 } else if (item->code == 2) {
546 if (strpbrk(lc->str, "/\\") != NULL) {
548 res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
549 newsize = res_incexe.current_opts->wildfile.size();
552 res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
553 newsize = res_incexe.current_opts->wildbase.size();
557 res_incexe.current_opts->wild.append(bstrdup(lc->str));
558 newsize = res_incexe.current_opts->wild.size();
560 Dmsg4(9, "set %s %p size=%d %s\n",
561 type, res_incexe.current_opts, newsize, lc->str);
564 scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
570 /* Store fstype info */
571 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
575 token = lex_get_token(lc, T_SKIP_EOL);
577 /* Pickup fstype string */
580 case T_UNQUOTED_STRING:
581 case T_QUOTED_STRING:
582 res_incexe.current_opts->fstype.append(bstrdup(lc->str));
583 Dmsg3(900, "set fstype %p size=%d %s\n",
584 res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
587 scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
593 /* Store drivetype info */
594 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
598 token = lex_get_token(lc, T_SKIP_EOL);
600 /* Pickup drivetype string */
603 case T_UNQUOTED_STRING:
604 case T_QUOTED_STRING:
605 res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
606 Dmsg3(900, "set drivetype %p size=%d %s\n",
607 res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
610 scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
617 * Store Filename info. Note, for minor efficiency reasons, we
618 * always increase the name buffer by 10 items because we expect
619 * to add more entries.
621 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
626 token = lex_get_token(lc, T_SKIP_EOL);
628 /* Pickup Filename string
632 case T_UNQUOTED_STRING:
633 if (strchr(lc->str, '\\')) {
634 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
637 case T_QUOTED_STRING:
638 if (res_all.res_fs.have_MD5) {
639 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
641 incexe = &res_incexe;
642 if (incexe->name_list.size() == 0) {
643 incexe->name_list.init(10, true);
645 incexe->name_list.append(bstrdup(lc->str));
646 Dmsg1(900, "Add to name_list %s\n", lc->str);
649 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
656 * Store Filename info. Note, for minor efficiency reasons, we
657 * always increase the name buffer by 10 items because we expect
658 * to add more entries.
660 static void store_plugin_name(LEX *lc, RES_ITEM *item, int index, int pass)
665 token = lex_get_token(lc, T_SKIP_EOL);
667 /* Pickup Filename string
671 case T_UNQUOTED_STRING:
672 if (strchr(lc->str, '\\')) {
673 scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
676 case T_QUOTED_STRING:
677 if (res_all.res_fs.have_MD5) {
678 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
680 incexe = &res_incexe;
681 if (incexe->plugin_list.size() == 0) {
682 incexe->plugin_list.init(10, true);
684 incexe->plugin_list.append(bstrdup(lc->str));
685 Dmsg1(900, "Add to plugin_list %s\n", lc->str);
688 scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
697 * Come here when Options seen in Include/Exclude
699 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
703 token = lex_get_token(lc, T_SKIP_EOL);
704 if (token != T_BOB) {
705 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
709 setup_current_opts();
712 while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
713 if (token == T_EOL) {
716 if (token == T_EOB) {
719 if (token != T_IDENTIFIER) {
720 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
722 for (i=0; options_items[i].name; i++) {
723 if (strcasecmp(options_items[i].name, lc->str) == 0) {
724 token = lex_get_token(lc, T_SKIP_EOL);
725 if (token != T_EQUALS) {
726 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
728 /* Call item handler */
729 options_items[i].handler(lc, &options_items[i], i, pass);
735 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
742 * New style options come here
744 static 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);
773 /* If current_opts not defined, create first entry */
774 static void setup_current_opts(void)
776 FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
777 memset(fo, 0, sizeof(FOPTS));
778 fo->regex.init(1, true);
779 fo->regexdir.init(1, true);
780 fo->regexfile.init(1, true);
781 fo->wild.init(1, true);
782 fo->wilddir.init(1, true);
783 fo->wildfile.init(1, true);
784 fo->wildbase.init(1, true);
785 fo->base.init(1, true);
786 fo->fstype.init(1, true);
787 fo->drivetype.init(1, true);
788 res_incexe.current_opts = fo;
789 if (res_incexe.num_opts == 0) {
790 res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
792 res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
793 sizeof(FOPTS *) * (res_incexe.num_opts + 1));
795 res_incexe.opts_list[res_incexe.num_opts++] = fo;