]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
Correct pool source setting
[bacula/bacula] / bacula / src / dird / inc_conf.c
1 /*
2  *   Configuration file parser for new and old Include and
3  *      Exclude records
4  *
5  *     Kern Sibbald, March MMIII
6  *
7  *     Version $Id$
8  */
9 /*
10    Copyright (C) 2003-2006 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
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 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26 #ifndef HAVE_REGEX_H
27 #include "lib/regex.h"
28 #else
29 #include <regex.h>
30 #endif
31
32 /* Forward referenced subroutines */
33
34 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
35
36 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
37 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
38 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
39 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
40 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
41 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass);
42 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
43 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
44 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
45 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
46 static void setup_current_opts(void);
47
48
49 /* We build the current resource here as we are
50  * scanning the resource configuration definition,
51  * then move it to allocated memory when the resource
52  * scan is complete.
53  */
54 extern URES res_all;
55 extern int  res_all_size;
56
57 /* We build the current new Include and Exclude items here */
58 static INCEXE res_incexe;
59
60 /*
61  * new Include/Exclude items
62  *   name             handler     value    code flags default_value
63  */
64 static RES_ITEM newinc_items[] = {
65    {"file",            store_fname,   {0},      0, 0, 0},
66    {"options",         options_res,   {0},      0, 0, 0},
67    {NULL, NULL, {0}, 0, 0, 0}
68 };
69
70 /*
71  * Items that are valid in an Options resource
72  */
73 static RES_ITEM options_items[] = {
74    {"compression",     store_opts,    {0},     0, 0, 0},
75    {"signature",       store_opts,    {0},     0, 0, 0},
76    {"verify",          store_opts,    {0},     0, 0, 0},
77    {"onefs",           store_opts,    {0},     0, 0, 0},
78    {"recurse",         store_opts,    {0},     0, 0, 0},
79    {"sparse",          store_opts,    {0},     0, 0, 0},
80    {"hardlinks",       store_opts,    {0},     0, 0, 0},
81    {"readfifo",        store_opts,    {0},     0, 0, 0},
82    {"replace",         store_opts,    {0},     0, 0, 0},
83    {"portable",        store_opts,    {0},     0, 0, 0},
84    {"mtimeonly",       store_opts,    {0},     0, 0, 0},
85    {"keepatime",       store_opts,    {0},     0, 0, 0},
86    {"regex",           store_regex,   {0},     0, 0, 0},
87    {"regexdir",        store_regex,   {0},     1, 0, 0},
88    {"regexfile",       store_regex,   {0},     2, 0, 0},
89    {"base",            store_base,    {0},     0, 0, 0},
90    {"wild",            store_wild,    {0},     0, 0, 0},
91    {"wilddir",         store_wild,    {0},     1, 0, 0},
92    {"wildfile",        store_wild,    {0},     2, 0, 0},
93    {"exclude",         store_opts,    {0},     0, 0, 0},
94    {"aclsupport",      store_opts,    {0},     0, 0, 0},
95    {"reader",          store_reader,  {0},     0, 0, 0},
96    {"writer",          store_writer,  {0},     0, 0, 0},
97    {"ignorecase",      store_opts,    {0},     0, 0, 0},
98    {"fstype",          store_fstype,  {0},     0, 0, 0},
99    {"hfsplussupport",  store_opts,    {0},     0, 0, 0},
100    {"noatime",         store_opts,    {0},     0, 0, 0},
101    {NULL, NULL, {0}, 0, 0, 0}
102 };
103
104
105 /* Define FileSet KeyWord values */
106 enum {
107    INC_KW_NONE,
108    INC_KW_COMPRESSION,
109    INC_KW_DIGEST,
110    INC_KW_ENCRYPTION,
111    INC_KW_VERIFY,
112    INC_KW_ONEFS,
113    INC_KW_RECURSE,
114    INC_KW_SPARSE,
115    INC_KW_HARDLINK,
116    INC_KW_REPLACE,               /* restore options */
117    INC_KW_READFIFO,              /* Causes fifo data to be read */
118    INC_KW_PORTABLE,
119    INC_KW_MTIMEONLY,
120    INC_KW_KEEPATIME,
121    INC_KW_EXCLUDE,
122    INC_KW_ACL,
123    INC_KW_IGNORECASE,
124    INC_KW_HFSPLUS,
125    INC_KW_NOATIME
126 };
127
128 /*
129  * This is the list of options that can be stored by store_opts
130  *   Note, now that the old style Include/Exclude code is gone,
131  *   the INC_KW code could be put into the "code" field of the
132  *   options given above.
133  */
134 static struct s_kw FS_option_kw[] = {
135    {"compression", INC_KW_COMPRESSION},
136    {"signature",   INC_KW_DIGEST},
137    {"encryption",  INC_KW_ENCRYPTION},
138    {"verify",      INC_KW_VERIFY},
139    {"onefs",       INC_KW_ONEFS},
140    {"recurse",     INC_KW_RECURSE},
141    {"sparse",      INC_KW_SPARSE},
142    {"hardlinks",   INC_KW_HARDLINK},
143    {"replace",     INC_KW_REPLACE},
144    {"readfifo",    INC_KW_READFIFO},
145    {"portable",    INC_KW_PORTABLE},
146    {"mtimeonly",   INC_KW_MTIMEONLY},
147    {"keepatime",   INC_KW_KEEPATIME},
148    {"exclude",     INC_KW_EXCLUDE},
149    {"aclsupport",  INC_KW_ACL},
150    {"ignorecase",  INC_KW_IGNORECASE},
151    {"hfsplussupport", INC_KW_HFSPLUS},
152    {"noatime",     INC_KW_NOATIME},
153    {NULL,          0}
154 };
155
156 /* Options for FileSet keywords */
157
158 struct s_fs_opt {
159    const char *name;
160    int keyword;
161    const char *option;
162 };
163
164 /*
165  * Options permitted for each keyword and resulting value.
166  * The output goes into opts, which are then transmitted to
167  * the FD for application as options to the following list of
168  * included files.
169  */
170 static struct s_fs_opt FS_options[] = {
171    {"md5",      INC_KW_DIGEST,        "M"},
172    {"sha1",     INC_KW_DIGEST,        "S"},
173    {"sha256",   INC_KW_DIGEST,       "S2"},
174    {"sha512",   INC_KW_DIGEST,       "S3"},
175    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
176    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
177    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
178    {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
179    {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
180    {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
181    {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
182    {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
183    {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
184    {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
185    {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
186    {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
187    {"yes",      INC_KW_ONEFS,         "0"},
188    {"no",       INC_KW_ONEFS,         "f"},
189    {"yes",      INC_KW_RECURSE,       "0"},
190    {"no",       INC_KW_RECURSE,       "h"},
191    {"yes",      INC_KW_SPARSE,        "s"},
192    {"no",       INC_KW_SPARSE,        "0"},
193    {"yes",      INC_KW_HARDLINK,      "0"},
194    {"no",       INC_KW_HARDLINK,      "H"},
195    {"always",   INC_KW_REPLACE,       "a"},
196    {"ifnewer",  INC_KW_REPLACE,       "w"},
197    {"never",    INC_KW_REPLACE,       "n"},
198    {"yes",      INC_KW_READFIFO,      "r"},
199    {"no",       INC_KW_READFIFO,      "0"},
200    {"yes",      INC_KW_PORTABLE,      "p"},
201    {"no",       INC_KW_PORTABLE,      "0"},
202    {"yes",      INC_KW_MTIMEONLY,     "m"},
203    {"no",       INC_KW_MTIMEONLY,     "0"},
204    {"yes",      INC_KW_KEEPATIME,     "k"},
205    {"no",       INC_KW_KEEPATIME,     "0"},
206    {"yes",      INC_KW_EXCLUDE,       "e"},
207    {"no",       INC_KW_EXCLUDE,       "0"},
208    {"yes",      INC_KW_ACL,           "A"},
209    {"no",       INC_KW_ACL,           "0"},
210    {"yes",      INC_KW_IGNORECASE,    "i"},
211    {"no",       INC_KW_IGNORECASE,    "0"},
212    {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
213    {"no",       INC_KW_HFSPLUS,       "0"},
214    {"yes",      INC_KW_NOATIME,       "K"},
215    {"no",       INC_KW_NOATIME,       "0"},
216    {NULL,       0,                      0}
217 };
218
219
220
221 /*
222  * Scan for right hand side of Include options (keyword=option) is
223  *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
224  *    Whatever is found is concatenated to the opts string.
225  * This code is also used inside an Options resource.
226  */
227 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
228 {
229    int token, i;
230    char option[3];
231    int lcopts = lc->options;
232
233    option[0] = 0;                     /* default option = none */
234    option[2] = 0;                     /* terminate options */
235    lc->options |= LOPT_STRING;        /* force string */
236    token = lex_get_token(lc, T_STRING);          /* expect at least one option */
237    if (keyword == INC_KW_VERIFY) { /* special case */
238       /* ***FIXME**** ensure these are in permitted set */
239       bstrncat(opts, "V", optlen);         /* indicate Verify */
240       bstrncat(opts, lc->str, optlen);
241       bstrncat(opts, ":", optlen);         /* terminate it */
242       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
243
244    /*
245     * Standard keyword options for Include/Exclude
246     */
247    } else {
248       for (i=0; FS_options[i].name; i++) {
249          if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
250             /* NOTE! maximum 2 letters here or increase option[3] */
251             option[0] = FS_options[i].option[0];
252             option[1] = FS_options[i].option[1];
253             i = 0;
254             break;
255          }
256       }
257       if (i != 0) {
258          scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
259       } else { /* add option */
260          bstrncat(opts, option, optlen);
261          Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
262       }
263    }
264    lc->options = lcopts;
265
266    /* If option terminated by comma, eat it */
267    if (lc->ch == ',') {
268       token = lex_get_token(lc, T_ALL);      /* yes, eat comma */
269    }
270 }
271
272 /*
273  *
274  * Store FileSet Include/Exclude info
275  *  NEW style includes are handled in store_newinc()
276  */
277 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
278 {
279    int token;
280
281    /*
282     * Decide if we are doing a new Include or an old include. The
283     *  new Include is followed immediately by open brace, whereas the
284     *  old include has options following the Include.
285     */
286    token = lex_get_token(lc, T_SKIP_EOL);
287    if (token == T_BOB) {
288       store_newinc(lc, item, index, pass);
289       return;
290    }
291    scan_err0(lc, _("Old style Include/Exclude not supported\n"));
292 }
293
294
295 /*
296  * Store NEW style FileSet FInclude/FExclude info
297  *
298  *  Note, when this routine is called, we are inside a FileSet
299  *  resource.  We treat the Include/Execlude like a sort of
300  *  mini-resource within the FileSet resource.
301  */
302 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
303 {
304    int token, i;
305    INCEXE *incexe;
306    bool options;
307
308    if (!res_all.res_fs.have_MD5) {
309       MD5Init(&res_all.res_fs.md5c);
310       res_all.res_fs.have_MD5 = true;
311    }
312    memset(&res_incexe, 0, sizeof(INCEXE));
313    res_all.res_fs.new_include = true;
314    while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
315       if (token == T_EOB) {
316          break;
317       }
318       if (token != T_IDENTIFIER) {
319          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
320       }
321       for (i=0; newinc_items[i].name; i++) {
322          options = strcasecmp(lc->str, "options") == 0;
323          if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
324             if (!options) {
325                token = lex_get_token(lc, T_SKIP_EOL);
326                if (token != T_EQUALS) {
327                   scan_err1(lc, _("expected an equals, got: %s"), lc->str);
328                }
329             }
330             /* Call item handler */
331             newinc_items[i].handler(lc, &newinc_items[i], i, pass);
332             i = -1;
333             break;
334          }
335       }
336       if (i >=0) {
337          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
338       }
339    }
340    if (pass == 1) {
341       incexe = (INCEXE *)malloc(sizeof(INCEXE));
342       memcpy(incexe, &res_incexe, sizeof(INCEXE));
343       memset(&res_incexe, 0, sizeof(INCEXE));
344       if (item->code == 0) { /* include */
345          if (res_all.res_fs.num_includes == 0) {
346             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
347          } else {
348             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
349                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
350          }
351          res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
352          Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
353       } else {    /* exclude */
354          if (res_all.res_fs.num_excludes == 0) {
355             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
356          } else {
357             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
358                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
359          }
360          res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
361          Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
362       }
363    }
364    scan_to_eol(lc);
365    set_bit(index, res_all.hdr.item_present);
366 }
367
368
369 /* Store regex info */
370 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
371 {
372    int token, rc;
373    regex_t preg;
374    char prbuf[500];
375    const char *type;
376    int newsize;
377
378    token = lex_get_token(lc, T_SKIP_EOL);
379    if (pass == 1) {
380       /* Pickup regex string
381        */
382       switch (token) {
383       case T_IDENTIFIER:
384       case T_UNQUOTED_STRING:
385       case T_QUOTED_STRING:
386          rc = regcomp(&preg, lc->str, REG_EXTENDED);
387          if (rc != 0) {
388             regerror(rc, &preg, prbuf, sizeof(prbuf));
389             regfree(&preg);
390             scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
391             break;
392          }
393          regfree(&preg);
394          if (item->code == 1) {
395             type = "regexdir";
396             res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
397             newsize = res_incexe.current_opts->regexdir.size();
398          } else if (item->code == 2) {
399             type = "regexfile";
400             res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
401             newsize = res_incexe.current_opts->regexfile.size();
402          } else {
403             type = "regex";
404             res_incexe.current_opts->regex.append(bstrdup(lc->str));
405             newsize = res_incexe.current_opts->regex.size();
406          }
407          Dmsg4(900, "set %s %p size=%d %s\n",
408             type, res_incexe.current_opts, newsize, lc->str);
409          break;
410       default:
411          scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
412       }
413    }
414    scan_to_eol(lc);
415 }
416
417 /* Store Base info */
418 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
419 {
420    int token;
421
422    token = lex_get_token(lc, T_NAME);
423    if (pass == 1) {
424       /*
425        * Pickup Base Job Name
426        */
427       res_incexe.current_opts->base.append(bstrdup(lc->str));
428    }
429    scan_to_eol(lc);
430 }
431
432 /* Store reader info */
433 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
434 {
435    int token;
436
437    token = lex_get_token(lc, T_NAME);
438    if (pass == 1) {
439       /*
440        * Pickup reader command
441        */
442       res_incexe.current_opts->reader = bstrdup(lc->str);
443    }
444    scan_to_eol(lc);
445 }
446
447 /* Store writer innfo */
448 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
449 {
450    int token;
451
452    token = lex_get_token(lc, T_NAME);
453    if (pass == 1) {
454       /*
455        * Pickup writer command
456        */
457       res_incexe.current_opts->writer = bstrdup(lc->str);
458    }
459    scan_to_eol(lc);
460 }
461
462
463
464 /* Store Wild-card info */
465 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
466 {
467    int token;
468    const char *type;
469    int newsize;
470
471    token = lex_get_token(lc, T_SKIP_EOL);
472    if (pass == 1) {
473       /*
474        * Pickup Wild-card string
475        */
476       switch (token) {
477       case T_IDENTIFIER:
478       case T_UNQUOTED_STRING:
479       case T_QUOTED_STRING:
480          if (item->code == 1) {
481             type = "wilddir";
482             res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
483             newsize = res_incexe.current_opts->wilddir.size();
484          } else if (item->code == 2) {
485             type = "wildfile";
486             res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
487             newsize = res_incexe.current_opts->wildfile.size();
488          } else {
489             type = "wild";
490             res_incexe.current_opts->wild.append(bstrdup(lc->str));
491             newsize = res_incexe.current_opts->wild.size();
492          }
493          Dmsg4(9, "set %s %p size=%d %s\n",
494             type, res_incexe.current_opts, newsize, lc->str);
495          break;
496       default:
497          scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
498       }
499    }
500    scan_to_eol(lc);
501 }
502
503 /* Store fstype info */
504 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
505 {
506    int token;
507
508    token = lex_get_token(lc, T_SKIP_EOL);
509    if (pass == 1) {
510       /* Pickup fstype string */
511       switch (token) {
512       case T_IDENTIFIER:
513       case T_UNQUOTED_STRING:
514       case T_QUOTED_STRING:
515          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
516          Dmsg3(900, "set fstype %p size=%d %s\n",
517             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
518          break;
519       default:
520          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
521       }
522    }
523    scan_to_eol(lc);
524 }
525
526 /*
527  * Store Filename info. Note, for minor efficiency reasons, we
528  * always increase the name buffer by 10 items because we expect
529  * to add more entries.
530  */
531 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
532 {
533    int token;
534    INCEXE *incexe;
535
536    token = lex_get_token(lc, T_SKIP_EOL);
537    if (pass == 1) {
538       /* Pickup Filename string
539        */
540       switch (token) {
541       case T_IDENTIFIER:
542       case T_UNQUOTED_STRING:
543          if (strchr(lc->str, '\\')) {
544             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
545             /* NOT REACHED */
546          }
547       case T_QUOTED_STRING:
548          if (res_all.res_fs.have_MD5) {
549             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
550          }
551          incexe = &res_incexe;
552          if (incexe->name_list.size() == 0) {
553             incexe->name_list.init(10, true);
554          }
555          incexe->name_list.append(bstrdup(lc->str));
556          Dmsg1(900, "Add to name_list %s\n", lc->str);
557          break;
558       default:
559          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
560       }
561    }
562    scan_to_eol(lc);
563 }
564
565
566 /*
567  * Come here when Options seen in Include/Exclude
568  */
569 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
570 {
571    int token, i;
572
573    token = lex_get_token(lc, T_SKIP_EOL);
574    if (token != T_BOB) {
575       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
576    }
577
578    if (pass == 1) {
579       setup_current_opts();
580    }
581
582    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
583       if (token == T_EOL) {
584          continue;
585       }
586       if (token == T_EOB) {
587          break;
588       }
589       if (token != T_IDENTIFIER) {
590          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
591       }
592       for (i=0; options_items[i].name; i++) {
593          if (strcasecmp(options_items[i].name, lc->str) == 0) {
594             token = lex_get_token(lc, T_SKIP_EOL);
595             if (token != T_EQUALS) {
596                scan_err1(lc, _("expected an equals, got: %s"), lc->str);
597             }
598             /* Call item handler */
599             options_items[i].handler(lc, &options_items[i], i, pass);
600             i = -1;
601             break;
602          }
603       }
604       if (i >=0) {
605          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
606       }
607    }
608 }
609
610
611 /*
612  * New style options come here
613  */
614 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
615 {
616    int i;
617    int keyword;
618    char inc_opts[100];
619
620    inc_opts[0] = 0;
621    keyword = INC_KW_NONE;
622    /* Look up the keyword */
623    for (i=0; FS_option_kw[i].name; i++) {
624       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
625          keyword = FS_option_kw[i].token;
626          break;
627       }
628    }
629    if (keyword == INC_KW_NONE) {
630       scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
631    }
632    /* Now scan for the value */
633    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
634    if (pass == 1) {
635       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
636       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
637    }
638    scan_to_eol(lc);
639 }
640
641
642
643 /* If current_opts not defined, create first entry */
644 static void setup_current_opts(void)
645 {
646    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
647    memset(fo, 0, sizeof(FOPTS));
648    fo->regex.init(1, true);
649    fo->regexdir.init(1, true);
650    fo->regexfile.init(1, true);
651    fo->wild.init(1, true);
652    fo->wilddir.init(1, true);
653    fo->wildfile.init(1, true);
654    fo->base.init(1, true);
655    fo->fstype.init(1, true);
656    res_incexe.current_opts = fo;
657    if (res_incexe.num_opts == 0) {
658       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
659    } else {
660       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
661                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
662    }
663    res_incexe.opts_list[res_incexe.num_opts++] = fo;
664 }