]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/message.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / lib / message.c
index bc5da5ce6512a4c9e5fa17f9d9282b24ac26173b..0dd596f30c20f07458f560dab153ed9d6c2849bc 100644 (file)
@@ -1,17 +1,20 @@
 /*
-   Bacula® - The Network Backup Solution
+   Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2017 Kern Sibbald
 
-   The main author of Bacula is Kern Sibbald, with contributions from many
-   others, a complete list can be found in the file AUTHORS.
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
 
    You may use this file and others of this release according to the
    license defined in the LICENSE file, which includes the Affero General
    Public License, v3.0 ("AGPLv3") and some additional permissions and
    terms pursuant to its AGPLv3 Section 7.
 
-   Bacula® is a registered trademark of Kern Sibbald.
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  * Bacula message handling routines
  *   otherwise you may get into recursive calls if there are
  *   errors, and that can lead to looping or deadlocks.
  *
- *   Written by Kern Sibbald, April 2000
+ *   Kern Sibbald, April 2000
  *
  */
 
 #include "bacula.h"
 #include "jcr.h"
 
-sql_query_func p_sql_query = NULL;
-sql_escape_func p_sql_escape = NULL;
+sql_query_call  p_sql_query = NULL;
+sql_escape_call p_sql_escape = NULL;
 
 #define FULL_LOCATION 1               /* set for file:line in Debug messages */
 
@@ -37,26 +40,29 @@ sql_escape_func p_sql_escape = NULL;
  *  This is where we define "Globals" because all the
  *    daemons include this file.
  */
+dlist *daemon_msg_queue = NULL;
+pthread_mutex_t daemon_msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
 const char *working_directory = NULL; /* working directory path stored here */
 const char *assert_msg = NULL;        /* ASSERT2 error message */
 const char *version = VERSION " (" BDATE ")";
 const char *dist_name = DISTNAME " " DISTVER;
 char *exepath = (char *)NULL;
 char *exename = (char *)NULL;
-char *catalog_db = NULL;              /* database type */
+char db_engine_name[50] = {0};        /* Database engine name or type */
 char con_fname[500];                  /* Console filename */
-char my_name[30] = {0};               /* daemon name is stored here */
+char my_name[MAX_NAME_LENGTH] = {0};  /* daemon name is stored here */
 char host_name[50] = {0};             /* host machine name */
 char fail_time[30] = {0};             /* Time of failure */
 int verbose = 0;                      /* increase User messages */
 int64_t debug_level = 0;              /* debug level */
+int64_t debug_level_tags = 0;         /* debug tags */
 int32_t debug_flags = 0;              /* debug flags */
-int beef = BEEF;
 int console_msg_pending = false;
 utime_t daemon_start_time = 0;        /* Daemon start time */
 FILE *con_fd = NULL;                  /* Console file descriptor */
 brwlock_t con_lock;                   /* Console lock structure */
 bool dbg_timestamp = false;           /* print timestamp in debug output */
+bool dbg_thread = false;              /* add thread_id to details */
 bool prt_kaboom = false;              /* Print kaboom output */
 job_code_callback_t message_job_code_callback = NULL;   /* Job code callback. Only used by director. */
 
@@ -81,6 +87,7 @@ static bool trace = true;
 static bool trace = false;
 #endif
 static int hangup = 0;
+static int blowup = 0;
 
 /* Constants */
 const char *host_os = HOST_OS;
@@ -105,16 +112,6 @@ static const char *bstrrpath(const char *start, const char *end)
    return end;
 }
 
-/*
- * Returns: 0 if not configured
- *         -1 on error
- *          1 OK
- */
-int generate_daemon_event(JCR *jcr, const char *event)
-{
-   return 0;
-}
-
 /* Some message class methods */
 void MSGS::lock()
 {
@@ -197,6 +194,14 @@ void set_debug_flags(char *options)
          dbg_timestamp = false;
          break;
 
+      case 'h':
+         dbg_thread = true;
+         break;
+
+      case 'H':
+         dbg_thread = false;
+         break;
+
       case 'c':
          /* truncate the trace file */
          if (trace && trace_fd) {
@@ -300,15 +305,11 @@ set_assert_msg(const char *file, int line, const char *msg)
    assert_msg = bstrdup(buf);
 }
 
-void
-set_db_type(const char *name)
-{
-   if (catalog_db != NULL) {
-      free(catalog_db);
-   }
-   catalog_db = bstrdup(name);
-}
-
+void set_db_engine_name(const char *name)
+{ 
+   bstrncpy(db_engine_name, name, sizeof(db_engine_name)-1);
+} 
 /*
  * Initialize message handler for a daemon or a Job
  *   We make a copy of the MSGS resource passed, so it belows
@@ -421,7 +422,7 @@ void init_console_msg(const char *wd)
       console_msg_pending = 1;
    }
    close(fd);
-   con_fd = fopen(con_fname, "a+b");
+   con_fd = bfopen(con_fname, "a+b");
    if (!con_fd) {
       berrno be;
       Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
@@ -584,6 +585,7 @@ void close_msg(JCR *jcr)
    Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
    cmd = get_pool_memory(PM_MESSAGE);
    for (d=msgs->dest_chain; d; ) {
+      bool success;
       if (d->fd) {
          switch (d->dest_code) {
          case MD_FILE:
@@ -600,39 +602,18 @@ void close_msg(JCR *jcr)
             if (!d->fd) {
                break;
             }
+            success = jcr && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings);
 
-            switch (d->dest_code) {
-            case MD_MAIL_ON_ERROR:
-               if (jcr) {
-                  switch (jcr->JobStatus) {
-                  case JS_Terminated:
-                  case JS_Warnings:
-                     goto rem_temp_file;
-                  default:
-                     break;
-                  }
-               }
-               break;
-            case MD_MAIL_ON_SUCCESS:
-               if (jcr) {
-                  switch (jcr->JobStatus) {
-                  case JS_Terminated:
-                  case JS_Warnings:
-                     break;
-                  default:
-                     goto rem_temp_file;
-                  }
-               }
-               break;
-            default:
-               break;
+            if (d->dest_code == MD_MAIL_ON_ERROR && success) {
+               goto rem_temp_file;       /* no mail */
+            } else if (d->dest_code == MD_MAIL_ON_SUCCESS && !success) {
+               goto rem_temp_file;       /* no mail */
             }
 
             if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
                Pmsg0(000, _("open mail pipe failed.\n"));
-               goto rem_temp_file;
+               goto rem_temp_file;       /* error get out */
             }
-
             Dmsg0(850, "Opened mail pipe\n");
             len = d->max_len+10;
             line = get_memory(len);
@@ -667,6 +648,7 @@ void close_msg(JCR *jcr)
                                  "ERR=%s\n"), cmd, be.bstrerror());
             }
             free_memory(line);
+
 rem_temp_file:
             /* Remove temp mail file */
             if (d->fd) {
@@ -754,17 +736,15 @@ void term_msg()
    if (trace_fd) {
       fclose(trace_fd);
       trace_fd = NULL;
+      trace = false;
    }
-   if (catalog_db) {
-      free(catalog_db);
-      catalog_db = NULL;
-   }
+   working_directory = NULL;
    term_last_jobs_list();
 }
 
 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
 {
-   d->fd = fopen(d->where, mode);
+   d->fd = bfopen(d->where, mode);
    if (!d->fd) {
       berrno be;
       delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
@@ -807,6 +787,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
     MSGS *msgs;
     BPIPE *bpipe;
     const char *mode;
+    bool created_jcr = false;
 
     Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
 
@@ -852,6 +833,10 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
     if (!jcr) {
        jcr = get_jcr_from_tsd();
     }
+    if (!jcr) {
+       jcr = new_jcr(sizeof(JCR), NULL);
+       created_jcr = true;
+    }
     if (jcr) {
        msgs = jcr->jcr_msgs;
     }
@@ -870,12 +855,14 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
        return;
     }
 
+
     for (d=msgs->dest_chain; d; d=d->next) {
        if (bit_is_set(type, d->msg_types)) {
+          bool ok;
           switch (d->dest_code) {
              case MD_CATALOG:
                 char ed1[50];
-                if (!jcr || !jcr->db) {
+                if (!jcr || !jcr->db) { 
                    break;
                 }
                 if (p_sql_query && p_sql_escape) {
@@ -883,18 +870,17 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
                    POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
 
                    int len = strlen(msg) + 1;
-                   esc_msg = check_pool_memory_size(esc_msg, len * 2 + 1);
-                   if (p_sql_escape(jcr, jcr->db, esc_msg, msg, len)) {
-                      bstrutime(dt, sizeof(dt), mtime);
-                      Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
-                            edit_int64(jcr->JobId, ed1), dt, esc_msg);
-                      if (!p_sql_query(jcr, cmd)) {
-                         delivery_error(_("Msg delivery error: Unable to store data in database.\n"));
-                      }
-                   } else {
-                      delivery_error(_("Msg delivery error: Unable to store data in database.\n"));
-                   }
-
+                   esc_msg = check_pool_memory_size(esc_msg, len*2+1);
+                   ok = p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
+                   if (ok) {
+                      bstrutime(dt, sizeof(dt), mtime); 
+                      Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')", 
+                           edit_int64(jcr->JobId, ed1), dt, esc_msg);
+                      ok = p_sql_query(jcr, cmd);
+                   } 
+                   if (!ok) {
+                      delivery_error(_("Message delivery error: Unable to store data in database.\n"));
+                   } 
                    free_pool_memory(cmd);
                    free_pool_memory(esc_msg);
                 }
@@ -902,7 +888,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
              case MD_CONSOLE:
                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
                 if (!con_fd) {
-                   con_fd = fopen(con_fname, "a+b");
+                   con_fd = bfopen(con_fname, "a+b");
                    Dmsg0(850, "Console file not open.\n");
                 }
                 if (con_fd) {
@@ -962,7 +948,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
                 if (!d->fd) {
                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
                    make_unique_mail_filename(jcr, name, d);
-                   d->fd = fopen(name, "w+b");
+                   d->fd = bfopen(name, "w+b");
                    if (!d->fd) {
                       berrno be;
                       delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
@@ -1013,8 +999,8 @@ send_to_file:
              case MD_DIRECTOR:
                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
-                   jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
-                      jcr->Job, type, mtime, msg);
+                   jcr->dir_bsock->fsend("Jmsg JobId=%ld type=%d level=%lld %s",
+                      jcr->JobId, type, mtime, msg);
                 } else {
                    Dmsg1(800, "no jcr for following msg: %s", msg);
                 }
@@ -1038,6 +1024,9 @@ send_to_file:
           }
        }
     }
+    if (created_jcr) {
+       free_jcr(jcr);
+    }
 }
 
 /*********************************************************************
@@ -1074,7 +1063,7 @@ static void pt_out(char *buf)
        if (!trace_fd) {
           char fn[200];
           bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
-          trace_fd = fopen(fn, "a+b");
+          trace_fd = bfopen(fn, "a+b");
        }
        if (trace_fd) {
           fputs(buf, trace_fd);
@@ -1099,13 +1088,13 @@ static void pt_out(char *buf)
  *
  *  If the level is negative, the details of file and line number
  *  are not printed.
+ *
  */
 void
-d_msg(const char *file, int line, int64_t level, const char *fmt,...)
+vd_msg(const char *file, int line, int64_t level, const char *fmt, va_list arg_ptr)
 {
     char      buf[5000];
-    int       len;
-    va_list   arg_ptr;
+    int       len = 0; /* space used in buf */
     bool      details = true;
     utime_t   mtime;
 
@@ -1117,31 +1106,39 @@ d_msg(const char *file, int line, int64_t level, const char *fmt,...)
     if (chk_dbglvl(level)) {
        if (dbg_timestamp) {
           mtime = time(NULL);
-          bstrftimes(buf, sizeof(buf), mtime);
+          bstrftimes(buf+len, sizeof(buf)-len, mtime);
           len = strlen(buf);
           buf[len++] = ' ';
-          buf[len] = 0;
-          pt_out(buf);
        }
 
 #ifdef FULL_LOCATION
        if (details) {
-          len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
-                my_name, get_basename(file), line, get_jobid_from_tsd());
-       } else {
-          len = 0;
+          if (dbg_thread) {
+             len += bsnprintf(buf+len, sizeof(buf)-len, "%s[%lld]: %s:%d-%u ",
+                             my_name, bthread_get_thread_id(),
+                             get_basename(file), line, get_jobid_from_tsd());
+          } else {
+             len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
+                   my_name, get_basename(file), line, get_jobid_from_tsd());
+          }
        }
-#else
-       len = 0;
 #endif
-       va_start(arg_ptr, fmt);
        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
-       va_end(arg_ptr);
 
        pt_out(buf);
     }
 }
 
+void
+d_msg(const char *file, int line, int64_t level, const char *fmt,...)
+{
+   va_list arg_ptr;
+   va_start(arg_ptr, fmt);
+   vd_msg(file, line, level, fmt, arg_ptr); /* without tags */
+   va_end(arg_ptr);
+}
+
+
 /*
  * Set trace flag on/off. If argument is negative, there is no change
  */
@@ -1164,9 +1161,7 @@ void set_trace(int trace_flag)
 
 void set_hangup(int hangup_value)
 {
-   if (hangup_value < 0) {
-      return;
-   } else {
+   if (hangup_value != -1) {
       hangup = hangup_value;
    }
 }
@@ -1176,6 +1171,49 @@ int get_hangup(void)
    return hangup;
 }
 
+void set_blowup(int blowup_value)
+{
+   if (blowup_value != -1) {
+      blowup = blowup_value;
+   }
+}
+
+int get_blowup(void)
+{
+   return blowup;
+}
+
+bool handle_hangup_blowup(JCR *jcr, uint32_t file_count, uint64_t byte_count)
+{
+   if (hangup == 0 && blowup == 0) {
+      /* quick check */
+      return false;
+   }
+   /* Debug code: check if we must hangup  or blowup */
+   if ((hangup > 0 && (file_count > (uint32_t)hangup)) ||
+       (hangup < 0 && (byte_count/1024 > (uint32_t)-hangup)))  {
+      jcr->setJobStatus(JS_Incomplete);
+      if (hangup > 0) {
+         Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
+      } else {
+         Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d Kbytes.\n", -hangup);
+      }
+      set_hangup(0);
+      return true;
+   }
+   if ((blowup > 0 && (file_count > (uint32_t)blowup)) ||
+       (blowup < 0 && (byte_count/1024 > (uint32_t)-blowup)))  {
+      if (blowup > 0) {
+         Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
+      } else {
+         Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d Kbytes.\n", -blowup);
+      }
+      /* will never reach this line */
+      return true;
+   }
+   return false;
+}
+
 bool get_trace(void)
 {
    return trace;
@@ -1192,18 +1230,21 @@ void
 p_msg(const char *file, int line, int level, const char *fmt,...)
 {
     char      buf[5000];
-    int       len;
+    int       len = 0; /* space used in buf */
     va_list   arg_ptr;
 
+    if (dbg_timestamp) {
+       utime_t mtime = time(NULL);
+       bstrftimes(buf+len, sizeof(buf)-len, mtime);
+       len = strlen(buf);
+       buf[len++] = ' ';
+    }
+
 #ifdef FULL_LOCATION
     if (level >= 0) {
-       len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
+       len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
              my_name, get_basename(file), line, get_jobid_from_tsd());
-    } else {
-       len = 0;
     }
-#else
-       len = 0;
 #endif
 
     va_start(arg_ptr, fmt);
@@ -1232,15 +1273,17 @@ t_msg(const char *file, int line, int64_t level, const char *fmt,...)
     va_list   arg_ptr;
     int       details = TRUE;
 
+    level = level & ~DT_ALL;    /* level should be tag free */
+
     if (level < 0) {
        details = FALSE;
        level = -level;
     }
 
-    if (chk_dbglvl(level)) {
+    if (level <= debug_level) {
        if (!trace_fd) {
           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
-          trace_fd = fopen(buf, "a+b");
+          trace_fd = bfopen(buf, "a+b");
        }
 
 #ifdef FULL_LOCATION
@@ -1318,6 +1361,7 @@ e_msg(const char *file, int line, int type, int level, const char *fmt,...)
     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
     va_end(arg_ptr);
 
+    pt_out(buf);
     dispatch_message(NULL, type, 0, buf);
 
     if (type == M_ABORT) {
@@ -1329,6 +1373,23 @@ e_msg(const char *file, int line, int type, int level, const char *fmt,...)
     }
 }
 
+/* Check in the msgs resource if a given type is defined */
+bool is_message_type_set(JCR *jcr, int type)
+{
+   MSGS *msgs = NULL;
+   if (jcr) {
+       msgs = jcr->jcr_msgs;
+   }
+   if (!msgs) {
+      msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
+   }
+   if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
+       !bit_is_set(type, msgs->send_msg)) {
+      return false;                 /* no destination */
+   }
+   return true;
+}
+
 /* *********************************************************
  *
  * Generate a Job message
@@ -1457,6 +1518,10 @@ void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const
    int i, len, maxlen;
    POOLMEM *pool_buf;
 
+   va_start(arg_ptr, fmt);
+   vd_msg(file, line, 0, fmt, arg_ptr);
+   va_end(arg_ptr);
+
    pool_buf = get_pool_memory(PM_EMSG);
    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
 
@@ -1619,10 +1684,19 @@ void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
    if (!jcr) {
       jcr = get_jcr_from_tsd();
    }
+
+   if (jcr && type==M_FATAL) {
+      jcr->setJobStatus(JS_FatalError);
+    }
+
    /* If no jcr or no queue or dequeuing send to syslog */
    if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
       syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
-      free(item);
+      P(daemon_msg_queue_mutex);
+      if (daemon_msg_queue) {
+         daemon_msg_queue->append(item);
+      }
+      V(daemon_msg_queue_mutex);
    } else {
       /* Queue message for later sending */
       P(jcr->msg_queue_mutex);
@@ -1638,6 +1712,30 @@ void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
 void dequeue_messages(JCR *jcr)
 {
    MQUEUE_ITEM *item;
+   JobId_t JobId;
+
+   /* Avoid bad calls and recursion */
+   if (jcr == NULL || jcr->dequeuing_msgs) {
+      return;
+   }
+
+   /* Dequeue daemon messages */
+   if (daemon_msg_queue) {
+      P(daemon_msg_queue_mutex);
+      jcr->dequeuing_msgs = true;
+      JobId = jcr->JobId;
+      jcr->JobId = 0;       /* set daemon JobId == 0 */
+      foreach_dlist(item, daemon_msg_queue) {
+         Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
+      }
+      /* Remove messages just sent */
+      daemon_msg_queue->destroy();
+      jcr->JobId = JobId;   /* restore JobId */
+      jcr->dequeuing_msgs = false;
+      V(daemon_msg_queue_mutex);
+   }
+
+   /* Dequeue Job specific messages */
    if (!jcr->msg_queue) {
       return;
    }
@@ -1702,10 +1800,25 @@ static struct debugtags debug_tags[] = {
  { NT_("memory"),      DT_MEMORY,   _("Debug memory allocation")},
  { NT_("scheduler"),   DT_SCHEDULER,_("Debug scheduler information")},
  { NT_("protocol"),    DT_PROTOCOL, _("Debug protocol information")},
+ { NT_("snapshot"),    DT_SNAPSHOT, _("Debug snapshots")},
+ { NT_("asx"),         DT_ASX,      _("ASX personal's debugging")},
  { NT_("all"),         DT_ALL,      _("Debug all information")},
  { NULL,               0,   NULL}
 };
 
+#define MAX_TAG (sizeof(debug_tags) / sizeof(struct debugtags))
+
+const char *debug_get_tag(uint32_t pos, const char **desc)
+{
+   if (pos < MAX_TAG) {
+      if (desc) {
+         *desc = debug_tags[pos].help;
+      }
+      return debug_tags[pos].tag;
+   }
+   return NULL;
+}
+
 /* Allow +-, */
 bool debug_find_tag(const char *tagname, bool add, int64_t *current_level)
 {
@@ -1783,3 +1896,5 @@ bool debug_parse_tags(const char *options, int64_t *current_level)
    *current_level = level;
    return ret;
 }
+
+int generate_daemon_event(JCR *jcr, const char *event) { return 0; }