2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
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 time_t daemon_start_time = 0; /* Daemon start time */
54 const char *version = VERSION " (" BDATE ")";
55 char my_name[30]; /* daemon name is stored here */
56 char *exepath = (char *)NULL;
57 char *exename = (char *)NULL;
58 int console_msg_pending = 0;
59 char con_fname[500]; /* Console filename */
60 FILE *con_fd = NULL; /* Console file descriptor */
61 brwlock_t con_lock; /* Console lock structure */
63 static char *catalog_db = NULL; /* database type */
65 const char *host_os = HOST_OS;
66 const char *distname = DISTNAME;
67 const char *distver = DISTVER;
68 static FILE *trace_fd = NULL;
69 #if defined(HAVE_WIN32)
70 static bool trace = true;
72 static bool trace = false;
75 /* Forward referenced functions */
77 /* Imported functions */
82 /* Used to allow only one thread close the daemon messages at a time */
83 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
84 static MSGS *daemon_msgs; /* global messages */
88 * Set daemon name. Also, find canonical execution
89 * path. Note, exepath has spare room for tacking on
90 * the exename so that we can reconstruct the full name.
92 * Note, this routine can get called multiple times
93 * The second time is to put the name as found in the
94 * Resource record. On the second call, generally,
95 * argv is NULL to avoid doing the path code twice.
97 #define BTRACE_EXTRA 20
98 void my_name_is(int argc, char *argv[], const char *name)
104 bstrncpy(my_name, name, sizeof(my_name));
105 if (argc>0 && argv && argv[0]) {
106 /* strip trailing filename and save exepath */
107 for (l=p=argv[0]; *p; p++) {
108 if (IsPathSeparator(*p)) {
109 l = p; /* set pos of last slash */
112 if (IsPathSeparator(*l)) {
116 #if defined(HAVE_WIN32)
117 /* On Windows allow c: junk */
127 exename = (char *)malloc(len);
133 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
134 for (p=argv[0],q=exepath; p < l; ) {
138 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
139 if (getcwd(cpath, sizeof(cpath))) {
141 exepath = (char *)malloc(strlen(cpath) + 1 + len);
142 strcpy(exepath, cpath);
145 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
152 return catalog_db != NULL ? catalog_db : "unknown";
156 set_db_type(const char *name)
158 if (catalog_db != NULL)
163 catalog_db = bstrdup(name);
167 * Initialize message handler for a daemon or a Job
168 * We make a copy of the MSGS resource passed, so it belows
169 * to the job or daemon and thus can be modified.
171 * NULL for jcr -> initialize global messages for daemon
172 * non-NULL -> initialize jcr using Message resource
175 init_msg(JCR *jcr, MSGS *msg)
177 DEST *d, *dnew, *temp_chain = NULL;
180 if (jcr == NULL && msg == NULL) {
181 init_last_jobs_list();
184 #if !defined(HAVE_WIN32)
186 * Make sure we have fd's 0, 1, 2 open
187 * If we don't do this one of our sockets may open
188 * there and if we then use stdout, it could
189 * send total garbage to our socket.
193 fd = open("/dev/null", O_RDONLY, 0644);
197 for(i=1; fd + i <= 2; i++) {
204 * If msg is NULL, initialize global chain for STDOUT and syslog
207 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
208 memset(daemon_msgs, 0, sizeof(MSGS));
209 for (i=1; i<=M_MAX; i++) {
210 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
212 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
217 * Walk down the message resource chain duplicating it
218 * for the current Job.
220 for (d=msg->dest_chain; d; d=d->next) {
221 dnew = (DEST *)malloc(sizeof(DEST));
222 memcpy(dnew, d, sizeof(DEST));
223 dnew->next = temp_chain;
225 dnew->mail_filename = NULL;
227 dnew->mail_cmd = bstrdup(d->mail_cmd);
230 dnew->where = bstrdup(d->where);
236 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
237 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
238 jcr->jcr_msgs->dest_chain = temp_chain;
239 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
241 /* If we have default values, release them now */
243 free_msgs_res(daemon_msgs);
245 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
246 memset(daemon_msgs, 0, sizeof(MSGS));
247 daemon_msgs->dest_chain = temp_chain;
248 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
250 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
254 /* Initialize so that the console (User Agent) can
255 * receive messages -- stored in a file.
257 void init_console_msg(const char *wd)
261 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
262 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
265 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
266 con_fname, be.strerror());
268 if (lseek(fd, 0, SEEK_END) > 0) {
269 console_msg_pending = 1;
272 con_fd = fopen(con_fname, "a+b");
275 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
276 con_fname, be.strerror());
278 if (rwl_init(&con_lock) != 0) {
280 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
286 * Called only during parsing of the config file.
288 * Add a message destination. I.e. associate a message type with
289 * a destination (code).
290 * Note, where in the case of dest_code FILE is a filename,
291 * but in the case of MAIL is a space separated list of
292 * email addresses, ...
294 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
298 * First search the existing chain and see if we
299 * can simply add this msg_type to an existing entry.
301 for (d=msg->dest_chain; d; d=d->next) {
302 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
303 (strcmp(where, d->where) == 0))) {
304 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
305 d, msg_type, dest_code, NPRT(where));
306 set_bit(msg_type, d->msg_types);
307 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
311 /* Not found, create a new entry */
312 d = (DEST *)malloc(sizeof(DEST));
313 memset(d, 0, sizeof(DEST));
314 d->next = msg->dest_chain;
315 d->dest_code = dest_code;
316 set_bit(msg_type, d->msg_types); /* set type bit in structure */
317 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
319 d->where = bstrdup(where);
322 d->mail_cmd = bstrdup(mail_cmd);
324 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
325 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
330 * Called only during parsing of the config file.
332 * Remove a message destination
334 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
338 for (d=msg->dest_chain; d; d=d->next) {
339 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
340 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
341 ((where == NULL && d->where == NULL) ||
342 (strcmp(where, d->where) == 0))) {
343 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
344 d, msg_type, dest_code);
345 clear_bit(msg_type, d->msg_types);
346 Dmsg0(850, "Return rem_msg_dest\n");
354 * Create a unique filename for the mail command
356 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
359 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
360 jcr->Job, (int)(long)d);
362 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
363 my_name, (int)(long)d);
365 Dmsg1(850, "mailname=%s\n", name);
371 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
376 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
378 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
382 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
384 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
388 /* If we had to use sendmail, add subject */
390 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
397 * Close the messages for this Messages resource, which means to close
398 * any open files, and dispatch any pending email messages.
400 void close_msg(JCR *jcr)
408 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
410 if (jcr == NULL) { /* NULL -> global chain */
412 P(mutex); /* only one thread walking the chain */
414 msgs = jcr->jcr_msgs;
415 jcr->jcr_msgs = NULL;
420 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
421 cmd = get_pool_memory(PM_MESSAGE);
422 for (d=msgs->dest_chain; d; ) {
424 switch (d->dest_code) {
428 fclose(d->fd); /* close open file descriptor */
432 case MD_MAIL_ON_ERROR:
433 case MD_MAIL_ON_SUCCESS:
434 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
439 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
440 jcr->JobStatus == JS_Terminated)
442 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
443 jcr->JobStatus == JS_ErrorTerminated)
448 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
449 Pmsg0(000, _("open mail pipe failed.\n"));
452 Dmsg0(850, "Opened mail pipe\n");
454 line = get_memory(len);
456 while (fgets(line, len, d->fd)) {
457 fputs(line, bpipe->wfd);
459 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
461 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
465 * Since we are closing all messages, before "recursing"
466 * make sure we are not closing the daemon messages, otherwise
469 if (msgs != daemon_msgs) {
470 /* read what mail prog returned -- should be nothing */
471 while (fgets(line, len, bpipe->rfd)) {
472 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
476 stat = close_bpipe(bpipe);
477 if (stat != 0 && msgs != daemon_msgs) {
480 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
481 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
483 "ERR=%s\n"), cmd, be.strerror());
487 /* Remove temp file */
489 unlink(d->mail_filename);
490 free_pool_memory(d->mail_filename);
491 d->mail_filename = NULL;
492 Dmsg0(850, "end mail or mail on error\n");
499 d = d->next; /* point to next buffer */
501 free_pool_memory(cmd);
502 Dmsg0(850, "Done walking message chain.\n");
509 Dmsg0(850, "===End close msg resource\n");
513 * Free memory associated with Messages resource
515 void free_msgs_res(MSGS *msgs)
519 /* Walk down the message chain releasing allocated buffers */
520 for (d=msgs->dest_chain; d; ) {
527 old = d; /* save pointer to release */
528 d = d->next; /* point to next buffer */
529 free(old); /* free the destination item */
531 msgs->dest_chain = NULL;
532 free(msgs); /* free the head */
537 * Terminate the message handler for good.
538 * Release the global destination chain.
540 * Also, clean up a few other items (cons, exepath). Note,
541 * these really should be done elsewhere.
545 Dmsg0(850, "Enter term_msg\n");
546 close_msg(NULL); /* close global chain */
547 free_msgs_res(daemon_msgs); /* free the resources */
566 term_last_jobs_list();
569 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
571 d->fd = fopen(d->where, mode);
575 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
584 * Handle sending the message to the appropriate place
586 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
589 char dt[MAX_TIME_LENGTH];
596 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
599 * Most messages are prefixed by a date and time. If mtime is
600 * zero, then we use the current time. If mtime is 1 (special
601 * kludge), we do not prefix the date and time. Otherwise,
602 * we assume mtime is a time_t and use it.
611 bstrftime_ny(dt, sizeof(dt), mtime);
617 if (type == M_ABORT || type == M_ERROR_TERM) {
619 fputs(msg, stdout); /* print this here to INSURE that it is printed */
623 /* Now figure out where to send the message */
626 msgs = jcr->jcr_msgs;
631 for (d=msgs->dest_chain; d; d=d->next) {
632 if (bit_is_set(type, d->msg_types)) {
633 switch (d->dest_code) {
636 if (!jcr || !jcr->db) {
639 if (p_sql_query && p_sql_escape) {
640 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
641 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
643 int len = strlen(msg) + 1;
644 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
645 p_sql_escape(esc_msg, msg, len);
647 bstrutime(dt, sizeof(dt), mtime);
648 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
649 edit_int64(jcr->JobId, ed1), dt, esc_msg);
650 p_sql_query(jcr, cmd);
652 free_pool_memory(cmd);
653 free_pool_memory(esc_msg);
657 Dmsg1(850, "CONSOLE for following msg: %s", msg);
659 con_fd = fopen(con_fname, "a+b");
660 Dmsg0(850, "Console file not open.\n");
663 Pw(con_lock); /* get write lock on console message file */
666 (void)fwrite(dt, dtlen, 1, con_fd);
670 (void)fwrite(msg, len, 1, con_fd);
671 if (msg[len-1] != '\n') {
672 (void)fwrite("\n", 2, 1, con_fd);
675 (void)fwrite("\n", 2, 1, con_fd);
678 console_msg_pending = TRUE;
683 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
685 * We really should do an openlog() here.
687 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
690 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
691 mcmd = get_pool_memory(PM_MESSAGE);
692 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
694 fputs(dt, bpipe->wfd);
695 fputs(msg, bpipe->wfd);
696 /* Messages to the operator go one at a time */
697 stat = close_bpipe(bpipe);
701 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
703 "ERR=%s\n"), mcmd, be.strerror());
706 free_pool_memory(mcmd);
709 case MD_MAIL_ON_ERROR:
710 case MD_MAIL_ON_SUCCESS:
711 Dmsg1(850, "MAIL for following msg: %s", msg);
713 POOLMEM *name = get_pool_memory(PM_MESSAGE);
714 make_unique_mail_filename(jcr, name, d);
715 d->fd = fopen(name, "w+b");
719 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
722 free_pool_memory(name);
725 d->mail_filename = name;
728 len = strlen(msg) + dtlen;;
729 if (len > d->max_len) {
730 d->max_len = len; /* keep max line length */
735 Dmsg1(850, "APPEND for following msg: %s", msg);
739 Dmsg1(850, "FILE for following msg: %s", msg);
742 if (!d->fd && !open_dest_file(jcr, d, mode)) {
747 /* On error, we close and reopen to handle log rotation */
750 if (open_dest_file(jcr, d, mode)) {
757 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
758 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
759 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
760 jcr->Job, type, mtime, msg);
764 Dmsg1(850, "STDOUT for following msg: %s", msg);
765 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
772 Dmsg1(850, "STDERR for following msg: %s", msg);
784 /*********************************************************************
786 * This subroutine returns the filename portion of a Windows
787 * path. It is used because Microsoft Visual Studio sets __FILE__
792 get_basename(const char *pathname)
794 #if defined(_MSC_VER)
795 const char *basename;
797 if ((basename = strrchr(pathname, '\\')) == NULL) {
809 /*********************************************************************
811 * This subroutine prints a debug message if the level number
812 * is less than or equal the debug_level. File and line numbers
813 * are included for more detail if desired, but not currently
816 * If the level is negative, the details of file and line number
820 d_msg(const char *file, int line, int level, const char *fmt,...)
832 if (level <= debug_level) {
835 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
842 va_start(arg_ptr, fmt);
843 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
847 * Used the "trace on" command in the console to turn on
848 * output to the trace file. "trace off" will close the file.
853 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
854 trace_fd = fopen(fn, "a+b");
857 fputs(buf, trace_fd);
860 /* Some problem, turn off tracing */
863 } else { /* not tracing */
871 * Set trace flag on/off. If argument is negative, there is no change
873 void set_trace(int trace_flag)
875 if (trace_flag < 0) {
877 } else if (trace_flag > 0) {
882 if (!trace && trace_fd) {
883 FILE *ltrace_fd = trace_fd;
885 bmicrosleep(0, 100000); /* yield to prevent seg faults */
895 /*********************************************************************
897 * This subroutine prints a message regardless of the debug level
899 * If the level is negative, the details of file and line number
903 p_msg(const char *file, int line, int level, const char *fmt,...)
911 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
918 va_start(arg_ptr, fmt);
919 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
926 /*********************************************************************
928 * subroutine writes a debug message to the trace file if the level number
929 * is less than or equal the debug_level. File and line numbers
930 * are included for more detail if desired, but not currently
933 * If the level is negative, the details of file and line number
937 t_msg(const char *file, int line, int level, const char *fmt,...)
949 if (level <= debug_level) {
951 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
952 trace_fd = fopen(buf, "a+b");
957 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
964 va_start(arg_ptr, fmt);
965 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
967 if (trace_fd != NULL) {
968 fputs(buf, trace_fd);
976 /* *********************************************************
978 * print an error message
982 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
989 * Check if we have a message destination defined.
990 * We always report M_ABORT and M_ERROR_TERM
992 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
993 !bit_is_set(type, daemon_msgs->send_msg))) {
994 return; /* no destination */
998 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
999 my_name, get_basename(file), line);
1002 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1003 my_name, get_basename(file), line);
1006 if (level == -1) /* skip details */
1007 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1009 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1012 if (level == -1) /* skip details */
1013 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1015 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1018 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1021 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1024 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1028 va_start(arg_ptr, fmt);
1029 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1032 dispatch_message(NULL, type, 0, buf);
1034 if (type == M_ABORT) {
1036 p[0] = 0; /* generate segmentation violation */
1038 if (type == M_ERROR_TERM) {
1043 /* *********************************************************
1045 * Generate a Job message
1049 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1058 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1060 /* Special case for the console, which has a dir_bsock and JobId==0,
1061 * in that case, we send the message directly back to the
1064 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1065 BSOCK *dir = jcr->dir_bsock;
1066 va_start(arg_ptr, fmt);
1067 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1070 bnet_send(jcr->dir_bsock);
1077 msgs = jcr->jcr_msgs;
1081 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1084 job = ""; /* Set null job name if none */
1088 * Check if we have a message destination defined.
1089 * We always report M_ABORT and M_ERROR_TERM
1091 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1092 !bit_is_set(type, msgs->send_msg)) {
1093 return; /* no destination */
1097 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1100 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1103 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1105 set_jcr_job_status(jcr, JS_FatalError);
1109 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1115 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1118 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1121 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1125 va_start(arg_ptr, fmt);
1126 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1129 dispatch_message(jcr, type, mtime, rbuf);
1131 if (type == M_ABORT){
1133 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1134 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1135 p[0] = 0; /* generate segmentation violation */
1137 if (type == M_ERROR_TERM) {
1143 * If we come here, prefix the message with the file:line-number,
1144 * then pass it on to the normal Jmsg routine.
1146 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1152 pool_buf = get_pool_memory(PM_EMSG);
1153 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1156 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1157 va_start(arg_ptr, fmt);
1158 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1160 if (len < 0 || len >= (maxlen-5)) {
1161 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1167 Jmsg(jcr, type, mtime, "%s", pool_buf);
1168 free_memory(pool_buf);
1173 * Edit a message into a Pool memory buffer, with file:lineno
1175 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1180 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1183 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1184 va_start(arg_ptr, fmt);
1185 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1187 if (len < 0 || len >= (maxlen-5)) {
1188 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1196 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1201 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1204 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1205 va_start(arg_ptr, fmt);
1206 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1208 if (len < 0 || len >= (maxlen-5)) {
1209 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1219 * Edit a message into a Pool Memory buffer NO file:lineno
1220 * Returns: string length of what was edited.
1222 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1228 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1229 va_start(arg_ptr, fmt);
1230 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1232 if (len < 0 || len >= (maxlen-5)) {
1233 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1241 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1247 maxlen = sizeof_pool_memory(pool_buf) - 1;
1248 va_start(arg_ptr, fmt);
1249 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1251 if (len < 0 || len >= (maxlen-5)) {
1252 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1260 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1266 maxlen = pool_buf.max_size() - 1;
1267 va_start(arg_ptr, fmt);
1268 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1270 if (len < 0 || len >= (maxlen-5)) {
1271 pool_buf.realloc_pm(maxlen + maxlen/2);
1280 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1283 * We queue messages rather than print them directly. This
1284 * is generally used in low level routines (msg handler, bnet)
1285 * to prevent recursion (i.e. if you are in the middle of
1286 * sending a message, it is a bit messy to recursively call
1287 * yourself when the bnet packet is not reentrant).
1289 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1296 pool_buf = get_pool_memory(PM_EMSG);
1299 maxlen = sizeof_pool_memory(pool_buf) - 1;
1300 va_start(arg_ptr, fmt);
1301 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1303 if (len < 0 || len >= (maxlen-5)) {
1304 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1309 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1311 item->mtime = time(NULL);
1312 strcpy(item->msg, pool_buf);
1313 /* If no jcr or dequeuing send to daemon to avoid recursion */
1314 if (!jcr || jcr->dequeuing) {
1315 /* jcr==NULL => daemon message, safe to send now */
1316 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1319 /* Queue message for later sending */
1321 jcr->msg_queue->append(item);
1324 free_memory(pool_buf);
1330 void dequeue_messages(JCR *jcr)
1334 if (!jcr->msg_queue) {
1337 jcr->dequeuing = true;
1338 foreach_dlist(item, jcr->msg_queue) {
1339 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1341 jcr->msg_queue->destroy();
1342 jcr->dequeuing = false;
1350 * If we come here, prefix the message with the file:line-number,
1351 * then pass it on to the normal Qmsg routine.
1353 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1359 pool_buf = get_pool_memory(PM_EMSG);
1360 i = Mmsg(pool_buf, "%s:%d ", file, line);
1363 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1364 va_start(arg_ptr, fmt);
1365 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1367 if (len < 0 || len >= (maxlen-5)) {
1368 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1374 Qmsg(jcr, type, mtime, "%s", pool_buf);
1375 free_memory(pool_buf);