* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ 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 ammended with additional clauses defined in the
+ 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,
#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;
-#ifdef HAVE_WIN32
-// work around visual studio name manling preventing external linkage since res_all
+#if defined(_MSC_VER)
+// 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" int res_all_size;
#else
extern CURES res_all;
-extern int res_all_size;
#endif
+extern int res_all_size;
extern brwlock_t res_lock; /* resource lock */
/* 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);
/* Common Resource definitions */
{"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},
- {NULL, NULL, NULL, 0, 0}
+ {"catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, 0, 0},
+ {NULL, NULL, {0}, 0, 0, 0}
};
struct s_mtypes {
{"restored", M_RESTORED},
{"security", M_SECURITY},
{"alert", M_ALERT},
+ {"volmgmt", M_VOLMGMT},
{"all", M_MAX+1},
{NULL, 0}
};
*
* tape label label code = token
*/
-struct s_kw tapelabels[] = {
+static s_kw tapelabels[] = {
{"bacula", B_BACULA_LABEL},
{"ansi", B_ANSI_LABEL},
{"ibm", B_IBM_LABEL},
(items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
items[i].default_value);
if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
- if (items[i].handler == store_yesno) {
+ 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 != 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 */
*/
static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
{
- int i, found, quit, is_not;
+ int i;
+ bool found, is_not;
int msg_type = 0;
char *str;
- for (quit=0; !quit;) {
+ for ( ;; ) {
lex_get_token(lc, T_NAME); /* expect at least one type */
- found = FALSE;
+ found = false;
if (lc->str[0] == '!') {
- is_not = TRUE;
+ is_not = true;
str = &lc->str[1];
} else {
- is_not = FALSE;
+ is_not = false;
str = &lc->str[0];
}
for (i=0; msg_types[i].name; i++) {
if (strcasecmp(str, msg_types[i].name) == 0) {
msg_type = msg_types[i].token;
- found = TRUE;
+ found = true;
break;
}
}
for (i=1; i<=M_MAX; i++) { /* yes set all types */
add_msg_dest(msg, dest_code, i, where, cmd);
}
+ } else if (is_not) {
+ rem_msg_dest(msg, dest_code, msg_type, where);
} else {
- if (is_not) {
- rem_msg_dest(msg, dest_code, msg_type, where);
- } else {
- add_msg_dest(msg, dest_code, msg_type, where, cmd);
- }
+ add_msg_dest(msg, dest_code, msg_type, where, cmd);
}
if (lc->ch != ',') {
break;
{
unsigned int i, j;
struct MD5Context md5c;
- unsigned char signature[16];
+ unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
char sig[100];
if (pass == 1) {
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
- MD5Final(signature, &md5c);
- for (i = j = 0; i < sizeof(signature); i++) {
- sprintf(&sig[j], "%02x", signature[i]);
+ MD5Final(digest, &md5c);
+ for (i = j = 0; i < sizeof(digest); i++) {
+ sprintf(&sig[j], "%02x", digest[i]);
j += 2;
}
*(item->value) = bstrdup(sig);
case T_UNQUOTED_STRING:
bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
/* if terminated by space, scan and get modifier */
- if (lc->ch == ' ') {
+ while (lc->ch == ' ') {
token = lex_get_token(lc, T_ALL);
switch (token) {
+ case T_NUMBER:
case T_IDENTIFIER:
case T_UNQUOTED_STRING:
bstrncat(bsize, lc->str, sizeof(bsize));
case T_UNQUOTED_STRING:
bstrncpy(period, lc->str, sizeof(period)); /* get first part */
/* if terminated by space, scan and get modifier */
- if (lc->ch == ' ') {
+ while (lc->ch == ' ') {
token = lex_get_token(lc, T_ALL);
switch (token) {
+ case T_NUMBER:
case T_IDENTIFIER:
case T_UNQUOTED_STRING:
bstrncat(period, lc->str, sizeof(period));
/* Store a yes/no in a bit field */
-void store_yesno(LEX *lc, RES_ITEM *item, int index, int pass)
+void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
{
lex_get_token(lc, T_NAME);
- if (strcasecmp(lc->str, "yes") == 0) {
+ if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
*(int *)(item->value) |= item->code;
- } else if (strcasecmp(lc->str, "no") == 0) {
+ } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
*(int *)(item->value) &= ~(item->code);
} else {
- scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
+ scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
+ }
+ scan_to_eol(lc);
+ set_bit(index, res_all.hdr.item_present);
+}
+
+/* Store a bool in a bit field */
+void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+ lex_get_token(lc, T_NAME);
+ if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
+ *(bool *)(item->value) = true;
+ } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
+ *(bool *)(item->value) = false;
+ } else {
+ scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
}
scan_to_eol(lc);
set_bit(index, res_all.hdr.item_present);
}
+
/*
* Store Tape Label Type (Bacula, ANSI, IBM)
*
}
}
if (i != 0) {
- scan_err1(lc, "Expected a Tape Label keyword, got: %s", lc->str);
+ scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
}
scan_to_eol(lc);
set_bit(index, res_all.hdr.item_present);
* scan_error handler is to die on an error.
*/
int
-parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error)
+parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
{
LEX *lc = NULL;
int token, i, pass;
RES_ITEM *items = NULL;
int level = 0;
+ char *full_path = (char *)alloca(MAX_PATH);
+
+ if (find_config_file(cf, full_path)) {
+ cf = full_path;
+ }
+
/* Make two passes. The first builds the name symbol table,
* and the second picks up the items.
*/
} else {
lex_set_default_error_handler(lc);
}
+ lex_set_error_handler_error_type(lc, err_type) ;
bstrncpy(lc->str, cf, sizeof(lc->str));
lc->fname = lc->str;
scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
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));
switch (state) {
if (token == T_EOL) {
break;
}
+ if (token == T_UNICODE_MARK) {
+ break;
+ }
if (token != T_IDENTIFIER) {
scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
return 0;
}
if (state == p_none) {
scan_err1(lc, _("expected resource name, got: %s"), lc->str);
- return 0;
+ return 0;
}
break;
case p_resource:
level--;
state = p_none;
Dmsg0(900, "T_EOB => define new resource\n");
+ if (res_all.hdr.name == NULL) {
+ scan_err0(lc, _("Name not specified for resource"));
+ }
save_resource(res_type, items, pass); /* save resource */
break;
return 1;
}
+const char *get_default_configdir()
+{
+#if defined(HAVE_WIN32)
+#define DEFAULT_CONFIGDIR "C:\\Documents and Settings\\All Users\\Application Data\\Bacula"
+
+ HRESULT hr;
+ static char szConfigDir[MAX_PATH + 1] = { 0 };
+
+ if (szConfigDir[0] == '\0') {
+ hr = 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 "/etc/bacula";
+#endif
+}
+
+bool
+find_config_file(const char *config_file, char *full_path)
+{
+#if defined(HAVE_WIN32)
+ if (strpbrk(config_file, ":/\\") != NULL) {
+ return false;
+ }
+#else
+ if (strchr(config_file, '/') != NULL) {
+ return false;
+ }
+#endif
+
+ struct stat st;
+
+ if (stat(config_file, &st) == 0) {
+ return false;
+ }
+
+ const char *config_dir = get_default_configdir();
+ size_t dir_length = strlen(config_dir);
+ size_t 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 (full_path[dir_length - 1] != '/' &&
+ full_path[dir_length - 1] != '\\') {
+ full_path[dir_length++] = '/';
+ }
+
+ memcpy(&full_path[dir_length], config_file, file_length + 1);
+
+ return true;
+}
+
/*********************************************************************
*
* Free configuration resources