2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
29 sql_query p_sql_query = NULL;
30 sql_escape p_sql_escape = NULL;
32 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
35 * This is where we define "Globals" because all the
36 * daemons include this file.
38 const char *working_directory = NULL; /* working directory path stored here */
39 int verbose = 0; /* increase User messages */
40 int debug_level = 0; /* debug level */
41 time_t daemon_start_time = 0; /* Daemon start time */
42 const char *version = VERSION " (" BDATE ")";
43 char my_name[30]; /* daemon name is stored here */
44 char *exepath = (char *)NULL;
45 char *exename = (char *)NULL;
46 int console_msg_pending = 0;
47 char con_fname[500]; /* Console filename */
48 FILE *con_fd = NULL; /* Console file descriptor */
49 brwlock_t con_lock; /* Console lock structure */
51 static char *catalog_db = NULL; /* database type */
53 const char *host_os = HOST_OS;
54 const char *distname = DISTNAME;
55 const char *distver = DISTVER;
56 static FILE *trace_fd = NULL;
57 #if defined(HAVE_WIN32)
58 static bool trace = true;
60 static bool trace = false;
63 /* Forward referenced functions */
65 /* Imported functions */
70 /* Used to allow only one thread close the daemon messages at a time */
71 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
72 static MSGS *daemon_msgs; /* global messages */
76 * Set daemon name. Also, find canonical execution
77 * path. Note, exepath has spare room for tacking on
78 * the exename so that we can reconstruct the full name.
80 * Note, this routine can get called multiple times
81 * The second time is to put the name as found in the
82 * Resource record. On the second call, generally,
83 * argv is NULL to avoid doing the path code twice.
85 #define BTRACE_EXTRA 20
86 void my_name_is(int argc, char *argv[], const char *name)
92 bstrncpy(my_name, name, sizeof(my_name));
93 if (argc>0 && argv && argv[0]) {
94 /* strip trailing filename and save exepath */
95 for (l=p=argv[0]; *p; p++) {
97 l = p; /* set pos of last slash */
104 #if defined(HAVE_WIN32)
105 /* On Windows allow c: junk */
115 exename = (char *)malloc(len);
121 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
122 for (p=argv[0],q=exepath; p < l; ) {
126 if (strchr(exepath, '.') || exepath[0] != '/') {
127 if (getcwd(cpath, sizeof(cpath))) {
129 exepath = (char *)malloc(strlen(cpath) + 1 + len);
130 strcpy(exepath, cpath);
133 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
140 return catalog_db != NULL ? catalog_db : "unknown";
144 set_db_type(const char *name)
146 if (catalog_db != NULL)
151 catalog_db = bstrdup(name);
155 * Initialize message handler for a daemon or a Job
156 * We make a copy of the MSGS resource passed, so it belows
157 * to the job or daemon and thus can be modified.
159 * NULL for jcr -> initialize global messages for daemon
160 * non-NULL -> initialize jcr using Message resource
163 init_msg(JCR *jcr, MSGS *msg)
165 DEST *d, *dnew, *temp_chain = NULL;
168 if (jcr == NULL && msg == NULL) {
169 init_last_jobs_list();
172 #if !defined(HAVE_WIN32)
174 * Make sure we have fd's 0, 1, 2 open
175 * If we don't do this one of our sockets may open
176 * there and if we then use stdout, it could
177 * send total garbage to our socket.
181 fd = open("/dev/null", O_RDONLY, 0644);
185 for(i=1; fd + i <= 2; i++) {
192 * If msg is NULL, initialize global chain for STDOUT and syslog
195 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
196 memset(daemon_msgs, 0, sizeof(MSGS));
197 for (i=1; i<=M_MAX; i++) {
198 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
200 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
205 * Walk down the message resource chain duplicating it
206 * for the current Job.
208 for (d=msg->dest_chain; d; d=d->next) {
209 dnew = (DEST *)malloc(sizeof(DEST));
210 memcpy(dnew, d, sizeof(DEST));
211 dnew->next = temp_chain;
213 dnew->mail_filename = NULL;
215 dnew->mail_cmd = bstrdup(d->mail_cmd);
218 dnew->where = bstrdup(d->where);
224 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
225 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
226 jcr->jcr_msgs->dest_chain = temp_chain;
227 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
229 /* If we have default values, release them now */
231 free_msgs_res(daemon_msgs);
233 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
234 memset(daemon_msgs, 0, sizeof(MSGS));
235 daemon_msgs->dest_chain = temp_chain;
236 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
238 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
242 /* Initialize so that the console (User Agent) can
243 * receive messages -- stored in a file.
245 void init_console_msg(const char *wd)
249 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
250 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
253 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
254 con_fname, be.strerror());
256 if (lseek(fd, 0, SEEK_END) > 0) {
257 console_msg_pending = 1;
260 con_fd = fopen(con_fname, "a+b");
263 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
264 con_fname, be.strerror());
266 if (rwl_init(&con_lock) != 0) {
268 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
274 * Called only during parsing of the config file.
276 * Add a message destination. I.e. associate a message type with
277 * a destination (code).
278 * Note, where in the case of dest_code FILE is a filename,
279 * but in the case of MAIL is a space separated list of
280 * email addresses, ...
282 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
286 * First search the existing chain and see if we
287 * can simply add this msg_type to an existing entry.
289 for (d=msg->dest_chain; d; d=d->next) {
290 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
291 (strcmp(where, d->where) == 0))) {
292 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
293 d, msg_type, dest_code, NPRT(where));
294 set_bit(msg_type, d->msg_types);
295 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
299 /* Not found, create a new entry */
300 d = (DEST *)malloc(sizeof(DEST));
301 memset(d, 0, sizeof(DEST));
302 d->next = msg->dest_chain;
303 d->dest_code = dest_code;
304 set_bit(msg_type, d->msg_types); /* set type bit in structure */
305 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
307 d->where = bstrdup(where);
310 d->mail_cmd = bstrdup(mail_cmd);
312 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
313 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
318 * Called only during parsing of the config file.
320 * Remove a message destination
322 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
326 for (d=msg->dest_chain; d; d=d->next) {
327 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
328 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
329 ((where == NULL && d->where == NULL) ||
330 (strcmp(where, d->where) == 0))) {
331 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
332 d, msg_type, dest_code);
333 clear_bit(msg_type, d->msg_types);
334 Dmsg0(850, "Return rem_msg_dest\n");
342 * Create a unique filename for the mail command
344 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
347 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
348 jcr->Job, (int)(long)d);
350 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
351 my_name, (int)(long)d);
353 Dmsg1(850, "mailname=%s\n", name);
359 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
364 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
366 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
370 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
372 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
376 /* If we had to use sendmail, add subject */
378 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
385 * Close the messages for this Messages resource, which means to close
386 * any open files, and dispatch any pending email messages.
388 void close_msg(JCR *jcr)
396 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
398 if (jcr == NULL) { /* NULL -> global chain */
400 P(mutex); /* only one thread walking the chain */
402 msgs = jcr->jcr_msgs;
403 jcr->jcr_msgs = NULL;
408 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
409 cmd = get_pool_memory(PM_MESSAGE);
410 for (d=msgs->dest_chain; d; ) {
412 switch (d->dest_code) {
416 fclose(d->fd); /* close open file descriptor */
420 case MD_MAIL_ON_ERROR:
421 case MD_MAIL_ON_SUCCESS:
422 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
427 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
428 jcr->JobStatus == JS_Terminated)
430 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
431 jcr->JobStatus == JS_ErrorTerminated)
436 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
437 Pmsg0(000, _("open mail pipe failed.\n"));
440 Dmsg0(850, "Opened mail pipe\n");
442 line = get_memory(len);
444 while (fgets(line, len, d->fd)) {
445 fputs(line, bpipe->wfd);
447 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
449 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
453 * Since we are closing all messages, before "recursing"
454 * make sure we are not closing the daemon messages, otherwise
457 if (msgs != daemon_msgs) {
458 /* read what mail prog returned -- should be nothing */
459 while (fgets(line, len, bpipe->rfd)) {
460 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
464 stat = close_bpipe(bpipe);
465 if (stat != 0 && msgs != daemon_msgs) {
468 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
469 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
471 "ERR=%s\n"), cmd, be.strerror());
475 /* Remove temp file */
477 unlink(d->mail_filename);
478 free_pool_memory(d->mail_filename);
479 d->mail_filename = NULL;
480 Dmsg0(850, "end mail or mail on error\n");
487 d = d->next; /* point to next buffer */
489 free_pool_memory(cmd);
490 Dmsg0(850, "Done walking message chain.\n");
497 Dmsg0(850, "===End close msg resource\n");
501 * Free memory associated with Messages resource
503 void free_msgs_res(MSGS *msgs)
507 /* Walk down the message chain releasing allocated buffers */
508 for (d=msgs->dest_chain; d; ) {
515 old = d; /* save pointer to release */
516 d = d->next; /* point to next buffer */
517 free(old); /* free the destination item */
519 msgs->dest_chain = NULL;
520 free(msgs); /* free the head */
525 * Terminate the message handler for good.
526 * Release the global destination chain.
528 * Also, clean up a few other items (cons, exepath). Note,
529 * these really should be done elsewhere.
533 Dmsg0(850, "Enter term_msg\n");
534 close_msg(NULL); /* close global chain */
535 free_msgs_res(daemon_msgs); /* free the resources */
554 term_last_jobs_list();
557 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
559 d->fd = fopen(d->where, mode);
563 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
572 * Handle sending the message to the appropriate place
574 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
577 char dt[MAX_TIME_LENGTH];
584 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
587 * Most messages are prefixed by a date and time. If mtime is
588 * zero, then we use the current time. If mtime is 1 (special
589 * kludge), we do not prefix the date and time. Otherwise,
590 * we assume mtime is a time_t and use it.
599 bstrftime_ny(dt, sizeof(dt), mtime);
605 if (type == M_ABORT || type == M_ERROR_TERM) {
607 fputs(msg, stdout); /* print this here to INSURE that it is printed */
611 /* Now figure out where to send the message */
614 msgs = jcr->jcr_msgs;
619 for (d=msgs->dest_chain; d; d=d->next) {
620 if (bit_is_set(type, d->msg_types)) {
621 switch (d->dest_code) {
624 if (!jcr || !jcr->db) {
627 if (p_sql_query && p_sql_escape) {
628 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
629 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
631 int len = strlen(msg) + 1;
632 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
633 p_sql_escape(esc_msg, msg, len);
635 bstrftimes(dt, sizeof(dt), mtime);
636 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
637 edit_int64(jcr->JobId, ed1), dt, esc_msg);
638 p_sql_query(jcr, cmd);
640 free_pool_memory(cmd);
641 free_pool_memory(esc_msg);
645 Dmsg1(850, "CONSOLE for following msg: %s", msg);
647 con_fd = fopen(con_fname, "a+b");
648 Dmsg0(850, "Console file not open.\n");
651 Pw(con_lock); /* get write lock on console message file */
654 (void)fwrite(dt, dtlen, 1, con_fd);
658 (void)fwrite(msg, len, 1, con_fd);
659 if (msg[len-1] != '\n') {
660 (void)fwrite("\n", 2, 1, con_fd);
663 (void)fwrite("\n", 2, 1, con_fd);
666 console_msg_pending = TRUE;
671 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
673 * We really should do an openlog() here.
675 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
678 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
679 mcmd = get_pool_memory(PM_MESSAGE);
680 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
682 fputs(dt, bpipe->wfd);
683 fputs(msg, bpipe->wfd);
684 /* Messages to the operator go one at a time */
685 stat = close_bpipe(bpipe);
689 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
691 "ERR=%s\n"), mcmd, be.strerror());
694 free_pool_memory(mcmd);
697 case MD_MAIL_ON_ERROR:
698 case MD_MAIL_ON_SUCCESS:
699 Dmsg1(850, "MAIL for following msg: %s", msg);
701 POOLMEM *name = get_pool_memory(PM_MESSAGE);
702 make_unique_mail_filename(jcr, name, d);
703 d->fd = fopen(name, "w+b");
707 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
710 free_pool_memory(name);
713 d->mail_filename = name;
716 len = strlen(msg) + dtlen;;
717 if (len > d->max_len) {
718 d->max_len = len; /* keep max line length */
723 Dmsg1(850, "APPEND for following msg: %s", msg);
727 Dmsg1(850, "FILE for following msg: %s", msg);
730 if (!d->fd && !open_dest_file(jcr, d, mode)) {
735 /* On error, we close and reopen to handle log rotation */
738 if (open_dest_file(jcr, d, mode)) {
745 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
746 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
747 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
748 jcr->Job, type, mtime, msg);
752 Dmsg1(850, "STDOUT for following msg: %s", msg);
753 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
759 Dmsg1(850, "STDERR for following msg: %s", msg);
770 /*********************************************************************
772 * This subroutine returns the filename portion of a Windows
773 * path. It is used because Microsoft Visual Studio sets __FILE__
778 get_basename(const char *pathname)
780 #if defined(_MSC_VER)
781 const char *basename;
783 if ((basename = strrchr(pathname, '\\')) == NULL) {
795 /*********************************************************************
797 * This subroutine prints a debug message if the level number
798 * is less than or equal the debug_level. File and line numbers
799 * are included for more detail if desired, but not currently
802 * If the level is negative, the details of file and line number
806 d_msg(const char *file, int line, int level, const char *fmt,...)
818 if (level <= debug_level) {
821 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
828 va_start(arg_ptr, fmt);
829 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
833 * Used the "trace on" command in the console to turn on
834 * output to the trace file. "trace off" will close the file.
839 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
840 trace_fd = fopen(fn, "a+b");
843 fputs(buf, trace_fd);
846 /* Some problem, turn off tracing */
849 } else { /* not tracing */
856 * Set trace flag on/off. If argument is negative, there is no change
858 void set_trace(int trace_flag)
860 if (trace_flag < 0) {
862 } else if (trace_flag > 0) {
867 if (!trace && trace_fd) {
868 FILE *ltrace_fd = trace_fd;
870 bmicrosleep(0, 100000); /* yield to prevent seg faults */
880 /*********************************************************************
882 * This subroutine prints a message regardless of the debug level
884 * If the level is negative, the details of file and line number
888 p_msg(const char *file, int line, int level, const char *fmt,...)
896 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
903 va_start(arg_ptr, fmt);
904 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
910 /*********************************************************************
912 * subroutine writes a debug message to the trace file if the level number
913 * is less than or equal the debug_level. File and line numbers
914 * are included for more detail if desired, but not currently
917 * If the level is negative, the details of file and line number
921 t_msg(const char *file, int line, int level, const char *fmt,...)
933 if (level <= debug_level) {
935 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
936 trace_fd = fopen(buf, "a+b");
941 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
948 va_start(arg_ptr, fmt);
949 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
951 if (trace_fd != NULL) {
952 fputs(buf, trace_fd);
960 /* *********************************************************
962 * print an error message
966 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
973 * Check if we have a message destination defined.
974 * We always report M_ABORT and M_ERROR_TERM
976 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
977 !bit_is_set(type, daemon_msgs->send_msg))) {
978 return; /* no destination */
982 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
983 my_name, get_basename(file), line);
986 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
987 my_name, get_basename(file), line);
990 if (level == -1) /* skip details */
991 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
993 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
996 if (level == -1) /* skip details */
997 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
999 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1002 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1005 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1008 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1012 va_start(arg_ptr, fmt);
1013 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1016 dispatch_message(NULL, type, 0, buf);
1018 if (type == M_ABORT) {
1020 p[0] = 0; /* generate segmentation violation */
1022 if (type == M_ERROR_TERM) {
1027 /* *********************************************************
1029 * Generate a Job message
1033 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1042 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1044 /* Special case for the console, which has a dir_bsock and JobId==0,
1045 * in that case, we send the message directly back to the
1048 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1049 BSOCK *dir = jcr->dir_bsock;
1050 va_start(arg_ptr, fmt);
1051 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1054 bnet_send(jcr->dir_bsock);
1061 msgs = jcr->jcr_msgs;
1065 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1068 job = ""; /* Set null job name if none */
1072 * Check if we have a message destination defined.
1073 * We always report M_ABORT and M_ERROR_TERM
1075 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1076 !bit_is_set(type, msgs->send_msg)) {
1077 return; /* no destination */
1081 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1084 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1087 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1089 set_jcr_job_status(jcr, JS_FatalError);
1093 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1099 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1102 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1105 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1109 va_start(arg_ptr, fmt);
1110 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1113 dispatch_message(jcr, type, mtime, rbuf);
1115 if (type == M_ABORT){
1117 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1118 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1119 p[0] = 0; /* generate segmentation violation */
1121 if (type == M_ERROR_TERM) {
1127 * If we come here, prefix the message with the file:line-number,
1128 * then pass it on to the normal Jmsg routine.
1130 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1136 pool_buf = get_pool_memory(PM_EMSG);
1137 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1140 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1141 va_start(arg_ptr, fmt);
1142 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1144 if (len < 0 || len >= (maxlen-5)) {
1145 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1151 Jmsg(jcr, type, mtime, "%s", pool_buf);
1152 free_memory(pool_buf);
1157 * Edit a message into a Pool memory buffer, with file:lineno
1159 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1164 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1167 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1168 va_start(arg_ptr, fmt);
1169 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1171 if (len < 0 || len >= (maxlen-5)) {
1172 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1180 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1185 i = sprintf(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);
1203 * Edit a message into a Pool Memory buffer NO file:lineno
1204 * Returns: string length of what was edited.
1206 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1212 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1213 va_start(arg_ptr, fmt);
1214 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1216 if (len < 0 || len >= (maxlen-5)) {
1217 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1225 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1231 maxlen = sizeof_pool_memory(pool_buf) - 1;
1232 va_start(arg_ptr, fmt);
1233 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1235 if (len < 0 || len >= (maxlen-5)) {
1236 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1244 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1250 maxlen = pool_buf.max_size() - 1;
1251 va_start(arg_ptr, fmt);
1252 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1254 if (len < 0 || len >= (maxlen-5)) {
1255 pool_buf.realloc_pm(maxlen + maxlen/2);
1264 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1267 * We queue messages rather than print them directly. This
1268 * is generally used in low level routines (msg handler, bnet)
1269 * to prevent recursion (i.e. if you are in the middle of
1270 * sending a message, it is a bit messy to recursively call
1271 * yourself when the bnet packet is not reentrant).
1273 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1280 pool_buf = get_pool_memory(PM_EMSG);
1283 maxlen = sizeof_pool_memory(pool_buf) - 1;
1284 va_start(arg_ptr, fmt);
1285 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1287 if (len < 0 || len >= (maxlen-5)) {
1288 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1293 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1295 item->mtime = time(NULL);
1296 strcpy(item->msg, pool_buf);
1297 /* If no jcr or dequeuing send to daemon to avoid recursion */
1298 if (!jcr || jcr->dequeuing) {
1299 /* jcr==NULL => daemon message, safe to send now */
1300 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1303 /* Queue message for later sending */
1305 jcr->msg_queue->append(item);
1308 free_memory(pool_buf);
1314 void dequeue_messages(JCR *jcr)
1318 if (!jcr->msg_queue) {
1321 jcr->dequeuing = true;
1322 foreach_dlist(item, jcr->msg_queue) {
1323 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1325 jcr->msg_queue->destroy();
1326 jcr->dequeuing = false;
1334 * If we come here, prefix the message with the file:line-number,
1335 * then pass it on to the normal Qmsg routine.
1337 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1343 pool_buf = get_pool_memory(PM_EMSG);
1344 i = Mmsg(pool_buf, "%s:%d ", file, line);
1347 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1348 va_start(arg_ptr, fmt);
1349 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1351 if (len < 0 || len >= (maxlen-5)) {
1352 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1358 Qmsg(jcr, type, mtime, "%s", pool_buf);
1359 free_memory(pool_buf);