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