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