X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fmessage.c;h=2b624f823595163ccfad674c98d10a5f88d2d88f;hb=334b701e895a6ec517b26d05cf1266c25d518025;hp=6e131e55edb1d1777096c114c5d1ffa8928c80bd;hpb=d78222d489c99a79823a5c6c87a1b7d684d44435;p=bacula%2Fbacula diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c old mode 100755 new mode 100644 index 6e131e55ed..2b624f8235 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2008 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 and included + 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 * @@ -6,27 +33,13 @@ * 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" sql_query p_sql_query = NULL; +sql_escape p_sql_escape = NULL; #define FULL_LOCATION 1 /* set for file:line in Debug messages */ @@ -37,28 +50,17 @@ sql_query p_sql_query = NULL; const char *working_directory = NULL; /* working directory path stored here */ int verbose = 0; /* increase User messages */ int debug_level = 0; /* debug level */ +bool dbg_timestamp = false; /* print timestamp in debug output */ time_t daemon_start_time = 0; /* Daemon start time */ const char *version = VERSION " (" BDATE ")"; char my_name[30]; /* daemon name is stored here */ char *exepath = (char *)NULL; char *exename = (char *)NULL; -int console_msg_pending = 0; +int console_msg_pending = false; char con_fname[500]; /* Console filename */ FILE *con_fd = NULL; /* Console file descriptor */ brwlock_t con_lock; /* Console lock structure */ -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; -#if defined(HAVE_WIN32) -static bool trace = true; -#else -static bool trace = false; -#endif - /* Forward referenced functions */ /* Imported functions */ @@ -69,6 +71,25 @@ static bool trace = false; /* Used to allow only one thread close the daemon messages at a time */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static MSGS *daemon_msgs; /* global messages */ +static char *catalog_db = NULL; /* database type */ +static void (*message_callback)(int type, char *msg) = NULL; +static FILE *trace_fd = NULL; +#if defined(HAVE_WIN32) +static bool trace = true; +#else +static bool trace = false; +#endif + +/* Constants */ +const char *host_os = HOST_OS; +const char *distname = DISTNAME; +const char *distver = DISTVER; + + +void register_message_callback(void msg_callback(int type, char *msg)) +{ + message_callback = msg_callback; +} /* @@ -81,7 +102,6 @@ static MSGS *daemon_msgs; /* global messages */ * Resource record. On the second call, generally, * argv is NULL to avoid doing the path code twice. */ -#define BTRACE_EXTRA 20 void my_name_is(int argc, char *argv[], const char *name) { char *l, *p, *q; @@ -92,11 +112,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]; @@ -122,7 +142,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); @@ -142,11 +162,9 @@ get_db_type(void) void set_db_type(const char *name) { - if (catalog_db != NULL) - { + if (catalog_db != NULL) { free(catalog_db); } - catalog_db = bstrdup(name); } @@ -162,6 +180,7 @@ void init_msg(JCR *jcr, MSGS *msg) { DEST *d, *dnew, *temp_chain = NULL; + int i; if (jcr == NULL && msg == NULL) { init_last_jobs_list(); @@ -176,7 +195,6 @@ init_msg(JCR *jcr, MSGS *msg) * */ int fd; - int i; fd = open("/dev/null", O_RDONLY, 0644); if (fd > 2) { close(fd); @@ -193,11 +211,9 @@ init_msg(JCR *jcr, MSGS *msg) if (msg == NULL) { daemon_msgs = (MSGS *)malloc(sizeof(MSGS)); memset(daemon_msgs, 0, sizeof(MSGS)); -#if !defined(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; } @@ -247,12 +263,12 @@ void init_console_msg(const char *wd) { int fd; - bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name); + bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name); fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600); if (fd == -1) { berrno be; Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"), - con_fname, be.strerror()); + con_fname, be.bstrerror()); } if (lseek(fd, 0, SEEK_END) > 0) { console_msg_pending = 1; @@ -262,12 +278,12 @@ void init_console_msg(const char *wd) if (!con_fd) { berrno be; Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"), - con_fname, be.strerror()); + con_fname, be.bstrerror()); } if (rwl_init(&con_lock) != 0) { berrno be; Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"), - be.strerror()); + be.bstrerror()); } } @@ -371,7 +387,7 @@ static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d) if (!(bpipe = open_bpipe(cmd, 120, "rw"))) { berrno be; Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"), - cmd, be.strerror()); + cmd, be.bstrerror()); } /* If we had to use sendmail, add subject */ @@ -415,16 +431,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; } @@ -441,7 +464,7 @@ void close_msg(JCR *jcr) } if (!close_wpipe(bpipe)) { /* close write pipe sending mail */ berrno be; - Pmsg1(000, _("close error: ERR=%s\n"), be.strerror()); + Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror()); } /* @@ -463,12 +486,13 @@ void close_msg(JCR *jcr) Dmsg1(850, "Calling emsg. CMD=%s\n", cmd); Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n" "CMD=%s\n" - "ERR=%s\n"), cmd, be.strerror()); + "ERR=%s\n"), cmd, be.bstrerror()); } 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; @@ -546,10 +570,25 @@ 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.bstrerror()); + d->fd = NULL; + return false; + } + return true; +} /* * Handle sending the message to the appropriate place @@ -562,6 +601,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) int len, dtlen; MSGS *msgs; BPIPE *bpipe; + const char *mode; Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg); @@ -584,16 +624,24 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) dt[dtlen] = 0; } + /* If the program registered a callback, send it there */ + if (message_callback) { + message_callback(type, msg); + return; + } + if (type == M_ABORT || type == M_ERROR_TERM) { -#if !defined(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 */ msgs = NULL; + if (!jcr) { + jcr = get_jcr_from_tsd(); + } if (jcr) { msgs = jcr->jcr_msgs; } @@ -608,12 +656,21 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) if (!jcr || !jcr->db) { break; } - if (p_sql_query) { - POOL_MEM cmd(PM_MESSAGE); - bstrftimes(dt, sizeof(dt), mtime); + 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(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, msg); - p_sql_query(jcr, cmd.c_str()); + 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: @@ -638,7 +695,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) (void)fwrite("\n", 2, 1, con_fd); } fflush(con_fd); - console_msg_pending = TRUE; + console_msg_pending = true; Vw(con_lock); } break; @@ -663,13 +720,14 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) be.set_errno(stat); Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n" "CMD=%s\n" - "ERR=%s\n"), mcmd, be.strerror()); + "ERR=%s\n"), mcmd, be.bstrerror()); } } free_pool_memory(mcmd); 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); @@ -679,7 +737,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) berrno be; d->fd = stdout; Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name, - be.strerror()); + be.bstrerror()); d->fd = NULL; free_pool_memory(name); break; @@ -693,37 +751,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); @@ -737,12 +786,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; @@ -793,6 +844,7 @@ d_msg(const char *file, int line, int level, const char *fmt,...) int len; va_list arg_ptr; bool details = true; + time_t mtime; if (level < 0) { details = false; @@ -800,9 +852,19 @@ d_msg(const char *file, int line, int level, const char *fmt,...) } if (level <= debug_level) { + if (dbg_timestamp) { + mtime = time(NULL); + bstrftimes(buf, sizeof(buf), mtime); + len = strlen(buf); + buf[len++] = ' '; + buf[len] = 0; + fputs(buf, stdout); + } + #ifdef FULL_LOCATION if (details) { - len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line); + len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ", + my_name, get_basename(file), line, get_jobid_from_tsd()); } else { len = 0; } @@ -820,7 +882,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) { @@ -832,6 +894,7 @@ d_msg(const char *file, int line, int level, const char *fmt,...) } } else { /* not tracing */ fputs(buf, stdout); + fflush(stdout); } } } @@ -888,6 +951,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); } @@ -916,7 +980,7 @@ 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"); } @@ -1020,7 +1084,7 @@ Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...) va_list arg_ptr; int len; MSGS *msgs; - const char *job; + uint32_t JobId = 0; Dmsg1(850, "Enter Jmsg type=%d\n", type); @@ -1035,22 +1099,21 @@ Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...) dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg), fmt, arg_ptr); va_end(arg_ptr); - bnet_send(jcr->dir_bsock); + jcr->dir_bsock->send(); return; } msgs = NULL; - job = NULL; + if (!jcr) { + jcr = get_jcr_from_tsd(); + } if (jcr) { msgs = jcr->jcr_msgs; - job = jcr->Job; + JobId = jcr->JobId; } if (!msgs) { msgs = daemon_msgs; /* if no jcr, we use daemon handler */ } - if (!job) { - job = ""; /* Set null job name if none */ - } /* * Check if we have a message destination defined. @@ -1068,25 +1131,26 @@ Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...) len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name); break; case M_FATAL: - len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job); + len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId); if (jcr) { set_jcr_job_status(jcr, JS_FatalError); } break; case M_ERROR: - len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job); + len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId); if (jcr) { jcr->Errors++; } break; case M_WARNING: - len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job); + len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId); break; case M_SECURITY: - len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job); + len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "), + my_name, JobId); break; default: - len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name); + len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId); break; } @@ -1098,6 +1162,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) { @@ -1276,10 +1342,13 @@ void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...) item->type = type; item->mtime = time(NULL); strcpy(item->msg, pool_buf); + if (!jcr) { + jcr = get_jcr_from_tsd(); + } /* If no jcr or dequeuing send to daemon to avoid recursion */ - if (!jcr || jcr->dequeuing) { + if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) { /* jcr==NULL => daemon message, safe to send now */ - Jmsg(NULL, item->type, item->mtime, "%s", item->msg); + Jmsg(jcr, item->type, item->mtime, "%s", item->msg); free(item); } else { /* Queue message for later sending */