]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
Recompile configure
[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 token, 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    token = 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       token = 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    int token;
495
496    token = lex_get_token(lc, T_NAME);
497    if (pass == 1) {
498       /*
499        * Pickup Base Job Name
500        */
501       res_incexe.current_opts->base.append(bstrdup(lc->str));
502    }
503    scan_to_eol(lc);
504 }
505
506 /* Store reader info */
507 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
508 {
509    int token;
510
511    token = lex_get_token(lc, T_NAME);
512    if (pass == 1) {
513       /*
514        * Pickup plugin command
515        */
516       res_incexe.current_opts->plugin = bstrdup(lc->str);
517    }
518    scan_to_eol(lc);
519 }
520
521
522 /* Store Wild-card info */
523 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
524 {
525    int token;
526    const char *type;
527    int newsize;
528
529    token = lex_get_token(lc, T_SKIP_EOL);
530    if (pass == 1) {
531       /*
532        * Pickup Wild-card string
533        */
534       switch (token) {
535       case T_IDENTIFIER:
536       case T_UNQUOTED_STRING:
537       case T_QUOTED_STRING:
538          if (item->code == 1) {
539             type = "wilddir";
540             res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
541             newsize = res_incexe.current_opts->wilddir.size();
542          } else if (item->code == 2) {
543             if (strpbrk(lc->str, "/\\") != NULL) {
544                type = "wildfile";
545                res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
546                newsize = res_incexe.current_opts->wildfile.size();
547             } else {
548                type = "wildbase";
549                res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
550                newsize = res_incexe.current_opts->wildbase.size();
551             }
552          } else {
553             type = "wild";
554             res_incexe.current_opts->wild.append(bstrdup(lc->str));
555             newsize = res_incexe.current_opts->wild.size();
556          }
557          Dmsg4(9, "set %s %p size=%d %s\n",
558             type, res_incexe.current_opts, newsize, lc->str);
559          break;
560       default:
561          scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
562       }
563    }
564    scan_to_eol(lc);
565 }
566
567 /* Store fstype info */
568 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
569 {
570    int token;
571
572    token = lex_get_token(lc, T_SKIP_EOL);
573    if (pass == 1) {
574       /* Pickup fstype string */
575       switch (token) {
576       case T_IDENTIFIER:
577       case T_UNQUOTED_STRING:
578       case T_QUOTED_STRING:
579          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
580          Dmsg3(900, "set fstype %p size=%d %s\n",
581             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
582          break;
583       default:
584          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
585       }
586    }
587    scan_to_eol(lc);
588 }
589
590 /* Store exclude directory containing  info */
591 static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
592 {
593    int token;
594
595    if (exclude) {
596       scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
597       /* NOT REACHED */
598    }
599    token = lex_get_token(lc, T_NAME);
600    if (pass == 1) {
601       res_incexe.ignoredir = bstrdup(lc->str);
602    }
603    scan_to_eol(lc);
604 }
605
606 /* Store drivetype info */
607 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
608 {
609    int token;
610
611    token = lex_get_token(lc, T_SKIP_EOL);
612    if (pass == 1) {
613       /* Pickup drivetype string */
614       switch (token) {
615       case T_IDENTIFIER:
616       case T_UNQUOTED_STRING:
617       case T_QUOTED_STRING:
618          res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
619          Dmsg3(900, "set drivetype %p size=%d %s\n",
620             res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
621          break;
622       default:
623          scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
624       }
625    }
626    scan_to_eol(lc);
627 }
628
629 /*
630  * Store Filename info. Note, for minor efficiency reasons, we
631  * always increase the name buffer by 10 items because we expect
632  * to add more entries.
633  */
634 static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
635 {
636    int token;
637    INCEXE *incexe;
638
639    token = lex_get_token(lc, T_SKIP_EOL);
640    if (pass == 1) {
641       /* Pickup Filename string
642        */
643       switch (token) {
644       case T_IDENTIFIER:
645       case T_UNQUOTED_STRING:
646          if (strchr(lc->str, '\\')) {
647             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
648             /* NOT REACHED */
649          }
650       case T_QUOTED_STRING:
651          if (res_all.res_fs.have_MD5) {
652             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
653          }
654          incexe = &res_incexe;
655          if (incexe->name_list.size() == 0) {
656             incexe->name_list.init(10, true);
657          }
658          incexe->name_list.append(bstrdup(lc->str));
659          Dmsg1(900, "Add to name_list %s\n", lc->str);
660          break;
661       default:
662          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
663       }
664    }
665    scan_to_eol(lc);
666 }
667
668 /*
669  * Store Filename info. Note, for minor efficiency reasons, we
670  * always increase the name buffer by 10 items because we expect
671  * to add more entries.
672  */
673 static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
674 {
675    int token;
676    INCEXE *incexe;
677
678    if (exclude) {
679       scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
680       /* NOT REACHED */
681    }
682    token = lex_get_token(lc, T_SKIP_EOL);
683    if (pass == 1) {
684       /* Pickup Filename string
685        */
686       switch (token) {
687       case T_IDENTIFIER:
688       case T_UNQUOTED_STRING:
689          if (strchr(lc->str, '\\')) {
690             scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
691             /* NOT REACHED */
692          }
693       case T_QUOTED_STRING:
694          if (res_all.res_fs.have_MD5) {
695             MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
696          }
697          incexe = &res_incexe;
698          if (incexe->plugin_list.size() == 0) {
699             incexe->plugin_list.init(10, true);
700          }
701          incexe->plugin_list.append(bstrdup(lc->str));
702          Dmsg1(900, "Add to plugin_list %s\n", lc->str);
703          break;
704       default:
705          scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
706          /* NOT REACHED */
707       }
708    }
709    scan_to_eol(lc);
710 }
711
712
713
714 /*
715  * Come here when Options seen in Include/Exclude
716  */
717 static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
718 {
719    int token, i;
720
721    if (exclude) {
722       scan_err0(lc, _("Options section not permitted in Exclude\n"));
723       /* NOT REACHED */
724    }
725    token = lex_get_token(lc, T_SKIP_EOL);
726    if (token != T_BOB) {
727       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
728    }
729
730    if (pass == 1) {
731       setup_current_opts();
732    }
733
734    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
735       if (token == T_EOL) {
736          continue;
737       }
738       if (token == T_EOB) {
739          break;
740       }
741       if (token != T_IDENTIFIER) {
742          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
743       }
744       for (i=0; options_items[i].name; i++) {
745          if (strcasecmp(options_items[i].name, lc->str) == 0) {
746             token = lex_get_token(lc, T_SKIP_EOL);
747             if (token != T_EQUALS) {
748                scan_err1(lc, _("expected an equals, got: %s"), lc->str);
749             }
750             /* Call item handler */
751             options_items[i].handler(lc, &options_items[i], i, pass);
752             i = -1;
753             break;
754          }
755       }
756       if (i >=0) {
757          scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
758       }
759    }
760 }
761
762
763 /*
764  * New style options come here
765  */
766 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
767 {
768    int i;
769    int keyword;
770    char inc_opts[100];
771
772    inc_opts[0] = 0;
773    keyword = INC_KW_NONE;
774    /* Look up the keyword */
775    for (i=0; FS_option_kw[i].name; i++) {
776       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
777          keyword = FS_option_kw[i].token;
778          break;
779       }
780    }
781    if (keyword == INC_KW_NONE) {
782       scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
783    }
784    /* Now scan for the value */
785    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
786    if (pass == 1) {
787       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
788       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
789    }
790    scan_to_eol(lc);
791 }
792
793
794
795 /* If current_opts not defined, create first entry */
796 static void setup_current_opts(void)
797 {
798    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
799    memset(fo, 0, sizeof(FOPTS));
800    fo->regex.init(1, true);
801    fo->regexdir.init(1, true);
802    fo->regexfile.init(1, true);
803    fo->wild.init(1, true);
804    fo->wilddir.init(1, true);
805    fo->wildfile.init(1, true);
806    fo->wildbase.init(1, true);
807    fo->base.init(1, true);
808    fo->fstype.init(1, true);
809    fo->drivetype.init(1, true);
810    res_incexe.current_opts = fo;
811    if (res_incexe.num_opts == 0) {
812       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
813    } else {
814       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
815                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
816    }
817    res_incexe.opts_list[res_incexe.num_opts++] = fo;
818 }