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