+/*
+ 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 John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
/*
* Master Configuration routines.
*
*
* Version $Id$
*/
-/*
- Copyright (C) 2000-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"
-extern int debug_level;
+#if defined(HAVE_WIN32)
+#include "shlobj.h"
+#else
+#define MAX_PATH 1024
+#endif
/* Each daemon has a slightly different set of
* resources, so it will define the following
extern RES_TABLE resources[];
extern RES **res_head;
+/*
+ * Define the Union of all the common resource structure definitions.
+ */
+union URES {
+ MSGS res_msgs;
+ RES hdr;
+};
+
#if defined(_MSC_VER)
-// work around visual studio name manling preventing external linkage since res_all
+// work around visual studio name mangling preventing external linkage since res_all
// is declared as a different type when instantiated.
-extern "C" CURES res_all;
+extern "C" URES res_all;
#else
-extern CURES res_all;
+extern URES res_all;
#endif
extern int res_all_size;
/* Forward referenced subroutines */
static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
-
+static const char *get_default_configdir();
+static bool find_config_file(const char *config_file, char *full_path, int max_path);
/* Common Resource definitions */
{"syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0},
{"mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0},
{"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
+ {"mailonsuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0},
{"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
{"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
{"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
{"director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
{"console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
{"operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
+ {"catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, 0, 0},
{NULL, NULL, {0}, 0, 0, 0}
};
{"restored", M_RESTORED},
{"security", M_SECURITY},
{"alert", M_ALERT},
+ {"volmgmt", M_VOLMGMT},
{"all", M_MAX+1},
{NULL, 0}
};
* Initialize the static structure to zeros, then
* apply all the default values.
*/
-void init_resource(int type, RES_ITEM *items, int pass)
+static void init_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
{
int i;
int rindex = type - r_first;
- static bool first = true;
- int errstat;
-
- if (first && (errstat=rwl_init(&res_lock)) != 0) {
- Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
- strerror(errstat));
- }
- first = false;
- memset(&res_all, 0, res_all_size);
+ memset(config->m_res_all, 0, config->m_res_all_size);
res_all.hdr.rcode = type;
res_all.hdr.refcnt = 1;
if (items[i].handler == store_bit) {
*(int *)(items[i].value) |= items[i].code;
} else if (items[i].handler == store_bool) {
- *(bool *)(items[i].value) = items[i].default_value;
+ *(bool *)(items[i].value) = items[i].default_value != 0;
} else if (items[i].handler == store_pint ||
items[i].handler == store_int) {
*(int *)(items[i].value) = items[i].default_value;
case MD_STDERR:
case MD_SYSLOG: /* syslog */
case MD_CONSOLE:
+ case MD_CATALOG:
scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
break;
case MD_OPERATOR: /* send to operator */
case MD_DIRECTOR: /* send to Director */
case MD_MAIL: /* mail */
case MD_MAIL_ON_ERROR: /* mail if Job errors */
+ case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */
if (item->code == MD_OPERATOR) {
cmd = res_all.res_msgs.operator_cmd;
} else {
free_pool_memory(dest);
Dmsg0(900, "done with dest codes\n");
break;
+
case MD_FILE: /* file */
case MD_APPEND: /* append */
dest = get_pool_memory(PM_MESSAGE);
p_resource
};
+CONFIG *new_config_parser()
+{
+ CONFIG *config;
+ config = (CONFIG *)malloc(sizeof(CONFIG));
+ memset(config, 0, sizeof(CONFIG));
+ return config;
+}
+
+void CONFIG::init(
+ const char *cf,
+ LEX_ERROR_HANDLER *scan_error,
+ int err_type,
+ void *vres_all,
+ int res_all_size,
+ int r_first,
+ int r_last,
+ RES_TABLE *resources,
+ RES **res_head)
+{
+ m_cf = cf;
+ m_scan_error = scan_error;
+ m_err_type = err_type;
+ m_res_all = vres_all;
+ m_res_all_size = res_all_size;
+ m_r_first = r_first;
+ m_r_last = r_last;
+ m_resources = resources;
+ m_res_head = res_head;
+}
+
/*********************************************************************
*
* Parse configuration file
*/
int
parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
+{
+ int ok;
+ CONFIG *config = new_config_parser();
+ config->init(cf, scan_error, err_type, (void *)&res_all, res_all_size,
+ r_first, r_last, resources, res_head);
+ ok = config->parse_config();
+ free(config);
+ return ok;
+}
+
+
+bool CONFIG::parse_config()
{
LEX *lc = NULL;
int token, i, pass;
enum parse_state state = p_none;
RES_ITEM *items = NULL;
int level = 0;
+ static bool first = true;
+ int errstat;
+ const char *cf = m_cf;
+ LEX_ERROR_HANDLER *scan_error = m_scan_error;
+ int err_type = m_err_type;
+
+ if (first && (errstat=rwl_init(&res_lock)) != 0) {
+ berrno be;
+ Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
+ be.bstrerror(errstat));
+ }
+ first = false;
+
+ char *full_path = (char *)alloca(MAX_PATH + 1);
+
+ if (find_config_file(cf, full_path, MAX_PATH +1)) {
+ cf = full_path;
+ }
/* Make two passes. The first builds the name symbol table,
* and the second picks up the items.
bstrncpy(lc->str, cf, sizeof(lc->str));
lc->fname = lc->str;
scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
- lc->str, be.strerror());
+ lc->str, be.bstrerror());
free(lc);
return 0;
}
lex_set_error_handler_error_type(lc, err_type) ;
while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
- Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
+ Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
+ lex_tok_to_str(token));
switch (state) {
case p_none:
if (token == T_EOL) {
break;
- }
- if (token != T_IDENTIFIER) {
+ } else if (token == T_UTF8_BOM) {
+ /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
+ break;
+ } else if (token == T_UTF16_BOM) {
+ scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
+ "Please convert the conf file to UTF-8\n"));
+ return 0;
+ } else if (token != T_IDENTIFIER) {
scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
return 0;
}
- for (i=0; resources[i].name; i++)
+ for (i=0; resources[i].name; i++) {
if (strcasecmp(resources[i].name, lc->str) == 0) {
- state = p_resource;
items = resources[i].items;
+ if (!items) {
+ break;
+ }
+ state = p_resource;
res_type = resources[i].rcode;
- init_resource(res_type, items, pass);
+ init_resource(this, res_type, items, pass);
break;
}
+ }
if (state == p_none) {
scan_err1(lc, _("expected resource name, got: %s"), lc->str);
- return 0;
+ return 0;
}
break;
case p_resource:
return 1;
}
+const char *get_default_configdir()
+{
+#if defined(HAVE_WIN32)
+ HRESULT hr;
+ static char szConfigDir[MAX_PATH + 1] = { 0 };
+
+ if (!p_SHGetFolderPath) {
+ bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
+ return szConfigDir;
+ }
+
+ if (szConfigDir[0] == '\0') {
+ hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
+
+ if (SUCCEEDED(hr)) {
+ bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
+ } else {
+ bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
+ }
+ }
+ return szConfigDir;
+#else
+ return SYSCONFDIR;
+#endif
+}
+
+static bool
+find_config_file(const char *config_file, char *full_path, int max_path)
+{
+ if (first_path_separator(config_file) != NULL) {
+ return false;
+ }
+
+ struct stat st;
+
+ if (stat(config_file, &st) == 0) {
+ return false;
+ }
+
+ const char *config_dir = get_default_configdir();
+ int dir_length = strlen(config_dir);
+ int file_length = strlen(config_file);
+
+ if ((dir_length + 1 + file_length + 1) > max_path) {
+ return false;
+ }
+
+ memcpy(full_path, config_dir, dir_length + 1);
+
+ if (!IsPathSeparator(full_path[dir_length - 1])) {
+ full_path[dir_length++] = '/';
+ }
+
+ memcpy(&full_path[dir_length], config_file, file_length + 1);
+
+ return true;
+}
+
/*********************************************************************
*
* Free configuration resources
*
*/
+void CONFIG::free_resources()
+{
+ for (int i=m_r_first; i<=m_r_last; i++) {
+ free_resource(m_res_head[i-m_r_first], i);
+ m_res_head[i-m_r_first] = NULL;
+ }
+}
+
+RES **CONFIG::save_resources()
+{
+ int num = m_r_last - m_r_first + 1;
+ RES **res = (RES **)malloc(num*sizeof(RES *));
+ for (int i=0; i<num; i++) {
+ res[i] = m_res_head[i];
+ m_res_head[i] = NULL;
+ }
+ return res;
+}
+
+RES **CONFIG::new_res_head()
+{
+ int size = (m_r_last - m_r_first + 1) * sizeof(RES *);
+ RES **res = (RES **)malloc(size);
+ memset(res, 0, size);
+ return res;
+}
+
void free_config_resources()
{
for (int i=r_first; i<=r_last; i++) {
}
}
+#ifdef xxx
RES **save_config_resources()
{
int num = r_last - r_first + 1;
memset(res, 0, size);
return res;
}
+#endif