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