+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2000-2009 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 three of the GNU Affero 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 Affero 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-2006 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"
#ifndef HAVE_REGEX_H
-#include "lib/regex.h"
+#include "lib/bregex.h"
#else
#include <regex.h>
#endif
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,
*/
#if defined(_MSC_VER)
extern "C" { // work around visual compiler mangling variables
- extern URES res_all;
+ extern URES res_all;
}
#else
extern URES res_all;
#endif
-extern int res_all_size;
+extern int32_t res_all_size;
/* We build the current new Include and Exclude items here */
static INCEXE res_incexe;
* new Include/Exclude items
* name handler value code flags default_value
*/
-static RES_ITEM newinc_items[] = {
- {"file", store_fname, {0}, 0, 0, 0},
- {"options", options_res, {0}, 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}
};
static RES_ITEM options_items[] = {
{"compression", store_opts, {0}, 0, 0, 0},
{"signature", store_opts, {0}, 0, 0, 0},
+ {"basejob", 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},
{"wildfile", store_wild, {0}, 2, 0, 0},
{"exclude", store_opts, {0}, 0, 0, 0},
{"aclsupport", store_opts, {0}, 0, 0, 0},
- {"reader", store_reader, {0}, 0, 0, 0},
- {"writer", store_writer, {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},
+ {"xattrsupport", store_opts, {0}, 0, 0, 0},
{NULL, NULL, {0}, 0, 0, 0}
};
INC_KW_DIGEST,
INC_KW_ENCRYPTION,
INC_KW_VERIFY,
+ INC_KW_BASEJOB,
+ INC_KW_ACCURATE,
INC_KW_ONEFS,
INC_KW_RECURSE,
INC_KW_SPARSE,
INC_KW_ACL,
INC_KW_IGNORECASE,
INC_KW_HFSPLUS,
- INC_KW_NOATIME
+ INC_KW_NOATIME,
+ INC_KW_ENHANCEDWILD,
+ INC_KW_CHKCHANGES,
+ INC_KW_STRIPPATH,
+ INC_KW_HONOR_NODUMP,
+ INC_KW_XATTR
};
/*
{"signature", INC_KW_DIGEST},
{"encryption", INC_KW_ENCRYPTION},
{"verify", INC_KW_VERIFY},
+ {"basejob", INC_KW_BASEJOB},
+ {"accurate", INC_KW_ACCURATE},
{"onefs", INC_KW_ONEFS},
{"recurse", INC_KW_RECURSE},
{"sparse", INC_KW_SPARSE},
{"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},
+ {"xattrsupport", INC_KW_XATTR},
{NULL, 0}
};
{"gzip7", INC_KW_COMPRESSION, "Z7"},
{"gzip8", INC_KW_COMPRESSION, "Z8"},
{"gzip9", INC_KW_COMPRESSION, "Z9"},
+ {"lzo", INC_KW_COMPRESSION, "Zo"},
{"blowfish", INC_KW_ENCRYPTION, "B"}, /* ***FIXME*** not implemented */
{"3des", INC_KW_ENCRYPTION, "3"}, /* ***FIXME*** not implemented */
{"yes", INC_KW_ONEFS, "0"},
{"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"},
+ {"yes", INC_KW_XATTR, "X"},
+ {"no", INC_KW_XATTR, "0"},
{NULL, 0, 0}
};
*/
static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
{
- int token, i;
+ int i;
char option[3];
int lcopts = lc->options;
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 */
+ 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);
-
+ } 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_BASEJOB) { /* special case */
+ /* ***FIXME**** ensure these are in permitted set */
+ bstrncat(opts, "J", optlen); /* indicate BaseJob */
+ 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
*/
/* If option terminated by comma, eat it */
if (lc->ch == ',') {
- token = lex_get_token(lc, T_ALL); /* yes, eat comma */
+ lex_get_token(lc, T_ALL); /* yes, eat comma */
}
}
/*
*
* 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)
{
/*
- * 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
}
}
/* 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;
}
/* Store Base info */
static void store_base(LEX *lc, RES_ITEM *item, int index, int pass)
{
- int token;
- token = lex_get_token(lc, T_NAME);
+ lex_get_token(lc, T_NAME);
if (pass == 1) {
/*
* Pickup Base Job Name
}
/* 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);
+ lex_get_token(lc, T_NAME);
if (pass == 1) {
/*
- * Pickup reader command
+ * Pickup plugin 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);
+ res_incexe.current_opts->plugin = bstrdup(lc->str);
}
scan_to_eol(lc);
}
-
/* Store Wild-card info */
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));
scan_to_eol(lc);
}
+/* Store exclude directory containing info */
+static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
+{
+
+ if (exclude) {
+ scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
+ /* NOT REACHED */
+ }
+ lex_get_token(lc, T_NAME);
+ if (pass == 1) {
+ res_incexe.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;
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);
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 *));