]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/inc_conf.c
kes Change IncludeDir to Exclude Dir Containing.
[bacula/bacula] / bacula / src / dird / inc_conf.c
index 67ebde2ac8dcbe1c1ac8167898f0646dd700853f..7fa7399357139c174865f558a1990f496033433c 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
  *   Configuration file parser for new and old Include and
  *      Exclude records
  *
  *     Version $Id$
  */
-/*
-   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
-   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 
-   the file LICENSE for additional details.
-
- */
 
 #include "bacula.h"
 #include "dird.h"
-#ifdef HAVE_REGEX_H
+#ifndef HAVE_REGEX_H
+#include "lib/bregex.h"
+#else
 #include <regex.h>
 #endif
 
@@ -35,21 +50,31 @@ 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_drivetype(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 store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
 static void setup_current_opts(void);
 
+/* Include and Exclude items */
+static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
+static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
+static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
+static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude);
+
 
 /* We build the current resource here as we are
  * scanning the resource configuration definition,
  * then move it to allocated memory when the resource
  * scan is complete.
  */
+#if defined(_MSC_VER)
+extern "C" { // work around visual compiler mangling variables
+   extern URES res_all;
+}
+#else
 extern URES res_all;
+#endif
 extern int  res_all_size;
 
 /* We build the current new Include and Exclude items here */
@@ -59,43 +84,51 @@ static INCEXE res_incexe;
  * new Include/Exclude items
  *   name             handler     value    code flags default_value
  */
-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}
+static RES_ITEM2 newinc_items[] = {
+   {"file",            store_fname,       {0},      0, 0, 0},
+   {"plugin",          store_plugin_name, {0},      0, 0, 0},
+   {"excludedircontaining", store_excludedir,  {0}, 0, 0, 0},
+   {"options",         options_res,       {0},      0, 0, 0},
+   {NULL, NULL, {0}, 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},
-   {"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},
-   {"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}
+   {"compression",     store_opts,    {0},     0, 0, 0},
+   {"signature",       store_opts,    {0},     0, 0, 0},
+   {"accurate",        store_opts,    {0},     0, 0, 0},
+   {"verify",          store_opts,    {0},     0, 0, 0},
+   {"onefs",           store_opts,    {0},     0, 0, 0},
+   {"recurse",         store_opts,    {0},     0, 0, 0},
+   {"sparse",          store_opts,    {0},     0, 0, 0},
+   {"hardlinks",       store_opts,    {0},     0, 0, 0},
+   {"readfifo",        store_opts,    {0},     0, 0, 0},
+   {"replace",         store_opts,    {0},     0, 0, 0},
+   {"portable",        store_opts,    {0},     0, 0, 0},
+   {"mtimeonly",       store_opts,    {0},     0, 0, 0},
+   {"keepatime",       store_opts,    {0},     0, 0, 0},
+   {"regex",           store_regex,   {0},     0, 0, 0},
+   {"regexdir",        store_regex,   {0},     1, 0, 0},
+   {"regexfile",       store_regex,   {0},     2, 0, 0},
+   {"base",            store_base,    {0},     0, 0, 0},
+   {"wild",            store_wild,    {0},     0, 0, 0},
+   {"wilddir",         store_wild,    {0},     1, 0, 0},
+   {"wildfile",        store_wild,    {0},     2, 0, 0},
+   {"exclude",         store_opts,    {0},     0, 0, 0},
+   {"aclsupport",      store_opts,    {0},     0, 0, 0},
+   {"plugin",          store_plugin,  {0},     0, 0, 0},
+   {"ignorecase",      store_opts,    {0},     0, 0, 0},
+   {"fstype",          store_fstype,  {0},     0, 0, 0},
+   {"hfsplussupport",  store_opts,    {0},     0, 0, 0},
+   {"noatime",         store_opts,    {0},     0, 0, 0},
+   {"enhancedwild",    store_opts,    {0},     0, 0, 0},
+   {"drivetype",       store_drivetype, {0},   0, 0, 0},
+   {"checkfilechanges",store_opts,    {0},     0, 0, 1},
+   {"strippath",       store_opts,    {0},     0, 0, 0},
+   {"honornodumpflag", store_opts,    {0},     0, 0, 0},
+   {NULL, NULL, {0}, 0, 0, 0}
 };
 
 
@@ -106,6 +139,7 @@ enum {
    INC_KW_DIGEST,
    INC_KW_ENCRYPTION,
    INC_KW_VERIFY,
+   INC_KW_ACCURATE,
    INC_KW_ONEFS,
    INC_KW_RECURSE,
    INC_KW_SPARSE,
@@ -118,7 +152,12 @@ enum {
    INC_KW_EXCLUDE,
    INC_KW_ACL,
    INC_KW_IGNORECASE,
-   INC_KW_HFSPLUS
+   INC_KW_HFSPLUS,
+   INC_KW_NOATIME,
+   INC_KW_ENHANCEDWILD,
+   INC_KW_CHKCHANGES,
+   INC_KW_STRIPPATH,
+   INC_KW_HONOR_NODUMP
 };
 
 /*
@@ -132,6 +171,7 @@ static struct s_kw FS_option_kw[] = {
    {"signature",   INC_KW_DIGEST},
    {"encryption",  INC_KW_ENCRYPTION},
    {"verify",      INC_KW_VERIFY},
+   {"accurate",    INC_KW_ACCURATE},
    {"onefs",       INC_KW_ONEFS},
    {"recurse",     INC_KW_RECURSE},
    {"sparse",      INC_KW_SPARSE},
@@ -145,6 +185,11 @@ static struct s_kw FS_option_kw[] = {
    {"aclsupport",  INC_KW_ACL},
    {"ignorecase",  INC_KW_IGNORECASE},
    {"hfsplussupport", INC_KW_HFSPLUS},
+   {"noatime",     INC_KW_NOATIME},
+   {"enhancedwild", INC_KW_ENHANCEDWILD},
+   {"checkfilechanges", INC_KW_CHKCHANGES},
+   {"strippath",    INC_KW_STRIPPATH},
+   {"honornodumpflag",    INC_KW_HONOR_NODUMP},
    {NULL,          0}
 };
 
@@ -206,6 +251,14 @@ static struct s_fs_opt FS_options[] = {
    {"no",       INC_KW_IGNORECASE,    "0"},
    {"yes",      INC_KW_HFSPLUS,       "R"},   /* "R" for resource fork */
    {"no",       INC_KW_HFSPLUS,       "0"},
+   {"yes",      INC_KW_NOATIME,       "K"},
+   {"no",       INC_KW_NOATIME,       "0"},
+   {"yes",      INC_KW_ENHANCEDWILD,  "K"},
+   {"no",       INC_KW_ENHANCEDWILD,  "0"},
+   {"yes",      INC_KW_CHKCHANGES,    "c"},
+   {"no",       INC_KW_CHKCHANGES,    "0"},
+   {"yes",      INC_KW_HONOR_NODUMP,  "N"},
+   {"no",       INC_KW_HONOR_NODUMP,  "0"},
    {NULL,       0,                      0}
 };
 
@@ -233,13 +286,26 @@ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
       bstrncat(opts, lc->str, optlen);
       bstrncat(opts, ":", optlen);         /* terminate it */
       Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
-
+   } else if (keyword == INC_KW_ACCURATE) { /* special case */
+      /* ***FIXME**** ensure these are in permitted set */
+      bstrncat(opts, "C", optlen);         /* indicate Accurate */
+      bstrncat(opts, lc->str, optlen);
+      bstrncat(opts, ":", optlen);         /* terminate it */
+      Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
+   } else if (keyword == INC_KW_STRIPPATH) { /* another special case */
+      if (!is_an_integer(lc->str)) {
+         scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str);
+      }
+      bstrncat(opts, "P", optlen);         /* indicate strip path */
+      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
     */
    } else {
       for (i=0; FS_options[i].name; i++) {
-         if (strcasecmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
+         if (FS_options[i].keyword == keyword && strcasecmp(lc->str, FS_options[i].name) == 0) {
             /* NOTE! maximum 2 letters here or increase option[3] */
             option[0] = FS_options[i].option[0];
             option[1] = FS_options[i].option[1];
@@ -265,7 +331,7 @@ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
 /*
  *
  * Store FileSet Include/Exclude info
- *  NEW style includes are handled in store_newinc()
+ *  new style includes are handled in store_newinc()
  */
 void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
 {
@@ -286,7 +352,7 @@ void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
 
 
 /*
- * Store NEW style FileSet FInclude/FExclude info
+ * Store new style FileSet Include/Exclude info
  *
  *  Note, when this routine is called, we are inside a FileSet
  *  resource.  We treat the Include/Execlude like a sort of
@@ -321,7 +387,7 @@ static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass)
                }
             }
             /* Call item handler */
-            newinc_items[i].handler(lc, &newinc_items[i], i, pass);
+            newinc_items[i].handler(lc, &newinc_items[i], i, pass, item->code);
             i = -1;
             break;
          }
@@ -423,36 +489,20 @@ static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
 }
 
 /* Store reader info */
-static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass)
+static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    int token;
 
    token = lex_get_token(lc, T_NAME);
    if (pass == 1) {
       /*
-       * Pickup reader command
+       * Pickup plugin command
        */
-      res_incexe.current_opts->reader = bstrdup(lc->str);
+      res_incexe.current_opts->plugin = 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)
@@ -475,9 +525,15 @@ static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
             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();
+            if (strpbrk(lc->str, "/\\") != NULL) {
+               type = "wildfile";
+               res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
+               newsize = res_incexe.current_opts->wildfile.size();
+            } else {
+               type = "wildbase";
+               res_incexe.current_opts->wildbase.append(bstrdup(lc->str));
+               newsize = res_incexe.current_opts->wildbase.size();
+            }
          } else {
             type = "wild";
             res_incexe.current_opts->wild.append(bstrdup(lc->str));
@@ -516,12 +572,51 @@ static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
    scan_to_eol(lc);
 }
 
+/* Store exclude directory containing  info */
+static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
+{
+   int token;
+
+   if (exclude) {
+      scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
+      /* NOT REACHED */
+   }
+   token = lex_get_token(lc, T_NAME);
+   if (pass == 1) {
+      res_incexe.current_opts->ignoredir = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+}
+
+/* Store drivetype info */
+static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (pass == 1) {
+      /* Pickup drivetype string */
+      switch (token) {
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+      case T_QUOTED_STRING:
+         res_incexe.current_opts->drivetype.append(bstrdup(lc->str));
+         Dmsg3(900, "set drivetype %p size=%d %s\n",
+            res_incexe.current_opts, res_incexe.current_opts->drivetype.size(), lc->str);
+         break;
+      default:
+         scan_err1(lc, _("Expected an drivetype string, got: %s\n"), lc->str);
+      }
+   }
+   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, RES_ITEM *item, int index, int pass)
+static void store_fname(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
 {
    int token;
    INCEXE *incexe;
@@ -531,34 +626,87 @@ static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass)
       /* Pickup Filename string
        */
       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->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);
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+         if (strchr(lc->str, '\\')) {
+            scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
+            /* NOT REACHED */
+         }
+      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);
       }
    }
    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_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
+{
+   int token;
+   INCEXE *incexe;
+
+   if (exclude) {
+      scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
+      /* NOT REACHED */
+   }
+   token = lex_get_token(lc, T_SKIP_EOL);
+   if (pass == 1) {
+      /* Pickup Filename string
+       */
+      switch (token) {
+      case T_IDENTIFIER:
+      case T_UNQUOTED_STRING:
+         if (strchr(lc->str, '\\')) {
+            scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
+            /* NOT REACHED */
+         }
+      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->plugin_list.size() == 0) {
+            incexe->plugin_list.init(10, true);
+         }
+         incexe->plugin_list.append(bstrdup(lc->str));
+         Dmsg1(900, "Add to plugin_list %s\n", lc->str);
+         break;
+      default:
+         scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
+         /* NOT REACHED */
+      }
+   }
+   scan_to_eol(lc);
+}
+
+
 
 /*
  * Come here when Options seen in Include/Exclude
  */
-static void options_res(LEX *lc, RES_ITEM *item, int index, int pass)
+static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
 {
    int token, i;
 
+   if (exclude) {
+      scan_err0(lc, _("Options section not permitted in Exclude\n"));
+      /* NOT REACHED */
+   }
    token = lex_get_token(lc, T_SKIP_EOL);
    if (token != T_BOB) {
       scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
@@ -640,8 +788,10 @@ static void setup_current_opts(void)
    fo->wild.init(1, true);
    fo->wilddir.init(1, true);
    fo->wildfile.init(1, true);
+   fo->wildbase.init(1, true);
    fo->base.init(1, true);
    fo->fstype.init(1, true);
+   fo->drivetype.init(1, true);
    res_incexe.current_opts = fo;
    if (res_incexe.num_opts == 0) {
       res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *));