]> git.sur5r.net Git - bacula/bacula/commitdiff
Rewrite cleanup_old_files() and add safe_unlink() to make unlinking temp files more...
authorKern Sibbald <kern@sibbald.com>
Sun, 9 Sep 2012 18:21:50 +0000 (20:21 +0200)
committerKern Sibbald <kern@sibbald.com>
Sat, 20 Apr 2013 12:50:57 +0000 (14:50 +0200)
bacula/src/dird/dird.c
bacula/src/lib/bsys.c
bacula/src/lib/message.c
bacula/src/lib/protos.h
bacula/src/stored/stored.c

index 1c74ea049170772121247d73a8d595c7431a86f2..b2c3741a52c06a9b480ffae648cfdd140e875b57 100644 (file)
 
 #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
 
@@ -283,8 +296,6 @@ int main (int argc, char *argv[])
 
    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;
 
@@ -298,6 +309,8 @@ int main (int argc, char *argv[])
 
    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;
@@ -1128,31 +1141,108 @@ static bool check_catalog(cat_op mode)
    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);
 }
index 77137360d13a893db434772fcffefcc131da0833..ce4964e763d87fe588db4abcd7c43317262e332d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    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
index 48cd7a600be078dc35b93d709d7d3e95ab1c392d..e8149722d8c37dc8180158871a88b00da4218f2b 100644 (file)
@@ -585,10 +585,11 @@ void close_msg(JCR *jcr)
             }
             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");
index c956eccb354e321a149621423d5629c5c7a8c3ad..548799f6417d71cd935486f1a98d3a685c13e70b 100644 (file)
@@ -82,6 +82,7 @@ char     *escape_filename(const char *file_path);
 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);
index e0cb9dfafd51f613bb9f3008070b13d7ba55c18d..f2c65beaf34391ece83ea11bc6abbb2eb1fbe33f 100644 (file)
@@ -259,7 +259,6 @@ int main (int argc, char *argv[])
 
    cleanup_old_files();
 
-
    /* Ensure that Volume Session Time and Id are both
     * set and are both non-zero.
     */
@@ -459,23 +458,97 @@ static int check_resources()
 
 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);
 }