]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/message.c
Fix race condition in close_msg that causes seg fault
[bacula/bacula] / bacula / src / lib / message.c
index 05e0c2aabfb9b5e383bfbbad38dfcf1050d102c7..2a67c78ea6d35f48ca49b0d5bf4fabde5df9b49c 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.
@@ -74,6 +74,9 @@ void create_jcr_key();
 
 /* Static storage */
 
+/* Exclude spaces but require .mail at end */
+#define MAIL_REGEX "^[^ ]+\\.mail$"
+
 /* Allow only one thread to tweak d->fd at a time */
 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
 static MSGS *daemon_msgs;              /* global messages */
@@ -92,6 +95,24 @@ const char *host_os = HOST_OS;
 const char *distname = DISTNAME;
 const char *distver = DISTVER;
 
+/*
+ * Walk back in a string from end looking for a
+ *  path separator.  
+ *  This routine is passed the start of the string and
+ *  the end of the string, it returns either the beginning
+ *  of the string or where it found a path separator.
+ */
+static const char *bstrrpath(const char *start, const char *end)
+{
+   while ( end > start ) {
+      end--;   
+      if (IsPathSeparator(*end)) {
+         break;
+      }
+   }
+   return end;
+}
+
 /* Some message class methods */
 void MSGS::lock()
 {
@@ -496,6 +517,11 @@ void close_msg(JCR *jcr)
       return;
    }
    msgs->wait_not_in_use();          /* leaves fides_mutex set */
+   /* Note get_closing() does not lock because we are already locked */
+   if (msgs->get_closing()) {
+      msgs->unlock();
+      return;
+   }
    msgs->set_closing();
    msgs->unlock();
 
@@ -568,11 +594,16 @@ void close_msg(JCR *jcr)
             free_memory(line);
 rem_temp_file:
             /* Remove temp file */
-            fclose(d->fd);
-            d->fd = NULL;
-            unlink(d->mail_filename);
-            free_pool_memory(d->mail_filename);
-            d->mail_filename = NULL;
+            if (d->fd) {
+               fclose(d->fd);
+               d->fd = NULL;
+            }
+            if (d->mail_filename) {
+               /* Exclude spaces in mail_filename */
+               safer_unlink(d->mail_filename, MAIL_REGEX);
+               free_pool_memory(d->mail_filename);
+               d->mail_filename = NULL;
+            }
             Dmsg0(850, "end mail or mail on error\n");
             break;
          default:
@@ -665,6 +696,28 @@ static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
    return true;
 }
 
+/* Split the output for syslog (it converts \n to ' ' and is
+ *   limited to 1024 characters per syslog message
+ */
+static void send_to_syslog(int mode, const char *msg)
+{
+   int len;
+   char buf[1024];
+   const char *p2;
+   const char *p = msg;
+
+   while (*p && ((p2 = strchr(p, '\n')) != NULL)) {
+      len = MIN((int)sizeof(buf) - 1, p2 - p + 1); /* Add 1 to keep \n */
+      strncpy(buf, p, len);
+      buf[len] = 0;
+      syslog(mode, "%s", buf);
+      p = p2+1;                 /* skip \n */
+   }
+   if (*p != 0) {               /* no \n at the end ? */
+      syslog(mode, "%s", p);
+   }
+}
+
 /*
  * Handle sending the message to the appropriate place
  */
@@ -796,7 +849,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
                 /*
                  * We really should do an openlog() here.
                  */
-                syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
+                send_to_syslog(LOG_DAEMON|LOG_ERR, msg);
                 break;
              case MD_OPERATOR:
                 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
@@ -834,7 +887,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
                       delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
                             be.bstrerror());
                       free_pool_memory(name);
-                      V(fides_mutex);
+                      msgs->clear_in_use();
                       break;
                    }
                    d->mail_filename = name;
@@ -913,20 +966,17 @@ send_to_file:
  *  to the full path.  Try to return base + next higher path.
  */
 
-const char *
-get_basename(const char *pathname)
+const char *get_basename(const char *pathname)
 {
-   const char *basename, *basename2;
+   const char *basename;
    
-   if ((basename = strrchr(pathname, PathSeparator)) == NULL) {
-      basename = pathname;
-      if ((basename2 = strrchr(pathname, PathSeparator)) != NULL) {
-         basename = basename2 + 1;
-      }
+   if ((basename = bstrrpath(pathname, pathname+strlen(pathname))) == pathname) {
+      /* empty */
+   } else if ((basename = bstrrpath(pathname, basename-1)) == pathname) {
+      /* empty */
    } else {
       basename++;
    }
-
    return basename;
 }