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