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