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