2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula message handling routines
31 * Kern Sibbald, April 2000
41 sql_query p_sql_query = NULL;
42 sql_escape p_sql_escape = NULL;
44 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
47 * This is where we define "Globals" because all the
48 * daemons include this file.
50 const char *working_directory = NULL; /* working directory path stored here */
51 int verbose = 0; /* increase User messages */
52 int debug_level = 0; /* debug level */
53 bool dbg_timestamp = false; /* print timestamp in debug output */
54 time_t daemon_start_time = 0; /* Daemon start time */
55 const char *version = VERSION " (" BDATE ")";
56 char my_name[30]; /* daemon name is stored here */
57 char *exepath = (char *)NULL;
58 char *exename = (char *)NULL;
59 int console_msg_pending = false;
60 char con_fname[500]; /* Console filename */
61 FILE *con_fd = NULL; /* Console file descriptor */
62 brwlock_t con_lock; /* Console lock structure */
64 /* Forward referenced functions */
66 /* Imported functions */
71 /* Used to allow only one thread close the daemon messages at a time */
72 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
73 static MSGS *daemon_msgs; /* global messages */
74 static char *catalog_db = NULL; /* database type */
75 static void (*message_callback)(int type, char *msg) = NULL;
76 static FILE *trace_fd = NULL;
77 #if defined(HAVE_WIN32)
78 static bool trace = true;
80 static bool trace = false;
84 const char *host_os = HOST_OS;
85 const char *distname = DISTNAME;
86 const char *distver = DISTVER;
89 void register_message_callback(void msg_callback(int type, char *msg))
91 message_callback = msg_callback;
96 * Set daemon name. Also, find canonical execution
97 * path. Note, exepath has spare room for tacking on
98 * the exename so that we can reconstruct the full name.
100 * Note, this routine can get called multiple times
101 * The second time is to put the name as found in the
102 * Resource record. On the second call, generally,
103 * argv is NULL to avoid doing the path code twice.
105 void my_name_is(int argc, char *argv[], const char *name)
111 bstrncpy(my_name, name, sizeof(my_name));
112 if (argc>0 && argv && argv[0]) {
113 /* strip trailing filename and save exepath */
114 for (l=p=argv[0]; *p; p++) {
115 if (IsPathSeparator(*p)) {
116 l = p; /* set pos of last slash */
119 if (IsPathSeparator(*l)) {
123 #if defined(HAVE_WIN32)
124 /* On Windows allow c: junk */
134 exename = (char *)malloc(len);
140 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
141 for (p=argv[0],q=exepath; p < l; ) {
145 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
146 if (getcwd(cpath, sizeof(cpath))) {
148 exepath = (char *)malloc(strlen(cpath) + 1 + len);
149 strcpy(exepath, cpath);
152 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
159 return catalog_db != NULL ? catalog_db : "unknown";
163 set_db_type(const char *name)
165 if (catalog_db != NULL) {
168 catalog_db = bstrdup(name);
172 * Initialize message handler for a daemon or a Job
173 * We make a copy of the MSGS resource passed, so it belows
174 * to the job or daemon and thus can be modified.
176 * NULL for jcr -> initialize global messages for daemon
177 * non-NULL -> initialize jcr using Message resource
180 init_msg(JCR *jcr, MSGS *msg)
182 DEST *d, *dnew, *temp_chain = NULL;
185 if (jcr == NULL && msg == NULL) {
186 init_last_jobs_list();
189 #if !defined(HAVE_WIN32)
191 * Make sure we have fd's 0, 1, 2 open
192 * If we don't do this one of our sockets may open
193 * there and if we then use stdout, it could
194 * send total garbage to our socket.
198 fd = open("/dev/null", O_RDONLY, 0644);
202 for(i=1; fd + i <= 2; i++) {
209 * If msg is NULL, initialize global chain for STDOUT and syslog
212 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
213 memset(daemon_msgs, 0, sizeof(MSGS));
214 for (i=1; i<=M_MAX; i++) {
215 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
217 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
222 * Walk down the message resource chain duplicating it
223 * for the current Job.
225 for (d=msg->dest_chain; d; d=d->next) {
226 dnew = (DEST *)malloc(sizeof(DEST));
227 memcpy(dnew, d, sizeof(DEST));
228 dnew->next = temp_chain;
230 dnew->mail_filename = NULL;
232 dnew->mail_cmd = bstrdup(d->mail_cmd);
235 dnew->where = bstrdup(d->where);
241 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
242 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
243 jcr->jcr_msgs->dest_chain = temp_chain;
244 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
246 /* If we have default values, release them now */
248 free_msgs_res(daemon_msgs);
250 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
251 memset(daemon_msgs, 0, sizeof(MSGS));
252 daemon_msgs->dest_chain = temp_chain;
253 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
255 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
259 /* Initialize so that the console (User Agent) can
260 * receive messages -- stored in a file.
262 void init_console_msg(const char *wd)
266 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
267 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
270 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
271 con_fname, be.bstrerror());
273 if (lseek(fd, 0, SEEK_END) > 0) {
274 console_msg_pending = 1;
277 con_fd = fopen(con_fname, "a+b");
280 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
281 con_fname, be.bstrerror());
283 if (rwl_init(&con_lock) != 0) {
285 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
291 * Called only during parsing of the config file.
293 * Add a message destination. I.e. associate a message type with
294 * a destination (code).
295 * Note, where in the case of dest_code FILE is a filename,
296 * but in the case of MAIL is a space separated list of
297 * email addresses, ...
299 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
303 * First search the existing chain and see if we
304 * can simply add this msg_type to an existing entry.
306 for (d=msg->dest_chain; d; d=d->next) {
307 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
308 (strcmp(where, d->where) == 0))) {
309 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
310 d, msg_type, dest_code, NPRT(where));
311 set_bit(msg_type, d->msg_types);
312 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
316 /* Not found, create a new entry */
317 d = (DEST *)malloc(sizeof(DEST));
318 memset(d, 0, sizeof(DEST));
319 d->next = msg->dest_chain;
320 d->dest_code = dest_code;
321 set_bit(msg_type, d->msg_types); /* set type bit in structure */
322 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
324 d->where = bstrdup(where);
327 d->mail_cmd = bstrdup(mail_cmd);
329 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
330 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
335 * Called only during parsing of the config file.
337 * Remove a message destination
339 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
343 for (d=msg->dest_chain; d; d=d->next) {
344 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
345 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
346 ((where == NULL && d->where == NULL) ||
347 (strcmp(where, d->where) == 0))) {
348 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
349 d, msg_type, dest_code);
350 clear_bit(msg_type, d->msg_types);
351 Dmsg0(850, "Return rem_msg_dest\n");
359 * Create a unique filename for the mail command
361 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
364 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
365 jcr->Job, (int)(long)d);
367 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
368 my_name, (int)(long)d);
370 Dmsg1(850, "mailname=%s\n", name);
376 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
381 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
383 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
387 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
389 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
390 cmd, be.bstrerror());
393 /* If we had to use sendmail, add subject */
395 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
402 * Close the messages for this Messages resource, which means to close
403 * any open files, and dispatch any pending email messages.
405 void close_msg(JCR *jcr)
413 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
415 if (jcr == NULL) { /* NULL -> global chain */
417 P(mutex); /* only one thread walking the chain */
419 msgs = jcr->jcr_msgs;
420 jcr->jcr_msgs = NULL;
425 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
426 cmd = get_pool_memory(PM_MESSAGE);
427 for (d=msgs->dest_chain; d; ) {
429 switch (d->dest_code) {
433 fclose(d->fd); /* close open file descriptor */
438 case MD_MAIL_ON_ERROR:
439 case MD_MAIL_ON_SUCCESS:
440 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
445 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
446 jcr->JobStatus == JS_Terminated)
448 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
449 jcr->JobStatus == JS_ErrorTerminated)
454 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
455 Pmsg0(000, _("open mail pipe failed.\n"));
458 Dmsg0(850, "Opened mail pipe\n");
460 line = get_memory(len);
462 while (fgets(line, len, d->fd)) {
463 fputs(line, bpipe->wfd);
465 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
467 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
471 * Since we are closing all messages, before "recursing"
472 * make sure we are not closing the daemon messages, otherwise
475 if (msgs != daemon_msgs) {
476 /* read what mail prog returned -- should be nothing */
477 while (fgets(line, len, bpipe->rfd)) {
478 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
482 stat = close_bpipe(bpipe);
483 if (stat != 0 && msgs != daemon_msgs) {
486 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
487 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
489 "ERR=%s\n"), cmd, be.bstrerror());
493 /* Remove temp file */
496 unlink(d->mail_filename);
497 free_pool_memory(d->mail_filename);
498 d->mail_filename = NULL;
499 Dmsg0(850, "end mail or mail on error\n");
506 d = d->next; /* point to next buffer */
508 free_pool_memory(cmd);
509 Dmsg0(850, "Done walking message chain.\n");
516 Dmsg0(850, "===End close msg resource\n");
520 * Free memory associated with Messages resource
522 void free_msgs_res(MSGS *msgs)
526 /* Walk down the message chain releasing allocated buffers */
527 for (d=msgs->dest_chain; d; ) {
534 old = d; /* save pointer to release */
535 d = d->next; /* point to next buffer */
536 free(old); /* free the destination item */
538 msgs->dest_chain = NULL;
539 free(msgs); /* free the head */
544 * Terminate the message handler for good.
545 * Release the global destination chain.
547 * Also, clean up a few other items (cons, exepath). Note,
548 * these really should be done elsewhere.
552 Dmsg0(850, "Enter term_msg\n");
553 close_msg(NULL); /* close global chain */
554 free_msgs_res(daemon_msgs); /* free the resources */
577 term_last_jobs_list();
580 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
582 d->fd = fopen(d->where, mode);
586 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
594 * Handle sending the message to the appropriate place
596 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
599 char dt[MAX_TIME_LENGTH];
606 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
609 * Most messages are prefixed by a date and time. If mtime is
610 * zero, then we use the current time. If mtime is 1 (special
611 * kludge), we do not prefix the date and time. Otherwise,
612 * we assume mtime is a time_t and use it.
621 bstrftime_ny(dt, sizeof(dt), mtime);
627 /* If the program registered a callback, send it there */
628 if (message_callback) {
629 message_callback(type, msg);
633 if (type == M_ABORT || type == M_ERROR_TERM) {
635 fputs(msg, stdout); /* print this here to INSURE that it is printed */
640 /* Now figure out where to send the message */
643 jcr = get_jcr_from_tsd();
646 msgs = jcr->jcr_msgs;
651 for (d=msgs->dest_chain; d; d=d->next) {
652 if (bit_is_set(type, d->msg_types)) {
653 switch (d->dest_code) {
656 if (!jcr || !jcr->db) {
659 if (p_sql_query && p_sql_escape) {
660 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
661 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
663 int len = strlen(msg) + 1;
664 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
665 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
667 bstrutime(dt, sizeof(dt), mtime);
668 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
669 edit_int64(jcr->JobId, ed1), dt, esc_msg);
670 p_sql_query(jcr, cmd);
672 free_pool_memory(cmd);
673 free_pool_memory(esc_msg);
677 Dmsg1(850, "CONSOLE for following msg: %s", msg);
679 con_fd = fopen(con_fname, "a+b");
680 Dmsg0(850, "Console file not open.\n");
683 Pw(con_lock); /* get write lock on console message file */
686 (void)fwrite(dt, dtlen, 1, con_fd);
690 (void)fwrite(msg, len, 1, con_fd);
691 if (msg[len-1] != '\n') {
692 (void)fwrite("\n", 2, 1, con_fd);
695 (void)fwrite("\n", 2, 1, con_fd);
698 console_msg_pending = true;
703 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
705 * We really should do an openlog() here.
707 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
710 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
711 mcmd = get_pool_memory(PM_MESSAGE);
712 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
714 fputs(dt, bpipe->wfd);
715 fputs(msg, bpipe->wfd);
716 /* Messages to the operator go one at a time */
717 stat = close_bpipe(bpipe);
721 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
723 "ERR=%s\n"), mcmd, be.bstrerror());
726 free_pool_memory(mcmd);
729 case MD_MAIL_ON_ERROR:
730 case MD_MAIL_ON_SUCCESS:
731 Dmsg1(850, "MAIL for following msg: %s", msg);
733 POOLMEM *name = get_pool_memory(PM_MESSAGE);
734 make_unique_mail_filename(jcr, name, d);
735 d->fd = fopen(name, "w+b");
739 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
742 free_pool_memory(name);
745 d->mail_filename = name;
748 len = strlen(msg) + dtlen;;
749 if (len > d->max_len) {
750 d->max_len = len; /* keep max line length */
755 Dmsg1(850, "APPEND for following msg: %s", msg);
759 Dmsg1(850, "FILE for following msg: %s", msg);
762 if (!d->fd && !open_dest_file(jcr, d, mode)) {
767 /* On error, we close and reopen to handle log rotation */
771 if (open_dest_file(jcr, d, mode)) {
778 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
779 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
780 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
781 jcr->Job, type, mtime, msg);
785 Dmsg1(850, "STDOUT for following msg: %s", msg);
786 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
793 Dmsg1(850, "STDERR for following msg: %s", msg);
805 /*********************************************************************
807 * This subroutine returns the filename portion of a Windows
808 * path. It is used because Microsoft Visual Studio sets __FILE__
813 get_basename(const char *pathname)
815 #if defined(_MSC_VER)
816 const char *basename;
818 if ((basename = strrchr(pathname, '\\')) == NULL) {
830 /*********************************************************************
832 * This subroutine prints a debug message if the level number
833 * is less than or equal the debug_level. File and line numbers
834 * are included for more detail if desired, but not currently
837 * If the level is negative, the details of file and line number
841 d_msg(const char *file, int line, int level, const char *fmt,...)
854 if (level <= debug_level) {
857 bstrftimes(buf, sizeof(buf), mtime);
866 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
867 my_name, get_basename(file), line, get_jobid_from_tsd());
874 va_start(arg_ptr, fmt);
875 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
879 * Used the "trace on" command in the console to turn on
880 * output to the trace file. "trace off" will close the file.
885 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
886 trace_fd = fopen(fn, "a+b");
889 fputs(buf, trace_fd);
892 /* Some problem, turn off tracing */
895 } else { /* not tracing */
903 * Set trace flag on/off. If argument is negative, there is no change
905 void set_trace(int trace_flag)
907 if (trace_flag < 0) {
909 } else if (trace_flag > 0) {
914 if (!trace && trace_fd) {
915 FILE *ltrace_fd = trace_fd;
917 bmicrosleep(0, 100000); /* yield to prevent seg faults */
927 /*********************************************************************
929 * This subroutine prints a message regardless of the debug level
931 * If the level is negative, the details of file and line number
935 p_msg(const char *file, int line, int level, const char *fmt,...)
943 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
950 va_start(arg_ptr, fmt);
951 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
958 /*********************************************************************
960 * subroutine writes a debug message to the trace file if the level number
961 * is less than or equal the debug_level. File and line numbers
962 * are included for more detail if desired, but not currently
965 * If the level is negative, the details of file and line number
969 t_msg(const char *file, int line, int level, const char *fmt,...)
981 if (level <= debug_level) {
983 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
984 trace_fd = fopen(buf, "a+b");
989 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
996 va_start(arg_ptr, fmt);
997 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
999 if (trace_fd != NULL) {
1000 fputs(buf, trace_fd);
1008 /* *********************************************************
1010 * print an error message
1014 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1021 * Check if we have a message destination defined.
1022 * We always report M_ABORT and M_ERROR_TERM
1024 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1025 !bit_is_set(type, daemon_msgs->send_msg))) {
1026 return; /* no destination */
1030 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1031 my_name, get_basename(file), line);
1034 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1035 my_name, get_basename(file), line);
1038 if (level == -1) /* skip details */
1039 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1041 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1044 if (level == -1) /* skip details */
1045 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1047 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1050 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1053 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1056 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1060 va_start(arg_ptr, fmt);
1061 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1064 dispatch_message(NULL, type, 0, buf);
1066 if (type == M_ABORT) {
1068 p[0] = 0; /* generate segmentation violation */
1070 if (type == M_ERROR_TERM) {
1075 /* *********************************************************
1077 * Generate a Job message
1081 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1090 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1092 /* Special case for the console, which has a dir_bsock and JobId==0,
1093 * in that case, we send the message directly back to the
1096 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1097 BSOCK *dir = jcr->dir_bsock;
1098 va_start(arg_ptr, fmt);
1099 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1102 jcr->dir_bsock->send();
1108 jcr = get_jcr_from_tsd();
1111 msgs = jcr->jcr_msgs;
1115 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1119 * Check if we have a message destination defined.
1120 * We always report M_ABORT and M_ERROR_TERM
1122 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1123 !bit_is_set(type, msgs->send_msg)) {
1124 return; /* no destination */
1128 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1131 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1134 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1136 set_jcr_job_status(jcr, JS_FatalError);
1140 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1146 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1149 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1153 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1157 va_start(arg_ptr, fmt);
1158 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1161 dispatch_message(jcr, type, mtime, rbuf);
1163 if (type == M_ABORT){
1165 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1166 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1167 p[0] = 0; /* generate segmentation violation */
1169 if (type == M_ERROR_TERM) {
1175 * If we come here, prefix the message with the file:line-number,
1176 * then pass it on to the normal Jmsg routine.
1178 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1184 pool_buf = get_pool_memory(PM_EMSG);
1185 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1188 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1189 va_start(arg_ptr, fmt);
1190 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1192 if (len < 0 || len >= (maxlen-5)) {
1193 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1199 Jmsg(jcr, type, mtime, "%s", pool_buf);
1200 free_memory(pool_buf);
1205 * Edit a message into a Pool memory buffer, with file:lineno
1207 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1212 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1215 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1216 va_start(arg_ptr, fmt);
1217 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1219 if (len < 0 || len >= (maxlen-5)) {
1220 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1228 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1233 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1236 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1237 va_start(arg_ptr, fmt);
1238 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1240 if (len < 0 || len >= (maxlen-5)) {
1241 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1251 * Edit a message into a Pool Memory buffer NO file:lineno
1252 * Returns: string length of what was edited.
1254 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1260 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1261 va_start(arg_ptr, fmt);
1262 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1264 if (len < 0 || len >= (maxlen-5)) {
1265 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1273 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1279 maxlen = sizeof_pool_memory(pool_buf) - 1;
1280 va_start(arg_ptr, fmt);
1281 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1283 if (len < 0 || len >= (maxlen-5)) {
1284 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1292 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1298 maxlen = pool_buf.max_size() - 1;
1299 va_start(arg_ptr, fmt);
1300 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1302 if (len < 0 || len >= (maxlen-5)) {
1303 pool_buf.realloc_pm(maxlen + maxlen/2);
1312 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1315 * We queue messages rather than print them directly. This
1316 * is generally used in low level routines (msg handler, bnet)
1317 * to prevent recursion (i.e. if you are in the middle of
1318 * sending a message, it is a bit messy to recursively call
1319 * yourself when the bnet packet is not reentrant).
1321 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1328 pool_buf = get_pool_memory(PM_EMSG);
1331 maxlen = sizeof_pool_memory(pool_buf) - 1;
1332 va_start(arg_ptr, fmt);
1333 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1335 if (len < 0 || len >= (maxlen-5)) {
1336 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1341 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1343 item->mtime = time(NULL);
1344 strcpy(item->msg, pool_buf);
1346 jcr = get_jcr_from_tsd();
1348 /* If no jcr or dequeuing send to daemon to avoid recursion */
1349 if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) {
1350 /* jcr==NULL => daemon message, safe to send now */
1351 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1354 /* Queue message for later sending */
1356 jcr->msg_queue->append(item);
1359 free_memory(pool_buf);
1365 void dequeue_messages(JCR *jcr)
1369 if (!jcr->msg_queue) {
1372 jcr->dequeuing = true;
1373 foreach_dlist(item, jcr->msg_queue) {
1374 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1376 jcr->msg_queue->destroy();
1377 jcr->dequeuing = false;
1385 * If we come here, prefix the message with the file:line-number,
1386 * then pass it on to the normal Qmsg routine.
1388 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1394 pool_buf = get_pool_memory(PM_EMSG);
1395 i = Mmsg(pool_buf, "%s:%d ", file, line);
1398 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1399 va_start(arg_ptr, fmt);
1400 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1402 if (len < 0 || len >= (maxlen-5)) {
1403 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1409 Qmsg(jcr, type, mtime, "%s", pool_buf);
1410 free_memory(pool_buf);