]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/inc_conf.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / dird / inc_conf.c
index 78836276184bf4710c31f218f07793fa7abe08e2..0ca26731ab20e9edf9dca00bbdf875e2a3eeef12 100644 (file)
@@ -1,43 +1,46 @@
 /*
- *   Configuration file parser for Include, Exclude, Finclude
- *    and FExclude records.
+ *   Configuration file parser for new and old Include and
+ *      Exclude records
  *
  *     Kern Sibbald, March MMIII
  *
  *     Version $Id$
  */
 /*
-   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+   Copyright (C) 2003-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
  */
 
 #include "bacula.h"
 #include "dird.h"
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
 
 /* Forward referenced subroutines */
 
-void store_inc(LEX *lc, struct res_items *item, int index, int pass);
-void store_finc(LEX *lc, struct res_items *item, int index, int pass);
-
-static void store_match(LEX *lc, struct res_items *item, int index, int pass);
-static void store_opts(LEX *lc, struct res_items *item, int index, int pass);
-static void store_fname(LEX *lc, struct res_items *item, int index, int pass);
-static void store_base(LEX *lc, struct res_items *item, int index, int pass);
+void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
+
+static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass);
+static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
 static void setup_current_opts(void);
 
 
@@ -49,43 +52,80 @@ static void setup_current_opts(void);
 extern URES res_all;
 extern int  res_all_size;
 
-/* We build the current Finclude Fexclude item here */
+/* We build the current new Include and Exclude items here */
 static INCEXE res_incexe;
 
-/* 
- * FInclude/FExclude items
- *   name            handler     value                        code flags default_value
+/*
+ * new Include/Exclude items
+ *   name             handler     value    code flags default_value
  */
-static struct res_items finc_items[] = {
+static RES_ITEM newinc_items[] = {
+   {"file",            store_fname,   NULL,     0, 0, 0},
+   {"options",         options_res,   NULL,     0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0}
+};
+
+/*
+ * Items that are valid in an Options resource
+ */
+static RES_ITEM options_items[] = {
    {"compression",     store_opts,    NULL,     0, 0, 0},
    {"signature",       store_opts,    NULL,     0, 0, 0},
    {"verify",          store_opts,    NULL,     0, 0, 0},
    {"onefs",           store_opts,    NULL,     0, 0, 0},
    {"recurse",         store_opts,    NULL,     0, 0, 0},
    {"sparse",          store_opts,    NULL,     0, 0, 0},
+   {"hardlinks",       store_opts,    NULL,     0, 0, 0},
    {"readfifo",        store_opts,    NULL,     0, 0, 0},
    {"replace",         store_opts,    NULL,     0, 0, 0},
-   {"match",           store_match,   NULL,     0, 0, 0},
-   {"file",            store_fname,   NULL,     0, 0, 0},
+   {"portable",        store_opts,    NULL,     0, 0, 0},
+   {"mtimeonly",       store_opts,    NULL,     0, 0, 0},
+   {"keepatime",       store_opts,    NULL,     0, 0, 0},
+   {"regex",           store_regex,   NULL,     0, 0, 0},
+   {"regexdir",        store_regex,   NULL,     1, 0, 0},
+   {"regexfile",       store_regex,   NULL,     2, 0, 0},
    {"base",            store_base,    NULL,     0, 0, 0},
-   {NULL, NULL, NULL, 0, 0, 0} 
+   {"wild",            store_wild,    NULL,     0, 0, 0},
+   {"wilddir",         store_wild,    NULL,     1, 0, 0},
+   {"wildfile",        store_wild,    NULL,     2, 0, 0},
+   {"exclude",         store_opts,    NULL,     0, 0, 0},
+   {"aclsupport",      store_opts,    NULL,     0, 0, 0},
+   {"reader",          store_reader,  NULL,     0, 0, 0},
+   {"writer",          store_writer,  NULL,     0, 0, 0},
+   {"ignorecase",      store_opts,    NULL,     0, 0, 0},
+   {"fstype",          store_fstype,  NULL,     0, 0, 0},
+   {"hfsplussupport",  store_opts,    NULL,     0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0}
 };
 
+
 /* Define FileSet KeyWord values */
+enum {
+   INC_KW_NONE,
+   INC_KW_COMPRESSION,
+   INC_KW_SIGNATURE,
+   INC_KW_ENCRYPTION,
+   INC_KW_VERIFY,
+   INC_KW_ONEFS,
+   INC_KW_RECURSE,
+   INC_KW_SPARSE,
+   INC_KW_HARDLINK,
+   INC_KW_REPLACE,               /* restore options */
+   INC_KW_READFIFO,              /* Causes fifo data to be read */
+   INC_KW_PORTABLE,
+   INC_KW_MTIMEONLY,
+   INC_KW_KEEPATIME,
+   INC_KW_EXCLUDE,
+   INC_KW_ACL,
+   INC_KW_IGNORECASE,
+   INC_KW_HFSPLUS
+};
 
-#define INC_KW_NONE        0
-#define INC_KW_COMPRESSION  1
-#define INC_KW_SIGNATURE    2
-#define INC_KW_ENCRYPTION   3
-#define INC_KW_VERIFY      4
-#define INC_KW_ONEFS       5
-#define INC_KW_RECURSE     6
-#define INC_KW_SPARSE      7
-#define INC_KW_REPLACE     8         /* restore options */
-#define INC_KW_READFIFO     9        /* Causes fifo data to be read */
-
-/* Include keywords -- these are keywords that can appear
- *    in the options lists of an include ( Include = compression= ...)
+/*
+ * This is the list of options that can be stored by store_opts
+ *   Note, now that the old style Include/Exclude code is gone,
+ *   the INC_KW code could be put into the "code" field of the
+ *   options given above.
  */
 static struct s_kw FS_option_kw[] = {
    {"compression", INC_KW_COMPRESSION},
@@ -95,21 +135,29 @@ static struct s_kw FS_option_kw[] = {
    {"onefs",       INC_KW_ONEFS},
    {"recurse",     INC_KW_RECURSE},
    {"sparse",      INC_KW_SPARSE},
+   {"hardlinks",   INC_KW_HARDLINK},
    {"replace",     INC_KW_REPLACE},
    {"readfifo",    INC_KW_READFIFO},
-   {NULL,         0}
+   {"portable",    INC_KW_PORTABLE},
+   {"mtimeonly",   INC_KW_MTIMEONLY},
+   {"keepatime",   INC_KW_KEEPATIME},
+   {"exclude",     INC_KW_EXCLUDE},
+   {"aclsupport",  INC_KW_ACL},
+   {"ignorecase",  INC_KW_IGNORECASE},
+   {"hfsplussupport", INC_KW_HFSPLUS},
+   {NULL,          0}
 };
 
 /* Options for FileSet keywords */
 
 struct s_fs_opt {
-   char *name;
+   const char *name;
    int keyword;
-   char *option;
+   const char *option;
 };
 
 /*
- * Options permitted for each keyword and resulting value.     
+ * Options permitted for each keyword and resulting value.
  * The output goes into opts, which are then transmitted to
  * the FD for application as options to the following list of
  * included files.
@@ -135,54 +183,76 @@ static struct s_fs_opt FS_options[] = {
    {"no",       INC_KW_RECURSE,       "h"},
    {"yes",      INC_KW_SPARSE,        "s"},
    {"no",       INC_KW_SPARSE,        "0"},
+   {"yes",      INC_KW_HARDLINK,      "0"},
+   {"no",       INC_KW_HARDLINK,      "H"},
    {"always",   INC_KW_REPLACE,       "a"},
    {"ifnewer",  INC_KW_REPLACE,       "w"},
    {"never",    INC_KW_REPLACE,       "n"},
    {"yes",      INC_KW_READFIFO,      "r"},
    {"no",       INC_KW_READFIFO,      "0"},
-   {NULL,      0,                   0}
+   {"yes",      INC_KW_PORTABLE,      "p"},
+   {"no",       INC_KW_PORTABLE,      "0"},
+   {"yes",      INC_KW_MTIMEONLY,     "m"},
+   {"no",       INC_KW_MTIMEONLY,     "0"},
+   {"yes",      INC_KW_KEEPATIME,     "k"},
+   {"no",       INC_KW_KEEPATIME,     "0"},
+   {"yes",      INC_KW_EXCLUDE,       "e"},
+   {"no",       INC_KW_EXCLUDE,       "0"},
+   {"yes",      INC_KW_ACL,           "A"},
+   {"no",       INC_KW_ACL,           "0"},
+   {"yes",      INC_KW_IGNORECASE,    "i"},
+   {"no",       INC_KW_IGNORECASE,    "0"},
+   {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
+   {"no",       INC_KW_HFSPLUS,       "0"},
+   {NULL,       0,                      0}
 };
 
 
 
-/* 
- * Scan for Include options (keyword=option) is converted into one or
- *  two characters. Verifyopts=xxxx is Vxxxx:
+/*
+ * Scan for right hand side of Include options (keyword=option) is
+ *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
+ *    Whatever is found is concatenated to the opts string.
+ * This code is also used inside an Options resource.
  */
 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
 {
    int token, i;
    char option[3];
+   int lcopts = lc->options;
 
-   option[0] = 0;                    /* default option = none */
-   option[2] = 0;                    /* terminate options */
-   token = lex_get_token(lc, T_NAME);            /* expect at least one option */       
+   option[0] = 0;                     /* default option = none */
+   option[2] = 0;                     /* terminate options */
+   lc->options |= LOPT_STRING;        /* force string */
+   token = lex_get_token(lc, T_STRING);          /* expect at least one option */
    if (keyword == INC_KW_VERIFY) { /* special case */
       /* ***FIXME**** ensure these are in permitted set */
       bstrncat(opts, "V", optlen);         /* indicate Verify */
       bstrncat(opts, lc->str, optlen);
       bstrncat(opts, ":", optlen);         /* terminate it */
+      Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
 
    /*
-    * Standard keyword options for Include/Exclude 
+    * Standard keyword options for Include/Exclude
     */
    } else {
       for (i=0; FS_options[i].name; i++) {
-        if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
-           /* NOTE! maximum 2 letters here or increase option[3] */
-           option[0] = FS_options[i].option[0];
-           option[1] = FS_options[i].option[1];
-           i = 0;
-           break;
-        }
+         if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
+            /* NOTE! maximum 2 letters here or increase option[3] */
+            option[0] = FS_options[i].option[0];
+            option[1] = FS_options[i].option[1];
+            i = 0;
+            break;
+         }
       }
       if (i != 0) {
-         scan_err1(lc, "Expected a FileSet option keyword, got:%s:", lc->str);
+         scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str);
       } else { /* add option */
-        bstrncat(opts, option, optlen);
-         Dmsg3(200, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
+         bstrncat(opts, option, optlen);
+         Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
       }
    }
+   lc->options = lcopts;
 
    /* If option terminated by comma, eat it */
    if (lc->ch == ',') {
@@ -190,164 +260,72 @@ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
    }
 }
 
-/* Store FileSet Include/Exclude info */
-void store_inc(LEX *lc, struct res_items *item, int index, int pass)
+/*
+ *
+ * Store FileSet Include/Exclude info
+ *  NEW style includes are handled in store_newinc()
+ */
+void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
 {
-   int token, i;
-   int options = lc->options;
-   int keyword;
-   char inc_opts[100];
-   int inc_opts_len;
-
-   lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
-   memset(&res_incexe, 0, sizeof(INCEXE));
-
-   /* Get include options */
-   inc_opts[0] = 0;
-   while ((token=lex_get_token(lc, T_ALL)) != T_BOB) {
-      keyword = INC_KW_NONE;
-      for (i=0; FS_option_kw[i].name; i++) {
-        if (strcasecmp(lc->str, FS_option_kw[i].name) == 0) {
-           keyword = FS_option_kw[i].token;
-           break;
-        }
-      }
-      if (keyword == INC_KW_NONE) {
-         scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
-      }
-      /* Option keyword should be following by = <option> */
-      if ((token=lex_get_token(lc, T_ALL)) != T_EQUALS) {
-         scan_err1(lc, _("expected an = following keyword, got: %s"), lc->str);
-      } else {
-        scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
-      }
-      if (token == T_BOB) {
-        break;
-      }
-   }
-   if (!inc_opts[0]) {
-      strcat(inc_opts, "0");          /* set no options */
-   }
-   inc_opts_len = strlen(inc_opts);
-
-   if (pass == 1) {
-      INCEXE *incexe;
-      if (!res_all.res_fs.have_MD5) {
-        MD5Init(&res_all.res_fs.md5c);
-        res_all.res_fs.have_MD5 = TRUE;
-      }
-      setup_current_opts();
-      bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
-      Dmsg1(200, "incexe opts=%s\n", res_incexe.current_opts->opts);
-
-      /* Create incexe structure */
-      Dmsg0(200, "Create INCEXE structure\n");
-      incexe = (INCEXE *)malloc(sizeof(INCEXE));
-      memcpy(incexe, &res_incexe, sizeof(INCEXE));
-      memset(&res_incexe, 0, sizeof(INCEXE));
-      if (item->code == 0) { /* include */
-        if (res_all.res_fs.num_includes == 0) {
-           res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
-         } else {
-           res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
-                          sizeof(INCEXE *) * res_all.res_fs.num_includes + 1);
-         }
-         res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
-          Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
-      } else {   /* exclude */
-        if (res_all.res_fs.num_excludes == 0) {
-           res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
-         } else {
-           res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
-                          sizeof(INCEXE *) * res_all.res_fs.num_excludes + 1);
-         }
-         res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
-          Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
-      }
+   int token;
 
-      /* Pickup include/exclude names. They are stored in INCEXE
-       *  structures which contains the options and the name.
-       */
-      while ((token = lex_get_token(lc, T_ALL)) != T_EOB) {
-        switch (token) {
-           case T_COMMA:
-           case T_EOL:
-              continue;
-
-           case T_IDENTIFIER:
-           case T_UNQUOTED_STRING:
-           case T_QUOTED_STRING:
-              if (res_all.res_fs.have_MD5) {
-                 MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
-              }
-              if (incexe->num_names == incexe->max_names) {
-                 incexe->max_names += 10;
-                 if (incexe->name_list == NULL) {
-                    incexe->name_list = (char **)malloc(sizeof(char *) * incexe->max_names);
-                 } else {
-                    incexe->name_list = (char **)realloc(incexe->name_list,
-                          sizeof(char *) * incexe->max_names);
-                 }
-              }
-              incexe->name_list[incexe->num_names++] = bstrdup(lc->str);
-               Dmsg1(200, "Add to name_list %s\n", incexe->name_list[incexe->num_names -1]);
-              break;
-           default:
-               scan_err1(lc, "Expected a filename, got: %s", lc->str);
-        }                                 
-      }
-      /* Note, MD5Final is done in backup.c */
-   } else { /* pass 1 */
-      while (lex_get_token(lc, T_ALL) != T_EOB) 
-        {}
+   /*
+    * Decide if we are doing a new Include or an old include. The
+    *  new Include is followed immediately by open brace, whereas the
+    *  old include has options following the Include.
+    */
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (token == T_BOB) {
+      store_newinc(lc, item, index, pass);
+      return;
    }
-   scan_to_eol(lc);
-   lc->options = options;
-   set_bit(index, res_all.hdr.item_present);
+   scan_err0(lc, _("Old style Include/Exclude not supported\n"));
 }
 
 
 /*
- * Store FileSet FInclude/FExclude info   
+ * Store NEW style FileSet FInclude/FExclude info
+ *
  *  Note, when this routine is called, we are inside a FileSet
- *  resource.  We treat the Finclude/Fexeclude like a sort of
+ *  resource.  We treat the Include/Execlude like a sort of
  *  mini-resource within the FileSet resource.
  */
-void store_finc(LEX *lc, struct res_items *item, int index, int pass)
+static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    int token, i;
    INCEXE *incexe;
+   bool options;
 
-   res_all.res_fs.finclude = TRUE;
-   token = lex_get_token(lc, T_ALL);           
-   if (token != T_BOB) {
-      scan_err1(lc, _("Expecting a beginning brace, got: %s\n"), lc->str);
+   if (!res_all.res_fs.have_MD5) {
+      MD5Init(&res_all.res_fs.md5c);
+      res_all.res_fs.have_MD5 = true;
    }
    memset(&res_incexe, 0, sizeof(INCEXE));
-   while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
-      if (token == T_EOL) {
-        continue;
-      }
+   res_all.res_fs.new_include = true;
+   while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
       if (token == T_EOB) {
-        break;
+         break;
       }
       if (token != T_IDENTIFIER) {
          scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
       }
-      for (i=0; finc_items[i].name; i++) {
-        if (strcasecmp(finc_items[i].name, lc->str) == 0) {
-           token = lex_get_token(lc, T_ALL);
-           if (token != T_EQUALS) {
-               scan_err1(lc, "expected an equals, got: %s", lc->str);
-           }
-           /* Call item handler */
-           finc_items[i].handler(lc, &finc_items[i], i, pass);
-           i = -1;
-           break;
-        }
+      for (i=0; newinc_items[i].name; i++) {
+         options = strcasecmp(lc->str, "options") == 0;
+         if (strcasecmp(newinc_items[i].name, lc->str) == 0) {
+            if (!options) {
+               token = lex_get_token(lc, T_SKIP_EOL);
+               if (token != T_EQUALS) {
+                  scan_err1(lc, _("expected an equals, got: %s"), lc->str);
+               }
+            }
+            /* Call item handler */
+            newinc_items[i].handler(lc, &newinc_items[i], i, pass);
+            i = -1;
+            break;
+         }
       }
       if (i >=0) {
-         scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
+         scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
       }
    }
    if (pass == 1) {
@@ -355,23 +333,23 @@ void store_finc(LEX *lc, struct res_items *item, int index, int pass)
       memcpy(incexe, &res_incexe, sizeof(INCEXE));
       memset(&res_incexe, 0, sizeof(INCEXE));
       if (item->code == 0) { /* include */
-        if (res_all.res_fs.num_includes == 0) {
-           res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
-        } else {
-           res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
-                          sizeof(INCEXE *) * res_all.res_fs.num_includes + 1);
-        }
-        res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
-         Dmsg1(200, "num_includes=%d\n", res_all.res_fs.num_includes);
-      } else {   /* exclude */
-        if (res_all.res_fs.num_excludes == 0) {
-           res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
-        } else {
-           res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
-                          sizeof(INCEXE *) * res_all.res_fs.num_excludes + 1);
-        }
-        res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
-         Dmsg1(200, "num_excludes=%d\n", res_all.res_fs.num_excludes);
+         if (res_all.res_fs.num_includes == 0) {
+            res_all.res_fs.include_items = (INCEXE **)malloc(sizeof(INCEXE *));
+         } else {
+            res_all.res_fs.include_items = (INCEXE **)realloc(res_all.res_fs.include_items,
+                           sizeof(INCEXE *) * (res_all.res_fs.num_includes + 1));
+         }
+         res_all.res_fs.include_items[res_all.res_fs.num_includes++] = incexe;
+         Dmsg1(900, "num_includes=%d\n", res_all.res_fs.num_includes);
+      } else {    /* exclude */
+         if (res_all.res_fs.num_excludes == 0) {
+            res_all.res_fs.exclude_items = (INCEXE **)malloc(sizeof(INCEXE *));
+         } else {
+            res_all.res_fs.exclude_items = (INCEXE **)realloc(res_all.res_fs.exclude_items,
+                           sizeof(INCEXE *) * (res_all.res_fs.num_excludes + 1));
+         }
+         res_all.res_fs.exclude_items[res_all.res_fs.num_excludes++] = incexe;
+         Dmsg1(900, "num_excludes=%d\n", res_all.res_fs.num_excludes);
       }
    }
    scan_to_eol(lc);
@@ -379,104 +357,248 @@ void store_finc(LEX *lc, struct res_items *item, int index, int pass)
 }
 
 
-/* Store Match info */
-static void store_match(LEX *lc, struct res_items *item, int index, int pass)
+/* Store regex info */
+static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
 {
-   int token;
+   int token, rc;
+   regex_t preg;
+   char prbuf[500];
+   const char *type;
+   int newsize;
 
+   token = lex_get_token(lc, T_SKIP_EOL);
    if (pass == 1) {
-      /* Pickup Match string
+      /* Pickup regex string
        */
-      token = lex_get_token(lc, T_ALL);           
       switch (token) {
-        case T_IDENTIFIER:
-        case T_UNQUOTED_STRING:
-        case T_QUOTED_STRING:
-           setup_current_opts();
-           if (res_incexe.current_opts->match) {
-               scan_err0(lc, _("More than one match specified.\n")); 
-           }
-           res_incexe.current_opts->match = bstrdup(lc->str);
-           break;
-        default:
-            scan_err1(lc, _("Expected a filename, got: %s\n"), lc->str);
-      }                                
-   } else { /* pass 2 */
-      lex_get_token(lc, T_ALL);         
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+      case T_QUOTED_STRING:
+         rc = regcomp(&preg, lc->str, REG_EXTENDED);
+         if (rc != 0) {
+            regerror(rc, &preg, prbuf, sizeof(prbuf));
+            regfree(&preg);
+            scan_err1(lc, _("Regex compile error. ERR=%s\n"), prbuf);
+            break;
+         }
+         regfree(&preg);
+         if (item->code == 1) {
+            type = "regexdir";
+            res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->regexdir.size();
+         } else if (item->code == 2) {
+            type = "regexfile";
+            res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->regexfile.size();
+         } else {
+            type = "regex";
+            res_incexe.current_opts->regex.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->regex.size();
+         }
+         Dmsg4(900, "set %s %p size=%d %s\n",
+            type, res_incexe.current_opts, newsize, lc->str);
+         break;
+      default:
+         scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str);
+      }
    }
    scan_to_eol(lc);
 }
 
 /* Store Base info */
-static void store_base(LEX *lc, struct res_items *item, int index, int pass)
+static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    int token;
-   FOPTS *copt;
 
+   token = lex_get_token(lc, T_NAME);
    if (pass == 1) {
-      setup_current_opts();
       /*
        * Pickup Base Job Name
        */
-      token = lex_get_token(lc, T_NAME);          
-      copt = res_incexe.current_opts;
-      if (copt->base_list == NULL) {
-        copt->base_list = (char **)malloc(sizeof(char *));                     
-      } else {
-        copt->base_list = (char **)realloc(copt->base_list,
-           sizeof(char *) * (copt->num_base+1));
+      res_incexe.current_opts->base.append(bstrdup(lc->str));
+   }
+   scan_to_eol(lc);
+}
+
+/* Store reader info */
+static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc, T_NAME);
+   if (pass == 1) {
+      /*
+       * Pickup reader command
+       */
+      res_incexe.current_opts->reader = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+}
+
+/* Store writer innfo */
+static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc, T_NAME);
+   if (pass == 1) {
+      /*
+       * Pickup writer command
+       */
+      res_incexe.current_opts->writer = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+}
+
+
+
+/* Store Wild-card info */
+static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+   const char *type;
+   int newsize;
+
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (pass == 1) {
+      /*
+       * Pickup Wild-card string
+       */
+      switch (token) {
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+      case T_QUOTED_STRING:
+         if (item->code == 1) {
+            type = "wilddir";
+            res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->wilddir.size();
+         } else if (item->code == 2) {
+            type = "wildfile";
+            res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->wildfile.size();
+         } else {
+            type = "wild";
+            res_incexe.current_opts->wild.append(bstrdup(lc->str));
+            newsize = res_incexe.current_opts->wild.size();
+         }
+         Dmsg4(9, "set %s %p size=%d %s\n",
+            type, res_incexe.current_opts, newsize, lc->str);
+         break;
+      default:
+         scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str);
+      }
+   }
+   scan_to_eol(lc);
+}
+
+/* Store fstype info */
+static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (pass == 1) {
+      /* Pickup fstype string */
+      switch (token) {
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+      case T_QUOTED_STRING:
+         res_incexe.current_opts->fstype.append(bstrdup(lc->str));
+         Dmsg3(900, "set fstype %p size=%d %s\n",
+            res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str);
+         break;
+      default:
+         scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str);
       }
-      copt->base_list[copt->num_base++] = bstrdup(lc->str);
-   } else { /* pass 2 */
-      lex_get_token(lc, T_ALL);         
    }
    scan_to_eol(lc);
 }
+
 /*
  * Store Filename info. Note, for minor efficiency reasons, we
  * always increase the name buffer by 10 items because we expect
  * to add more entries.
  */
-static void store_fname(LEX *lc, struct res_items *item, int index, int pass)
+static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    int token;
    INCEXE *incexe;
 
+   token = lex_get_token(lc, T_SKIP_EOL);
    if (pass == 1) {
       /* Pickup Filename string
        */
-      token = lex_get_token(lc, T_ALL);           
       switch (token) {
-        case T_IDENTIFIER:
-        case T_UNQUOTED_STRING:
-        case T_QUOTED_STRING:
-           if (res_all.res_fs.have_MD5) {
-              MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
-           }
-           incexe = &res_incexe;
-           if (incexe->num_names == incexe->max_names) {
-              incexe->max_names += 10;
-              if (incexe->name_list == NULL) {
-                 incexe->name_list = (char **)malloc(sizeof(char *) * incexe->max_names);
-              } else {
-                 incexe->name_list = (char **)realloc(incexe->name_list,
-                       sizeof(char *) * incexe->max_names);
-              }
-           }
-           incexe->name_list[incexe->num_names++] = bstrdup(lc->str);
-            Dmsg1(200, "Add to name_list %s\n", incexe->name_list[incexe->num_names -1]);
-           break;
-        default:
+         case T_IDENTIFIER:
+         case T_UNQUOTED_STRING:
+         case T_QUOTED_STRING:
+            if (res_all.res_fs.have_MD5) {
+               MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
+            }
+            incexe = &res_incexe;
+            if (incexe->name_list.size() == 0) {
+               incexe->name_list.init(10, true);
+            }
+            incexe->name_list.append(bstrdup(lc->str));
+            Dmsg1(900, "Add to name_list %s\n", lc->str);
+            break;
+         default:
             scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
-      }                                
-   } else { /* pass 2 */
-      lex_get_token(lc, T_ALL);         
+      }
    }
    scan_to_eol(lc);
 }
 
 
-static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
+/*
+ * Come here when Options seen in Include/Exclude
+ */
+static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token, i;
+
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (token != T_BOB) {
+      scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
+   }
+
+   if (pass == 1) {
+      setup_current_opts();
+   }
+
+   while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
+      if (token == T_EOL) {
+         continue;
+      }
+      if (token == T_EOB) {
+         break;
+      }
+      if (token != T_IDENTIFIER) {
+         scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
+      }
+      for (i=0; options_items[i].name; i++) {
+         if (strcasecmp(options_items[i].name, lc->str) == 0) {
+            token = lex_get_token(lc, T_SKIP_EOL);
+            if (token != T_EQUALS) {
+               scan_err1(lc, _("expected an equals, got: %s"), lc->str);
+            }
+            /* Call item handler */
+            options_items[i].handler(lc, &options_items[i], i, pass);
+            i = -1;
+            break;
+         }
+      }
+      if (i >=0) {
+         scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
+      }
+   }
+}
+
+
+/*
+ * New style options come here
+ */
+static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    int i;
    int keyword;
@@ -484,24 +606,22 @@ static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
 
    inc_opts[0] = 0;
    keyword = INC_KW_NONE;
+   /* Look up the keyword */
    for (i=0; FS_option_kw[i].name; i++) {
       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
-        keyword = FS_option_kw[i].token;
-        break;
+         keyword = FS_option_kw[i].token;
+         break;
       }
    }
    if (keyword == INC_KW_NONE) {
-      scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
+      scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str);
    }
-   Dmsg2(200, "keyword=%d %s\n", keyword, FS_option_kw[keyword].name);
+   /* Now scan for the value */
    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
-
    if (pass == 1) {
-      setup_current_opts();
-
       bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
+      Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
    }
-
    scan_to_eol(lc);
 }
 
@@ -510,11 +630,22 @@ static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
 /* If current_opts not defined, create first entry */
 static void setup_current_opts(void)
 {
-   if (res_incexe.current_opts == NULL) {
-      res_incexe.current_opts = (FOPTS *)malloc(sizeof(FOPTS));
-      memset(res_incexe.current_opts, 0, sizeof(FOPTS));
-      res_incexe.num_opts = 1;
+   FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS));
+   memset(fo, 0, sizeof(FOPTS));
+   fo->regex.init(1, true);
+   fo->regexdir.init(1, true);
+   fo->regexfile.init(1, true);
+   fo->wild.init(1, true);
+   fo->wilddir.init(1, true);
+   fo->wildfile.init(1, true);
+   fo->base.init(1, true);
+   fo->fstype.init(1, true);
+   res_incexe.current_opts = fo;
+   if (res_incexe.num_opts == 0) {
       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));
-      res_incexe.opts_list[0] = res_incexe.current_opts;
+   } else {
+      res_incexe.opts_list = (FOPTS **)realloc(res_incexe.opts_list,
+                     sizeof(FOPTS *) * (res_incexe.num_opts + 1));
    }
+   res_incexe.opts_list[res_incexe.num_opts++] = fo;
 }