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