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