]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/message.c
Working directory pane in restore. Will get this into the stack next.
[bacula/bacula] / bacula / src / lib / message.c
old mode 100755 (executable)
new mode 100644 (file)
index 1c4b685..9b161a7
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2007 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.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
  * Bacula message handling routines
  *
  *   Version $Id$
  *
  */
-/*
-   Copyright (C) 2000-2006 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
-   the file LICENSE for additional details.
-
- */
-
 
 
 #include "bacula.h"
 #include "jcr.h"
 
-#if !defined(HAVE_CONSOLE) && defined(HAVE_WIN32)
-#include <windows.h>
-#endif
+sql_query p_sql_query = NULL;
+sql_escape p_sql_escape = NULL;
 
 #define FULL_LOCATION 1               /* set for file:line in Debug messages */
 
@@ -49,22 +60,13 @@ char con_fname[500];                  /* Console filename */
 FILE *con_fd = NULL;                  /* Console file descriptor */
 brwlock_t con_lock;                   /* Console lock structure */
 
-
-#if defined(HAVE_POSTGRESQL)
-char catalog_db[] = "PostgreSQL";
-#elif defined(HAVE_MYSQL)
-char catalog_db[] = "MySQL";
-#elif defined(HAVE_SQLITE)
-char catalog_db[] = "SQLite";
-#else
-char catalog_db[] = "Internal";
-#endif
+static char *catalog_db = NULL;       /* database type */
 
 const char *host_os = HOST_OS;
 const char *distname = DISTNAME;
 const char *distver = DISTVER;
 static FILE *trace_fd = NULL;
-#ifdef HAVE_WIN32
+#if defined(HAVE_WIN32)
 static bool trace = true;
 #else
 static bool trace = false;
@@ -103,11 +105,11 @@ void my_name_is(int argc, char *argv[], const char *name)
    if (argc>0 && argv && argv[0]) {
       /* strip trailing filename and save exepath */
       for (l=p=argv[0]; *p; p++) {
-         if (*p == '/') {
+         if (IsPathSeparator(*p)) {
             l = p;                       /* set pos of last slash */
          }
       }
-      if (*l == '/') {
+      if (IsPathSeparator(*l)) {
          l++;
       } else {
          l = argv[0];
@@ -133,7 +135,7 @@ void my_name_is(int argc, char *argv[], const char *name)
          *q++ = *p++;
       }
       *q = 0;
-      if (strchr(exepath, '.') || exepath[0] != '/') {
+      if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
          if (getcwd(cpath, sizeof(cpath))) {
             free(exepath);
             exepath = (char *)malloc(strlen(cpath) + 1 + len);
@@ -144,6 +146,21 @@ void my_name_is(int argc, char *argv[], const char *name)
    }
 }
 
+const char *
+get_db_type(void)
+{
+   return catalog_db != NULL ? catalog_db : "unknown";
+}
+
+void
+set_db_type(const char *name)
+{
+   if (catalog_db != NULL) {
+      free(catalog_db);
+   }
+   catalog_db = bstrdup(name);
+}
+
 /*
  * Initialize message handler for a daemon or a Job
  *   We make a copy of the MSGS resource passed, so it belows
@@ -156,15 +173,13 @@ void
 init_msg(JCR *jcr, MSGS *msg)
 {
    DEST *d, *dnew, *temp_chain = NULL;
-#ifndef HAVE_WIN32
    int i;
-#endif
 
    if (jcr == NULL && msg == NULL) {
       init_last_jobs_list();
    }
 
-#ifndef HAVE_WIN32
+#if !defined(HAVE_WIN32)
    /*
     * Make sure we have fd's 0, 1, 2 open
     *  If we don't do this one of our sockets may open
@@ -189,11 +204,9 @@ init_msg(JCR *jcr, MSGS *msg)
    if (msg == NULL) {
       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
       memset(daemon_msgs, 0, sizeof(MSGS));
-#ifndef HAVE_WIN32
       for (i=1; i<=M_MAX; i++) {
          add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
       }
-#endif
       Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
       return;
    }
@@ -411,16 +424,23 @@ void close_msg(JCR *jcr)
          case MD_APPEND:
             if (d->fd) {
                fclose(d->fd);            /* close open file descriptor */
+               d->fd = NULL;
             }
             break;
          case MD_MAIL:
          case MD_MAIL_ON_ERROR:
-            Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
+         case MD_MAIL_ON_SUCCESS:
+            Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
             if (!d->fd) {
                break;
             }
-            if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
-                jcr->JobStatus == JS_Terminated) {
+            if (
+                (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
+                 jcr->JobStatus == JS_Terminated) 
+                ||
+                (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
+                 jcr->JobStatus == JS_ErrorTerminated)
+                ){
                goto rem_temp_file;
             }
 
@@ -465,6 +485,7 @@ void close_msg(JCR *jcr)
 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;
@@ -542,10 +563,26 @@ void term_msg()
       fclose(trace_fd);
       trace_fd = NULL;
    }
+   if (catalog_db) {
+      free(catalog_db);
+      catalog_db = NULL;
+   }
    term_last_jobs_list();
 }
 
-
+static bool open_dest_file(JCR *jcr, DEST *d, const char *mode) 
+{
+   d->fd = fopen(d->where, mode);
+   if (!d->fd) {
+      berrno be;
+      d->fd = stdout;
+      Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
+            be.strerror());
+      d->fd = NULL;
+      return false;
+   }
+   return true;
+}
 
 /*
  * Handle sending the message to the appropriate place
@@ -558,6 +595,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
     int len, dtlen;
     MSGS *msgs;
     BPIPE *bpipe;
+    char *mode;
 
     Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
 
@@ -581,11 +619,9 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
     }
 
     if (type == M_ABORT || type == M_ERROR_TERM) {
-#ifndef HAVE_WIN32
        fputs(dt, stdout);
        fputs(msg, stdout);         /* print this here to INSURE that it is printed */
        fflush(stdout);
-#endif
     }
 
     /* Now figure out where to send the message */
@@ -599,6 +635,28 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
     for (d=msgs->dest_chain; d; d=d->next) {
        if (bit_is_set(type, d->msg_types)) {
           switch (d->dest_code) {
+             case MD_CATALOG:
+                char ed1[50];
+                if (!jcr || !jcr->db) {
+                   break;
+                }
+                if (p_sql_query && p_sql_escape) {
+                   POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
+                   POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
+                   
+                   int len = strlen(msg) + 1;
+                   esc_msg = check_pool_memory_size(esc_msg, len*2+1);
+                   p_sql_escape(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);
+                   p_sql_query(jcr, cmd);
+                   
+                   free_pool_memory(cmd);
+                   free_pool_memory(esc_msg);
+                }
+                break;
              case MD_CONSOLE:
                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
                 if (!con_fd) {
@@ -653,6 +711,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
                 break;
              case MD_MAIL:
              case MD_MAIL_ON_ERROR:
+             case MD_MAIL_ON_SUCCESS:
                 Dmsg1(850, "MAIL for following msg: %s", msg);
                 if (!d->fd) {
                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
@@ -676,37 +735,28 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
                 }
                 fputs(msg, d->fd);
                 break;
+             case MD_APPEND:
+                Dmsg1(850, "APPEND for following msg: %s", msg);
+                mode = "ab";
+                goto send_to_file;
              case MD_FILE:
                 Dmsg1(850, "FILE for following msg: %s", msg);
-                if (!d->fd) {
-                   d->fd = fopen(d->where, "w+b");
-                   if (!d->fd) {
-                      berrno be;
-                      d->fd = stdout;
-                      Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
-                            be.strerror());
-                      d->fd = NULL;
-                      break;
-                   }
+                mode = "w+b";
+send_to_file:
+                if (!d->fd && !open_dest_file(jcr, d, mode)) {
+                   break;
                 }
                 fputs(dt, d->fd);
                 fputs(msg, d->fd);
-                break;
-             case MD_APPEND:
-                Dmsg1(850, "APPEND for following msg: %s", msg);
-                if (!d->fd) {
-                   d->fd = fopen(d->where, "ab");
-                   if (!d->fd) {
-                      berrno be;
-                      d->fd = stdout;
-                      Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
-                            be.strerror());
-                      d->fd = NULL;
-                      break;
+                /* On error, we close and reopen to handle log rotation */
+                if (ferror(d->fd)) {
+                   fclose(d->fd);
+                   d->fd = NULL;
+                   if (open_dest_file(jcr, d, mode)) {
+                      fputs(dt, d->fd);
+                      fputs(msg, d->fd);
                    }
                 }
-                fputs(dt, d->fd);
-                fputs(msg, d->fd);
                 break;
              case MD_DIRECTOR:
                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
@@ -720,12 +770,14 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
                    fputs(dt, stdout);
                    fputs(msg, stdout);
+                   fflush(stdout);
                 }
                 break;
              case MD_STDERR:
                 Dmsg1(850, "STDERR for following msg: %s", msg);
                 fputs(dt, stderr);
                 fputs(msg, stderr);
+                fflush(stdout);
                 break;
              default:
                 break;
@@ -734,6 +786,30 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
     }
 }
 
+/*********************************************************************
+ *
+ *  This subroutine returns the filename portion of a Windows 
+ *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
+ *  to the full path.
+ */
+
+inline const char *
+get_basename(const char *pathname)
+{
+#if defined(_MSC_VER)
+   const char *basename;
+   
+   if ((basename = strrchr(pathname, '\\')) == NULL) {
+      basename = pathname;
+   } else {
+      basename++;
+   }
+
+   return basename;
+#else
+   return pathname;
+#endif
+}
 
 /*********************************************************************
  *
@@ -761,12 +837,7 @@ d_msg(const char *file, int line, int level, const char *fmt,...)
     if (level <= debug_level) {
 #ifdef FULL_LOCATION
        if (details) {
-          /* visual studio passes the whole path to the file as well
-           * which makes for very long lines
-           */
-          const char *f = strrchr(file, '\\');
-          if (f) file = f + 1;
-          len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
+          len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
        } else {
           len = 0;
        }
@@ -784,7 +855,7 @@ d_msg(const char *file, int line, int level, const char *fmt,...)
        if (trace) {
           if (!trace_fd) {
              char fn[200];
-             bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
+             bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
              trace_fd = fopen(fn, "a+b");
           }
           if (trace_fd) {
@@ -796,6 +867,7 @@ d_msg(const char *file, int line, int level, const char *fmt,...)
           }
        } else {   /* not tracing */
           fputs(buf, stdout);
+          fflush(stdout);
        }
     }
 }
@@ -841,7 +913,7 @@ p_msg(const char *file, int line, int level, const char *fmt,...)
 
 #ifdef FULL_LOCATION
     if (level >= 0) {
-       len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
+       len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
     } else {
        len = 0;
     }
@@ -852,6 +924,7 @@ p_msg(const char *file, int line, int level, const char *fmt,...)
     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
     va_end(arg_ptr);
     fputs(buf, stdout);
+    fflush(stdout);
 }
 
 
@@ -880,13 +953,13 @@ t_msg(const char *file, int line, int level, const char *fmt,...)
 
     if (level <= debug_level) {
        if (!trace_fd) {
-          bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
+          bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
           trace_fd = fopen(buf, "a+b");
        }
 
 #ifdef FULL_LOCATION
        if (details) {
-          len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
+          len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
        } else {
           len = 0;
        }
@@ -928,23 +1001,23 @@ e_msg(const char *file, int line, int type, int level, const char *fmt,...)
     switch (type) {
     case M_ABORT:
        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
-               my_name, file, line);
+               my_name, get_basename(file), line);
        break;
     case M_ERROR_TERM:
        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
-               my_name, file, line);
+               my_name, get_basename(file), line);
        break;
     case M_FATAL:
        if (level == -1)            /* skip details */
           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
        else
-          len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, file, line);
+          len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
        break;
     case M_ERROR:
        if (level == -1)            /* skip details */
           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
        else
-          len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, file, line);
+          len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
        break;
     case M_WARNING:
        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
@@ -1062,6 +1135,8 @@ Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
 
     if (type == M_ABORT){
        char *p = 0;
+       printf("Bacula forced SEG FAULT to obtain traceback.\n");
+       syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
        p[0] = 0;                      /* generate segmentation violation */
     }
     if (type == M_ERROR_TERM) {
@@ -1080,7 +1155,7 @@ void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const c
    POOLMEM *pool_buf;
 
    pool_buf = get_pool_memory(PM_EMSG);
-   i = Mmsg(pool_buf, "%s:%d ", file, line);
+   i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
 
    for (;;) {
       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
@@ -1107,7 +1182,7 @@ int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
    va_list   arg_ptr;
    int i, len, maxlen;
 
-   i = sprintf(*pool_buf, "%s:%d ", file, line);
+   i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
 
    for (;;) {
       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
@@ -1128,7 +1203,7 @@ int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
    va_list   arg_ptr;
    int i, len, maxlen;
 
-   i = sprintf(pool_buf, "%s:%d ", file, line);
+   i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
 
    for (;;) {
       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
@@ -1261,12 +1336,17 @@ void dequeue_messages(JCR *jcr)
 {
    MQUEUE_ITEM *item;
    P(msg_queue_mutex);
+   if (!jcr->msg_queue) {
+      goto bail_out;
+   }
    jcr->dequeuing = true;
    foreach_dlist(item, jcr->msg_queue) {
       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
    }
    jcr->msg_queue->destroy();
    jcr->dequeuing = false;
+
+bail_out:
    V(msg_queue_mutex);
 }