]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/inc_conf.c
- Integrated 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 and John Walker
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
223    option[0] = 0;                     /* default option = none */
224    option[2] = 0;                     /* terminate options */
225    token = lex_get_token(lc, T_NAME);             /* expect at least one option */       
226    if (keyword == INC_KW_VERIFY) { /* special case */
227       /* ***FIXME**** ensure these are in permitted set */
228       bstrncat(opts, "V", optlen);         /* indicate Verify */
229       bstrncat(opts, lc->str, optlen);
230       bstrncat(opts, ":", optlen);         /* terminate it */
231       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
232
233    /*
234     * Standard keyword options for Include/Exclude 
235     */
236    } else {
237       for (i=0; FS_options[i].name; i++) {
238          if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
239             /* NOTE! maximum 2 letters here or increase option[3] */
240             option[0] = FS_options[i].option[0];
241             option[1] = FS_options[i].option[1];
242             i = 0;
243             break;
244          }
245       }
246       if (i != 0) {
247          scan_err1(lc, "Expected a FileSet option keyword, got:%s:", lc->str);
248       } else { /* add option */
249          bstrncat(opts, option, optlen);
250          Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
251       }
252    }
253
254    /* If option terminated by comma, eat it */
255    if (lc->ch == ',') {
256       token = lex_get_token(lc, T_ALL);      /* yes, eat comma */
257    }
258 }
259
260 /* 
261  * 
262  * Store FileSet Include/Exclude info   
263  *  NEW style includes are handled in store_newinc()
264  */
265 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
266 {
267    int token, i;
268    int options = lc->options;
269    int keyword;
270    char inc_opts[100];
271    int inc_opts_len;
272
273    /*
274     * Decide if we are doing a new Include or an old include. The
275     *  new Include is followed immediately by open brace, whereas the
276     *  old include has options following the Include.
277     */
278    token = lex_get_token(lc, T_SKIP_EOL);            
279    if (token == T_BOB) {
280       store_newinc(lc, item, index, pass);
281       return;
282    }
283
284    /* What follows is scanning for the OLD style Include/Exclude */
285
286    if (token != T_EQUALS) {
287       scan_err1(lc, _("Expecting an equals sign, got: %s\n"), lc->str);
288    }
289    lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
290    memset(&res_incexe, 0, sizeof(INCEXE));
291
292    /* Get include options */
293    inc_opts[0] = 0;
294    while ((token=lex_get_token(lc, T_SKIP_EOL)) != T_BOB) {
295          
296       keyword = INC_KW_NONE;
297       for (i=0; FS_option_kw[i].name; i++) {
298          if (strcasecmp(lc->str, FS_option_kw[i].name) == 0) {
299             keyword = FS_option_kw[i].token;
300             break;
301          }
302       }
303       if (keyword == INC_KW_NONE) {
304          scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
305       }
306       /* Option keyword should be following by = <option> */
307       if ((token=lex_get_token(lc, T_SKIP_EOL)) != T_EQUALS) {
308          scan_err1(lc, _("expected an = following keyword, got: %s"), lc->str);
309       } else {
310          /* Scan right hand side of option */
311          scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
312       }
313       if (token == T_BOB) {
314          break;
315       }
316    }
317
318    if (!inc_opts[0]) {
319       strcat(inc_opts, "0");          /* set no options */
320    }
321    inc_opts_len = strlen(inc_opts);
322
323    if (pass == 1) {
324       INCEXE *incexe;
325       if (!res_all.res_fs.have_MD5) {
326          MD5Init(&res_all.res_fs.md5c);
327          res_all.res_fs.have_MD5 = TRUE;
328       }
329       setup_current_opts();
330       bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
331       Dmsg2(900, "old pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
332
333       /* Create incexe structure */
334       Dmsg0(900, "Create INCEXE structure\n");
335       incexe = (INCEXE *)malloc(sizeof(INCEXE));
336       memcpy(incexe, &res_incexe, sizeof(INCEXE));
337       memset(&res_incexe, 0, sizeof(INCEXE));
338       if (item->code == 0) { /* include */
339          if (res_all.res_fs.num_includes == 0) {
340             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
341           } else {
342             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
343                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
344           }
345           res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
346           Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
347       } else {    /* exclude */
348          if (res_all.res_fs.num_excludes == 0) {
349             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
350           } else {
351             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
352                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
353           }
354           res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
355           Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
356       }
357
358       /* Pickup include/exclude names.  They are stored in INCEXE
359        *  structures which contains the options and the name.
360        */
361       while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOB) {
362          switch (token) {
363          case T_COMMA:
364             continue;
365
366          case T_IDENTIFIER:
367          case T_UNQUOTED_STRING:
368          case T_QUOTED_STRING:
369             if (res_all.res_fs.have_MD5) {
370                MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
371             }
372             if (incexe->name_list.size() == 0) {
373                incexe->name_list.init(10, true);
374             }
375             incexe->name_list.append(bstrdup(lc->str));
376             Dmsg1(900, "Add to name_list %s\n", lc->str);
377             break;
378          default:
379             scan_err1(lc, "Expected a filename, got: %s", lc->str);
380          }                                 
381       }
382       /* Note, MD5Final is done in backup.c */
383    } else { /* pass 2 */
384       while (lex_get_token(lc, T_ALL) != T_EOB) 
385          {}
386    }
387    scan_to_eol(lc);
388    lc->options = options;
389    set_bit(index, res_all.hdr.item_present);
390 }
391
392
393 /*
394  * Store NEW style FileSet FInclude/FExclude info   
395  *
396  *  Note, when this routine is called, we are inside a FileSet
397  *  resource.  We treat the Include/Execlude like a sort of
398  *  mini-resource within the FileSet resource.
399  */
400 static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
401 {
402    int token, i;
403    INCEXE *incexe;
404    bool options;  
405
406    if (!res_all.res_fs.have_MD5) {
407       MD5Init(&res_all.res_fs.md5c);
408       res_all.res_fs.have_MD5 = true;
409    }
410    memset(&res_incexe, 0, sizeof(INCEXE));
411    res_all.res_fs.new_include = true;
412    while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
413       if (token == T_EOB) {
414          break;
415       }
416       if (token != T_IDENTIFIER) {
417          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
418       }
419       for (i=0; newinc_items[i].name; i++) {
420          options = strcasecmp(lc->str, "options") == 0;
421          if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
422             if (!options) {
423                token = lex_get_token(lc, T_SKIP_EOL);
424                if (token != T_EQUALS) {
425                   scan_err1(lc, "expected an equals, got: %s", lc->str);
426                }
427             }
428             /* Call item handler */
429             newinc_items[i].handler(lc, &newinc_items[i], i, pass);
430             i = -1;
431             break;
432          }
433       }
434       if (i >=0) {
435          scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
436       }
437    }
438    if (pass == 1) {
439       incexe = (INCEXE *)malloc(sizeof(INCEXE));
440       memcpy(incexe, &res_incexe, sizeof(INCEXE));
441       memset(&res_incexe, 0, sizeof(INCEXE));
442       if (item->code == 0) { /* include */
443          if (res_all.res_fs.num_includes == 0) {
444             res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
445          } else {
446             res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
447                            sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
448          }
449          res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
450          Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
451       } else {    /* exclude */
452          if (res_all.res_fs.num_excludes == 0) {
453             res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
454          } else {
455             res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
456                            sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
457          }
458          res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
459          Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
460       }
461    }
462    scan_to_eol(lc);
463    set_bit(index, res_all.hdr.item_present);
464 }
465
466
467 /* Store regex info */
468 static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
469 {
470    int token, rc;
471    regex_t preg;
472    char prbuf[500];
473
474    token = lex_get_token(lc, T_SKIP_EOL);            
475    if (pass == 1) {
476       /* Pickup regex string
477        */
478       switch (token) {
479       case T_IDENTIFIER:
480       case T_UNQUOTED_STRING:
481       case T_QUOTED_STRING:
482          rc = regcomp(&preg, lc->str, REG_EXTENDED);
483          if (rc != 0) {
484             regerror(rc, &preg, prbuf, sizeof(prbuf));
485             regfree(&preg);
486             scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
487             break;
488          }
489          regfree(&preg);
490          res_incexe.current_opts->regex.append(bstrdup(lc->str));
491          Dmsg3(900, "set regex %p size=%d %s\n", 
492             res_incexe.current_opts, res_incexe.current_opts->regex.size(),lc->str);
493          break;
494       default:
495          scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
496       }                                 
497    }
498    scan_to_eol(lc);
499 }
500
501 /* Store Base info */
502 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
503 {
504    int token;
505
506    token = lex_get_token(lc, T_NAME);           
507    if (pass == 1) {
508       /*
509        * Pickup Base Job Name
510        */
511       res_incexe.current_opts->base.append(bstrdup(lc->str));
512    }
513    scan_to_eol(lc);
514 }
515
516 /* Store reader info */
517 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
518 {
519    int token;
520
521    token = lex_get_token(lc, T_NAME);           
522    if (pass == 1) {
523       /*
524        * Pickup reader command
525        */
526       res_incexe.current_opts->reader = bstrdup(lc->str); 
527    }
528    scan_to_eol(lc);
529 }
530
531 /* Store writer innfo */
532 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
533 {
534    int token;
535
536    token = lex_get_token(lc, T_NAME);           
537    if (pass == 1) {
538       /*
539        * Pickup writer command
540        */
541       res_incexe.current_opts->writer = bstrdup(lc->str);
542    }
543    scan_to_eol(lc);
544 }
545
546
547
548 /* Store Wild-card info */
549 static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
550 {
551    int token;
552
553    token = lex_get_token(lc, T_SKIP_EOL);            
554    if (pass == 1) {
555       /*
556        * Pickup Wild-card string
557        */
558       switch (token) {
559       case T_IDENTIFIER:
560       case T_UNQUOTED_STRING:
561       case T_QUOTED_STRING:
562          res_incexe.current_opts->wild.append(bstrdup(lc->str));
563          Dmsg3(900, "set wild %p size=%d %s\n", 
564             res_incexe.current_opts, res_incexe.current_opts->wild.size(),lc->str);
565          break;
566       default:
567          scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
568       }                                 
569    }
570    scan_to_eol(lc);
571 }
572
573 /* Store fstype info */
574 static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
575 {
576    int token;
577
578    token = lex_get_token(lc, T_SKIP_EOL);            
579    if (pass == 1) {
580       /* Pickup fstype string */
581       switch (token) {
582       case T_IDENTIFIER:
583       case T_UNQUOTED_STRING:
584       case T_QUOTED_STRING:
585          res_incexe.current_opts->fstype.append(bstrdup(lc->str));
586          Dmsg3(900, "set fstype %p size=%d %s\n", 
587             res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
588          break;
589       default:
590          scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
591       }                                 
592    }
593    scan_to_eol(lc);
594 }
595
596 /*
597  * Store Filename info. Note, for minor efficiency reasons, we
598  * always increase the name buffer by 10 items because we expect
599  * to add more entries.
600  */
601 static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
602 {
603    int token;
604    INCEXE *incexe;
605
606    token = lex_get_token(lc, T_SKIP_EOL);            
607    if (pass == 1) {
608       /* Pickup Filename string
609        */
610       switch (token) {
611          case T_IDENTIFIER:
612          case T_UNQUOTED_STRING:
613          case T_QUOTED_STRING:
614             if (res_all.res_fs.have_MD5) {
615                MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
616             }
617             incexe = &res_incexe;
618             if (incexe->name_list.size() == 0) {
619                incexe->name_list.init(10, true);
620             }
621             incexe->name_list.append(bstrdup(lc->str));
622             Dmsg1(900, "Add to name_list %s\n", lc->str);
623             break;
624          default:
625             scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
626       }                                 
627    }
628    scan_to_eol(lc);
629 }
630
631
632 /*
633  * Come here when Options seen in Include/Exclude
634  */
635 static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
636 {
637    int token, i;
638
639    token = lex_get_token(lc, T_SKIP_EOL);            
640    if (token != T_BOB) {
641       scan_err1(lc, "Expecting open brace. Got %s", lc->str);
642    }
643
644    if (pass == 1) {
645       setup_current_opts();
646    }
647          
648    while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
649       if (token == T_EOL) {
650          continue;
651       }
652       if (token == T_EOB) {
653          break;
654       }
655       if (token != T_IDENTIFIER) {
656          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
657       }
658       for (i=0; options_items[i].name; i++) {
659          if (strcasecmp(options_items[i].name, lc->str) == 0) {
660             token = lex_get_token(lc, T_SKIP_EOL);
661             if (token != T_EQUALS) {
662                scan_err1(lc, "expected an equals, got: %s", lc->str);
663             }
664             /* Call item handler */
665             options_items[i].handler(lc, &options_items[i], i, pass);
666             i = -1;
667             break;
668          }
669       }
670       if (i >=0) {
671          scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
672       }
673    }
674 }
675
676
677 /*
678  * New style options come here
679  */
680 static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
681 {
682    int i;
683    int keyword;
684    char inc_opts[100];
685
686    inc_opts[0] = 0;
687    keyword = INC_KW_NONE;
688    /* Look up the keyword */
689    for (i=0; FS_option_kw[i].name; i++) {
690       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
691          keyword = FS_option_kw[i].token;
692          break;
693       }
694    }
695    if (keyword == INC_KW_NONE) {
696       scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
697    }
698    /* Now scan for the value */
699    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
700    if (pass == 1) {
701       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
702       Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
703    }
704    scan_to_eol(lc);
705 }
706
707
708
709 /* If current_opts not defined, create first entry */
710 static void setup_current_opts(void)
711 {
712    FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
713    memset(fo, 0, sizeof(FOPTS));
714    fo->regex.init(1, true);
715    fo->wild.init(1, true);
716    fo->base.init(1, true);
717    fo->fstype.init(1, true);
718    res_incexe.current_opts = fo;
719    if (res_incexe.num_opts == 0) {
720       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
721    } else {
722       res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
723                      sizeof(FOPTS *) * (res_incexe.num_opts + 1));
724    }
725    res_incexe.opts_list[res_incexe.num_opts++] = fo;
726 }