/*
- 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 */
* 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. */
static bool trace = false;
#endif
static int hangup = 0;
+static int blowup = 0;
/* Constants */
const char *host_os = HOST_OS;
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()
{
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) {
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
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"),
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:
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);
"ERR=%s\n"), cmd, be.bstrerror());
}
free_memory(line);
+
rem_temp_file:
/* Remove temp mail file */
if (d->fd) {
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());
MSGS *msgs;
BPIPE *bpipe;
const char *mode;
+ bool created_jcr = false;
Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, 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;
}
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) {
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);
}
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) {
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,
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);
}
}
}
}
+ if (created_jcr) {
+ free_jcr(jcr);
+ }
}
/*********************************************************************
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);
*
* 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;
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
*/
void set_hangup(int hangup_value)
{
- if (hangup_value < 0) {
- return;
- } else {
+ if (hangup_value != -1) {
hangup = hangup_value;
}
}
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;
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);
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
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) {
}
}
+/* 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
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);
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);
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;
}
{ 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)
{
*current_level = level;
return ret;
}
+
+int generate_daemon_event(JCR *jcr, const char *event) { return 0; }