From ff9f379bc9f3302ad6d93037192adc763ac00f95 Mon Sep 17 00:00:00 2001 From: Robert Nelson Date: Tue, 24 Oct 2006 23:28:49 +0000 Subject: [PATCH] Change daemons and utilities so that if -c is omitted from the command line AND there is no configuration file in the current directory then the "standard" configuration file (eg /etc/bacula/bacula-*.conf) will be used. If the argument to -c doesn't contain any path separators AND there is no configuration file by that name in the current directory then the "standard" configuration file directory will be searched for a file by that name. Fixed restore on Windows so that backslashes as path separators works. Add missing query.sql file to Windows installer. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3572 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/console/console.c | 2 +- bacula/src/dird/dird.c | 2 +- bacula/src/dird/ua_restore.c | 30 ++++- bacula/src/filed/filed.c | 2 +- bacula/src/findlib/create_file.c | 13 +- bacula/src/findlib/makepath.c | 22 +++- bacula/src/lib/bsys.c | 24 ++++ bacula/src/lib/parse_conf.c | 81 +++++++++++- bacula/src/lib/protos.h | 1 + bacula/src/win32/cats/make_catalog_backup.cmd | 71 ++++++----- bacula/src/win32/compat/compat.cpp | 26 ++-- bacula/src/win32/dird/dird.vcproj | 8 ++ bacula/src/win32/dll/bacula.def | 1 + bacula/src/win32/installer/Makefile | 7 +- bacula/src/win32/installer/bacula-dir.conf.in | 6 +- bacula/src/win32/installer/installer.vcproj | 8 +- bacula/src/win32/libbac/msvc/bacula.def | 1 + .../src/win32/stored/storelib/storelib.vcproj | 120 +++++++++--------- 18 files changed, 294 insertions(+), 131 deletions(-) diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 8bae25bde3..331f50ccc8 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -90,7 +90,7 @@ static int timecmd(FILE *input, BSOCK *UA_sock); static int sleepcmd(FILE *input, BSOCK *UA_sock); -#define CONFIG_FILE "./bconsole.conf" /* default configuration file */ +#define CONFIG_FILE "bconsole.conf" /* default configuration file */ static void usage() { diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index df1efeb848..b8d6491c2d 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -70,7 +70,7 @@ extern "C" { // work around visual compiler mangling variables extern URES res_all; #endif -#define CONFIG_FILE "./bacula-dir.conf" /* default configuration file */ +#define CONFIG_FILE "bacula-dir.conf" /* default configuration file */ static void usage() { diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 1ae783b8ee..090c78bbae 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -68,6 +68,8 @@ int restore_cmd(UAContext *ua, const char *cmd) JOB *job; int i; JCR *jcr = ua->jcr; + char *escaped_bsr_name = NULL; + char *escaped_where_name = NULL; memset(&rx, 0, sizeof(rx)); rx.path = get_pool_memory(PM_FNAME); @@ -166,24 +168,40 @@ int restore_cmd(UAContext *ua, const char *cmd) goto bail_out; } + escaped_bsr_name = escape_filename(jcr->RestoreBootstrap); + escaped_where_name = escape_filename(rx.where); + /* Build run command */ if (rx.where) { if (!acl_access_ok(ua, Where_ACL, rx.where)) { bsendmsg(ua, _("Forbidden \"where\" specified.\n")); goto bail_out; } + Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" " where=\"%s\" files=%d catalog=\"%s\"", job->name(), rx.ClientName, rx.store?rx.store->name():"", - jcr->RestoreBootstrap, rx.where, rx.selected_files, ua->catalog->name()); + escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, + escaped_where_name ? escaped_where_name : rx.where, + rx.selected_files, ua->catalog->name()); } else { Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" " files=%d catalog=\"%s\"", job->name(), rx.ClientName, rx.store?rx.store->name():"", - jcr->RestoreBootstrap, rx.selected_files, ua->catalog->name()); + escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, + rx.selected_files, ua->catalog->name()); + } + + if (escaped_bsr_name != NULL) { + bfree(escaped_bsr_name); + } + + if (escaped_where_name != NULL) { + bfree(escaped_where_name); } + if (find_arg(ua, NT_("yes")) > 0) { pm_strcat(ua->cmd, " yes"); /* pass it on to the run command */ } @@ -194,6 +212,14 @@ int restore_cmd(UAContext *ua, const char *cmd) return 1; bail_out: + if (escaped_bsr_name != NULL) { + bfree(escaped_bsr_name); + } + + if (escaped_where_name != NULL) { + bfree(escaped_where_name); + } + free_rx(&rx); return 0; diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 2a2ccb9d97..fe898e0446 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -36,7 +36,7 @@ CLIENT *me; /* my resource */ bool no_signals = false; -#define CONFIG_FILE "./bacula-fd.conf" /* default config file */ +#define CONFIG_FILE "bacula-fd.conf" /* default config file */ char *configfile = NULL; static bool foreground = false; diff --git a/bacula/src/findlib/create_file.c b/bacula/src/findlib/create_file.c index c494ba8f1e..3f845c1508 100644 --- a/bacula/src/findlib/create_file.c +++ b/bacula/src/findlib/create_file.c @@ -348,15 +348,18 @@ static int separate_path_and_file(JCR *jcr, char *fname, char *ofile) /* Separate pathname and filename */ for (q=p=f=ofile; *p; p++) { - if (*p == '/') { - f = q; /* possible filename */ - } #ifdef HAVE_WIN32 - if (*p == '\\') { /* strip backslashes on Win32 */ - continue; + if (*p == '\\' || *p == '/') { + f = q; + if (p[1] == '\\' || p[1] == '/') { + p++; + } } *q++ = *p; /* copy data */ #else + if (*p == '/') { + f = q; /* possible filename */ + } q++; #endif } diff --git a/bacula/src/findlib/makepath.c b/bacula/src/findlib/makepath.c index 2ca799fadf..dbb873b2ba 100644 --- a/bacula/src/findlib/makepath.c +++ b/bacula/src/findlib/makepath.c @@ -255,9 +255,13 @@ make_path( } /* Skip over leading slashes. */ +#if defined(HAVE_WIN32) + while (*slash == '/' || *slash == '\\') + slash++; +#else while (*slash == '/') slash++; - +#endif while (1) { int newly_created_dir; int fail; @@ -265,10 +269,17 @@ make_path( /* slash points to the leftmost unprocessed component of dirpath. */ basename_dir = slash; +#if defined(HAVE_WIN32) + slash = strpbrk(slash, ":/\\"); + if (slash == NULL) { + break; + } +#else slash = strchr (slash, '/'); if (slash == NULL) { break; } +#endif /* If we're *not* doing chdir before each mkdir, then we have to refer to the target using the full (multi-component) directory name. */ @@ -327,8 +338,13 @@ make_path( /* Avoid unnecessary calls to `stat' when given pathnames containing multiple adjacent slashes. */ - while (*slash == '/') - slash++; +#if defined(HAVE_WIN32) + while (*slash == '/' || *slash == '\\') + slash++; +#else + while (*slash == '/') + slash++; +#endif } /* end while (1) */ if (!cwd.do_chdir) { diff --git a/bacula/src/lib/bsys.c b/bacula/src/lib/bsys.c index a4dc7231aa..2869a3fa29 100644 --- a/bacula/src/lib/bsys.c +++ b/bacula/src/lib/bsys.c @@ -744,3 +744,27 @@ void make_unique_filename(POOLMEM **name, int Id, char *what) { Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id); } + +char *escape_filename(const char *file_path) +{ + if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) { + return NULL; + } + + char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1)); + char *cur_char = escaped_path; + + while (*file_path) { + if (*file_path == '\\' || *file_path == '"') { + *cur_char++ = '\\'; + } + + *cur_char++ = *file_path++; + } + + *cur_char = '\0'; + + return escaped_path; +} + + diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index d5a0ceafda..fb18ada83c 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -50,6 +50,12 @@ #include "bacula.h" +#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 * global values. @@ -60,7 +66,7 @@ extern RES_TABLE resources[]; extern RES **res_head; #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; #else @@ -73,7 +79,8 @@ 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 */ @@ -193,7 +200,7 @@ void init_resource(int type, RES_ITEM *items, int pass) 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; @@ -768,6 +775,12 @@ parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type) 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. */ @@ -895,6 +908,68 @@ parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type) 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 diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index d0ddd5326e..7d93cfd638 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -62,6 +62,7 @@ long long int strtoll (const char *ptr, char **endptr, int base); #endif void read_state_file(char *dir, const char *progname, int port); int bstrerror(int errnum, char *buf, size_t bufsiz); +char *escape_filename(const char *file_path); /* bnet.c */ int32_t bnet_recv (BSOCK *bsock); diff --git a/bacula/src/win32/cats/make_catalog_backup.cmd b/bacula/src/win32/cats/make_catalog_backup.cmd index 18b5a60ae8..29cee07d38 100644 --- a/bacula/src/win32/cats/make_catalog_backup.cmd +++ b/bacula/src/win32/cats/make_catalog_backup.cmd @@ -1,38 +1,41 @@ -#!/bin/sh -# -# This script dumps your Bacula catalog in ASCII format -# It works for MySQL, SQLite, and PostgreSQL -# -# $1 is the name of the database to be backed up and the name -# of the output file (default = bacula -# $2 is the user name with which to access the database -# (default = bacula). -# $3 is the password with which to access the database or "" if no password -# (default "") -# -# -cd %WORKING_DIR% -del /f bacula.sql +@echo off +rem +rem This script dumps your Bacula catalog in ASCII format +rem It works for MySQL, SQLite, and PostgreSQL +rem +rem %1 is the name of the database to be backed up and the name +rem of the output file (default = bacula +rem %2 is the user name with which to access the database +rem (default = bacula). +rem %3 is the password with which to access the database or "" if no password +rem (default "") +rem +rem +@echo on + +cd @working_dir@ +del /f bacula.sql 2>nul set MYSQLPASSWORD= -if "%3"!="" set MYSQLPASSWORD=" --password=%3" -%SQL_BINDIR%/mysqldump -u %2 %MYSQLPASSWORD% -f --opt %1 >%1.sql +if not "%3"=="" set MYSQLPASSWORD=--password=%3 +"@SQL_BINDIR@\mysqldump" -u %2 %MYSQLPASSWORD% -f --opt %1 >%1.sql -# -# To read back a MySQL database use: -# cd @working_dir@ -# rm -f @SQL_BINDIR@/../var/bacula/* -# mysql