#include "bacula.h"
#include "dird.h"
+#ifndef HAVE_REGEX_H
+#include "lib/bregex.h"
+#else
+#include <regex.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMELEN(dirent) (strlen((dirent)->d_name))
+#endif
+#ifndef HAVE_READDIR_R
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+#endif
+
#ifdef HAVE_PYTHON
drop(uid, gid, false); /* reduce privileges if requested */
- cleanup_old_files();
-
/* If we are in testing mode, we don't try to fix the catalog */
cat_op mode=(test_config)?CHECK_CONNECTION:UPDATE_AND_FIX;
my_name_is(0, NULL, director->name()); /* set user defined name */
+ cleanup_old_files();
+
/* Plug database interface for library routines */
p_sql_query = (sql_query_func)dir_sql_query;
p_sql_escape = (sql_escape_func)db_escape_string;
return OK;
}
-static void copy_base_name(POOLMEM *cleanup)
+static void cleanup_old_files()
{
+ DIR* dp;
+ struct dirent *entry, *result;
+ int rc, name_max;
+ int my_name_len = strlen(my_name);
int len = strlen(director->working_directory);
-#if defined(HAVE_WIN32)
- pm_strcpy(cleanup, "del /q ");
-#else
- pm_strcpy(cleanup, "/bin/rm -f ");
-#endif
- pm_strcat(cleanup, director->working_directory);
+ POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
+ POOLMEM *basename = get_pool_memory(PM_MESSAGE);
+ regex_t preg1, preg2, pexc1;
+ char prbuf[500];
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ berrno be;
+
+ /* Includes */
+ const char *pat1 = ".*\\.restore\\..*\\.bsr$";
+ const char *pat2 = ".*\\.mail$";
+
+ /* Excludes */
+ const char *exc1 = ".*\\ ";
+
+ /* Setup working directory prefix */
+ pm_strcpy(basename, director->working_directory);
if (len > 0 && !IsPathSeparator(director->working_directory[len-1])) {
- pm_strcat(cleanup, "/");
+ pm_strcat(basename, "/");
}
- pm_strcat(cleanup, my_name);
-}
-static void cleanup_old_files()
-{
- POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
- POOLMEM *results = get_pool_memory(PM_MESSAGE);
- copy_base_name(cleanup);
- pm_strcat(cleanup, "*.restore.*.bsr");
- run_program(cleanup, 0, results);
- copy_base_name(cleanup);
- pm_strcat(cleanup, "*.mail");
- run_program(cleanup, 0, results);
+ /* Compile regex expressions */
+ rc = regcomp(&preg1, pat1, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &preg1, prbuf, sizeof(prbuf));
+ Dmsg2(500, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+ pat1, prbuf);
+ goto get_out4;
+ }
+ rc = regcomp(&preg2, pat2, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &preg2, prbuf, sizeof(prbuf));
+ Pmsg2(100, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+ pat2, prbuf);
+ goto get_out3;
+ }
+
+ rc = regcomp(&pexc1, exc1, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &pexc1, prbuf, sizeof(prbuf));
+ Pmsg2(100, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+ exc1, prbuf);
+ goto get_out2;
+ }
+
+ name_max = pathconf(".", _PC_NAME_MAX);
+ if (name_max < 1024) {
+ name_max = 1024;
+ }
+
+ if (!(dp = opendir(director->working_directory))) {
+ berrno be;
+ Pmsg2(100, "Failed to open working dir %s for cleanup: ERR=%s\n",
+ director->working_directory, be.bstrerror());
+ goto get_out1;
+ return;
+ }
+
+ entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+ while (1) {
+ if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+ break;
+ }
+ /* Exclude any name with ., .., not my_name or containing a space */
+ if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
+ strncmp(result->d_name, my_name, my_name_len) != 0) {
+ Dmsg1(500, "Skipped: %s\n", result->d_name);
+ continue;
+ }
+ rc = regexec(&pexc1, result->d_name, nmatch, pmatch, 0);
+ if (rc == 0) {
+ Dmsg1(500, "Excluded: %s\n", result->d_name);
+ continue;
+ }
+
+ /* Unlink files that match regexes */
+ if (regexec(&preg1, result->d_name, nmatch, pmatch, 0) == 0 ||
+ regexec(&preg2, result->d_name, nmatch, pmatch, 0) == 0) {
+ pm_strcpy(cleanup, basename);
+ pm_strcat(cleanup, result->d_name);
+ Dmsg1(100, "Unlink: %s\n", cleanup);
+ unlink(cleanup);
+ }
+ }
+
+ free(entry);
+ closedir(dp);
+/* Be careful to free up the correct resources */
+get_out1:
+ regfree(&pexc1);
+get_out2:
+ regfree(&preg2);
+get_out3:
+ regfree(&preg1);
+get_out4:
free_pool_memory(cleanup);
- free_pool_memory(results);
+ free_pool_memory(basename);
}
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2012 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.
*/
#include "bacula.h"
-
+#ifndef HAVE_REGEX_H
+#include "lib/bregex.h"
+#else
+#include <regex.h>
+#endif
static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
+/*
+ * This routine is a somewhat safer unlink in that it
+ * allows you to ensure that there are no spaces in the
+ * filename to be deleted, and it also allows you to run
+ * a regex on the filename before excepting it. It also
+ * requires the file to be in the working directory.
+ */
+int safer_unlink(const char *pathname, const char *regx)
+{
+ int rc;
+ regex_t preg1, pexc1;
+ char prbuf[500];
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ int rtn;
+
+ /* Excludes */
+ const char *exc1 = ".*\\ ";
+
+ /* Name must start with working directory */
+ if (strncmp(pathname, working_directory, strlen(working_directory)) != 0) {
+ Pmsg1(000, "Safe_unlink excluded: %s\n", pathname);
+ return EROFS;
+ }
+
+ /* Compile regex expressions */
+ rc = regcomp(&preg1, regx, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &preg1, prbuf, sizeof(prbuf));
+ Pmsg2(000, _("safe_unlink could not compile regex pattern \"%s\" ERR=%s\n"),
+ regx, prbuf);
+ return ENOENT;
+ }
+
+ rc = regcomp(&pexc1, exc1, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &pexc1, prbuf, sizeof(prbuf));
+ Pmsg2(000, _("safe_unlink could not compile regex pattern \"%s\" ERR=%s\n"),
+ exc1, prbuf);
+ regfree(&preg1);
+ return ENOENT;
+ }
+
+ rc = regexec(&pexc1, pathname, nmatch, pmatch, 0);
+ if (rc == 0) {
+ Pmsg1(000, "safe_unlink excluded: %s\n", pathname);
+ rtn = EROFS;
+ goto get_out;
+ }
+
+ /* Unlink files that match regexes */
+ if (regexec(&preg1, pathname, nmatch, pmatch, 0) == 0) {
+ Dmsg1(100, "safe_unlink unlinking: %s\n", pathname);
+ rtn = unlink(pathname);
+ } else {
+ Pmsg2(000, "safe_unlink regex failed: regex=%s file=%s\n", regx, pathname);
+ rtn = EROFS;
+ }
+
+get_out:
+ regfree(&preg1);
+ regfree(&pexc1);
+ return rtn;
+}
+
/*
* This routine will sleep (sec, microsec). Note, however, that if a
* signal occurs, it will return early. It is up to the caller
}
free_memory(line);
rem_temp_file:
- /* Remove temp file */
+ /* Remove temp mail file */
fclose(d->fd);
d->fd = NULL;
- unlink(d->mail_filename);
+ /* Exclude spaces in mail_filename */
+ safer_unlink(d->mail_filename, ".*\\.mail$");
free_pool_memory(d->mail_filename);
d->mail_filename = NULL;
Dmsg0(850, "end mail or mail on error\n");
int Zdeflate(char *in, int in_len, char *out, int &out_len);
int Zinflate(char *in, int in_len, char *out, int &out_len);
void stack_trace();
+int safer_unlink(const char *pathname, const char *regex);
/* bnet.c */
int32_t bnet_recv (BSOCK *bsock);
cleanup_old_files();
-
/* Ensure that Volume Session Time and Id are both
* set and are both non-zero.
*/
static void cleanup_old_files()
{
- POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
- POOLMEM *results = get_pool_memory(PM_MESSAGE);
+ DIR* dp;
+ struct dirent *entry, *result;
+ int rc, name_max;
+ int my_name_len = strlen(my_name);
int len = strlen(me->working_directory);
-#if defined(HAVE_WIN32)
- pm_strcpy(cleanup, "del /q ");
-#else
- pm_strcpy(cleanup, "/bin/rm -f ");
-#endif
- pm_strcat(cleanup, me->working_directory);
+ POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
+ POOLMEM *basename = get_pool_memory(PM_MESSAGE);
+ regex_t preg1, pexc1;
+ char prbuf[500];
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ berrno be;
+
+ /* Includes */
+ const char *pat1 = ".*\\.spool$";
+
+ /* Excludes */
+ const char *exc1 = ".*\\ ";
+
+ /* Setup working directory prefix */
+ pm_strcpy(basename, me->working_directory);
if (len > 0 && !IsPathSeparator(me->working_directory[len-1])) {
- pm_strcat(cleanup, "/");
+ pm_strcat(basename, "/");
+ }
+
+ /* Compile regex expressions */
+ rc = regcomp(&preg1, pat1, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &preg1, prbuf, sizeof(prbuf));
+ Dmsg2(500, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+ pat1, prbuf);
+ goto get_out3;
+ }
+
+ rc = regcomp(&pexc1, exc1, REG_EXTENDED);
+ if (rc != 0) {
+ regerror(rc, &pexc1, prbuf, sizeof(prbuf));
+ Pmsg2(100, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+ exc1, prbuf);
+ goto get_out2;
+ }
+
+ name_max = pathconf(".", _PC_NAME_MAX);
+ if (name_max < 1024) {
+ name_max = 1024;
}
- pm_strcat(cleanup, my_name);
- pm_strcat(cleanup, "*.spool");
- run_program(cleanup, 0, results);
+
+ if (!(dp = opendir(me->working_directory))) {
+ berrno be;
+ Pmsg2(100, "Failed to open working dir %s for cleanup: ERR=%s\n",
+ me->working_directory, be.bstrerror());
+ goto get_out1;
+ }
+
+ //Dmsg1(000, "my_name=%s\n", my_name);
+
+ entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+ while (1) {
+ if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+ break;
+ }
+ /* Exclude any name with ., .., not my_name or containing a space */
+ if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
+ strncmp(result->d_name, my_name, my_name_len) != 0) {
+ Dmsg1(500, "Skipped: %s\n", result->d_name);
+ continue;
+ }
+ rc = regexec(&pexc1, result->d_name, nmatch, pmatch, 0);
+ if (rc == 0) {
+ Dmsg1(500, "Excluded: %s\n", result->d_name);
+ continue;
+ }
+
+ /* Unlink files that match regexes */
+ if (regexec(&preg1, result->d_name, nmatch, pmatch, 0) == 0) {
+ pm_strcpy(cleanup, basename);
+ pm_strcat(cleanup, result->d_name);
+ Dmsg1(500, "Unlink: %s\n", cleanup);
+ unlink(cleanup);
+ }
+ }
+
+ free(entry);
+ closedir(dp);
+get_out1:
+ regfree(&pexc1);
+get_out2:
+ regfree(&preg1);
+get_out3:
free_pool_memory(cleanup);
- free_pool_memory(results);
+ free_pool_memory(basename);
}