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