2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 Kern Sibbald.
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 * NOTE: don't use any Jmsg or Qmsg calls within this file,
32 * except in q_msg or j_msg (setup routines),
33 * otherwise you may get into recursive calls if there are
34 * errors, and that can lead to looping or deadlocks.
36 * Kern Sibbald, April 2000
43 sql_query p_sql_query = NULL;
44 sql_escape p_sql_escape = NULL;
46 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
49 * This is where we define "Globals" because all the
50 * daemons include this file.
52 const char *working_directory = NULL; /* working directory path stored here */
53 int verbose = 0; /* increase User messages */
54 int debug_level = 0; /* debug level */
55 bool dbg_timestamp = false; /* print timestamp in debug output */
56 bool prt_kaboom = false; /* Print kaboom output */
57 utime_t daemon_start_time = 0; /* Daemon start time */
58 const char *version = VERSION " (" BDATE ")";
59 char my_name[30]; /* daemon name is stored here */
60 char host_name[50]; /* host machine name */
61 char *exepath = (char *)NULL;
62 char *exename = (char *)NULL;
63 int console_msg_pending = false;
64 char con_fname[500]; /* Console filename */
65 FILE *con_fd = NULL; /* Console file descriptor */
66 brwlock_t con_lock; /* Console lock structure */
68 /* Forward referenced functions */
70 /* Imported functions */
71 void create_jcr_key();
75 /* Allow only one thread to tweak d->fd at a time */
76 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
77 static MSGS *daemon_msgs; /* global messages */
78 static char *catalog_db = NULL; /* database type */
79 static void (*message_callback)(int type, char *msg) = NULL;
80 static FILE *trace_fd = NULL;
81 #if defined(HAVE_WIN32)
82 static bool trace = true;
84 static bool trace = false;
88 const char *host_os = HOST_OS;
89 const char *distname = DISTNAME;
90 const char *distver = DISTVER;
93 * Handle message delivery errors
95 static void delivery_error(const char *fmt,...)
100 char dt[MAX_TIME_LENGTH];
103 pool_buf = get_pool_memory(PM_EMSG);
105 bstrftime_ny(dt, sizeof(dt), time(NULL));
110 i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
113 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
114 va_start(arg_ptr, fmt);
115 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
117 if (len < 0 || len >= (maxlen-5)) {
118 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
124 fputs(pool_buf, stdout); /* print this here to INSURE that it is printed */
126 syslog(LOG_DAEMON|LOG_ERR, pool_buf);
127 free_memory(pool_buf);
130 void register_message_callback(void msg_callback(int type, char *msg))
132 message_callback = msg_callback;
137 * Set daemon name. Also, find canonical execution
138 * path. Note, exepath has spare room for tacking on
139 * the exename so that we can reconstruct the full name.
141 * Note, this routine can get called multiple times
142 * The second time is to put the name as found in the
143 * Resource record. On the second call, generally,
144 * argv is NULL to avoid doing the path code twice.
146 void my_name_is(int argc, char *argv[], const char *name)
152 if (gethostname(host_name, sizeof(host_name)) != 0) {
153 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
155 bstrncpy(my_name, name, sizeof(my_name));
156 if (argc>0 && argv && argv[0]) {
157 /* strip trailing filename and save exepath */
158 for (l=p=argv[0]; *p; p++) {
159 if (IsPathSeparator(*p)) {
160 l = p; /* set pos of last slash */
163 if (IsPathSeparator(*l)) {
167 #if defined(HAVE_WIN32)
168 /* On Windows allow c: junk */
178 exename = (char *)malloc(len);
184 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
185 for (p=argv[0],q=exepath; p < l; ) {
189 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
190 if (getcwd(cpath, sizeof(cpath))) {
192 exepath = (char *)malloc(strlen(cpath) + 1 + len);
193 strcpy(exepath, cpath);
196 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
203 return catalog_db != NULL ? catalog_db : "unknown";
207 set_db_type(const char *name)
209 if (catalog_db != NULL) {
212 catalog_db = bstrdup(name);
216 * Initialize message handler for a daemon or a Job
217 * We make a copy of the MSGS resource passed, so it belows
218 * to the job or daemon and thus can be modified.
220 * NULL for jcr -> initialize global messages for daemon
221 * non-NULL -> initialize jcr using Message resource
224 init_msg(JCR *jcr, MSGS *msg)
226 DEST *d, *dnew, *temp_chain = NULL;
229 if (jcr == NULL && msg == NULL) {
230 init_last_jobs_list();
231 /* Create a daemon key then set invalid jcr */
232 /* Maybe we should give the daemon a jcr??? */
234 set_jcr_in_tsd(INVALID_JCR);
237 #if !defined(HAVE_WIN32)
239 * Make sure we have fd's 0, 1, 2 open
240 * If we don't do this one of our sockets may open
241 * there and if we then use stdout, it could
242 * send total garbage to our socket.
246 fd = open("/dev/null", O_RDONLY, 0644);
250 for(i=1; fd + i <= 2; i++) {
257 * If msg is NULL, initialize global chain for STDOUT and syslog
260 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
261 memset(daemon_msgs, 0, sizeof(MSGS));
262 for (i=1; i<=M_MAX; i++) {
263 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
265 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
270 * Walk down the message resource chain duplicating it
271 * for the current Job.
273 for (d=msg->dest_chain; d; d=d->next) {
274 dnew = (DEST *)malloc(sizeof(DEST));
275 memcpy(dnew, d, sizeof(DEST));
276 dnew->next = temp_chain;
278 dnew->mail_filename = NULL;
280 dnew->mail_cmd = bstrdup(d->mail_cmd);
283 dnew->where = bstrdup(d->where);
289 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
290 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
291 jcr->jcr_msgs->dest_chain = temp_chain;
292 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
294 /* If we have default values, release them now */
296 free_msgs_res(daemon_msgs);
298 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
299 memset(daemon_msgs, 0, sizeof(MSGS));
300 daemon_msgs->dest_chain = temp_chain;
301 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
303 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
307 /* Initialize so that the console (User Agent) can
308 * receive messages -- stored in a file.
310 void init_console_msg(const char *wd)
314 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
315 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
318 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
319 con_fname, be.bstrerror());
321 if (lseek(fd, 0, SEEK_END) > 0) {
322 console_msg_pending = 1;
325 con_fd = fopen(con_fname, "a+b");
328 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
329 con_fname, be.bstrerror());
331 if (rwl_init(&con_lock) != 0) {
333 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
339 * Called only during parsing of the config file.
341 * Add a message destination. I.e. associate a message type with
342 * a destination (code).
343 * Note, where in the case of dest_code FILE is a filename,
344 * but in the case of MAIL is a space separated list of
345 * email addresses, ...
347 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
351 * First search the existing chain and see if we
352 * can simply add this msg_type to an existing entry.
354 for (d=msg->dest_chain; d; d=d->next) {
355 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
356 (strcmp(where, d->where) == 0))) {
357 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
358 d, msg_type, dest_code, NPRT(where));
359 set_bit(msg_type, d->msg_types);
360 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
364 /* Not found, create a new entry */
365 d = (DEST *)malloc(sizeof(DEST));
366 memset(d, 0, sizeof(DEST));
367 d->next = msg->dest_chain;
368 d->dest_code = dest_code;
369 set_bit(msg_type, d->msg_types); /* set type bit in structure */
370 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
372 d->where = bstrdup(where);
375 d->mail_cmd = bstrdup(mail_cmd);
377 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
378 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
383 * Called only during parsing of the config file.
385 * Remove a message destination
387 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
391 for (d=msg->dest_chain; d; d=d->next) {
392 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
393 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
394 ((where == NULL && d->where == NULL) ||
395 (strcmp(where, d->where) == 0))) {
396 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
397 d, msg_type, dest_code);
398 clear_bit(msg_type, d->msg_types);
399 Dmsg0(850, "Return rem_msg_dest\n");
407 * Create a unique filename for the mail command
409 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
412 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
413 jcr->Job, (int)(intptr_t)d);
415 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
416 my_name, (int)(intptr_t)d);
418 Dmsg1(850, "mailname=%s\n", name);
424 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
429 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
431 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
435 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
436 /* If we had to use sendmail, add subject */
438 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
442 delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
443 cmd, be.bstrerror());
449 * Close the messages for this Messages resource, which means to close
450 * any open files, and dispatch any pending email messages.
452 void close_msg(JCR *jcr)
460 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
462 if (jcr == NULL) { /* NULL -> global chain */
465 msgs = jcr->jcr_msgs;
466 jcr->jcr_msgs = NULL;
472 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
473 cmd = get_pool_memory(PM_MESSAGE);
474 for (d=msgs->dest_chain; d; ) {
476 switch (d->dest_code) {
480 fclose(d->fd); /* close open file descriptor */
485 case MD_MAIL_ON_ERROR:
486 case MD_MAIL_ON_SUCCESS:
487 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
492 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
493 (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
495 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
496 jcr->JobStatus == JS_ErrorTerminated)
501 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
502 Pmsg0(000, _("open mail pipe failed.\n"));
505 Dmsg0(850, "Opened mail pipe\n");
507 line = get_memory(len);
509 while (fgets(line, len, d->fd)) {
510 fputs(line, bpipe->wfd);
512 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
514 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
518 * Since we are closing all messages, before "recursing"
519 * make sure we are not closing the daemon messages, otherwise
522 if (msgs != daemon_msgs) {
523 /* read what mail prog returned -- should be nothing */
524 while (fgets(line, len, bpipe->rfd)) {
525 delivery_error(_("Mail prog: %s"), line);
529 stat = close_bpipe(bpipe);
530 if (stat != 0 && msgs != daemon_msgs) {
533 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
534 delivery_error(_("Mail program terminated in error.\n"
536 "ERR=%s\n"), cmd, be.bstrerror());
540 /* Remove temp file */
543 unlink(d->mail_filename);
544 free_pool_memory(d->mail_filename);
545 d->mail_filename = NULL;
546 Dmsg0(850, "end mail or mail on error\n");
553 d = d->next; /* point to next buffer */
556 free_pool_memory(cmd);
557 Dmsg0(850, "Done walking message chain.\n");
562 Dmsg0(850, "===End close msg resource\n");
566 * Free memory associated with Messages resource
568 void free_msgs_res(MSGS *msgs)
572 /* Walk down the message chain releasing allocated buffers */
573 for (d=msgs->dest_chain; d; ) {
580 old = d; /* save pointer to release */
581 d = d->next; /* point to next buffer */
582 free(old); /* free the destination item */
584 msgs->dest_chain = NULL;
585 free(msgs); /* free the head */
590 * Terminate the message handler for good.
591 * Release the global destination chain.
593 * Also, clean up a few other items (cons, exepath). Note,
594 * these really should be done elsewhere.
598 Dmsg0(850, "Enter term_msg\n");
599 close_msg(NULL); /* close global chain */
600 free_msgs_res(daemon_msgs); /* free the resources */
623 term_last_jobs_list();
626 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
628 d->fd = fopen(d->where, mode);
631 delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
638 * Handle sending the message to the appropriate place
640 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
643 char dt[MAX_TIME_LENGTH];
650 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
653 * Most messages are prefixed by a date and time. If mtime is
654 * zero, then we use the current time. If mtime is 1 (special
655 * kludge), we do not prefix the date and time. Otherwise,
656 * we assume mtime is a utime_t and use it.
664 mtime = time(NULL); /* get time for SQL log */
666 bstrftime_ny(dt, sizeof(dt), mtime);
672 /* If the program registered a callback, send it there */
673 if (message_callback) {
674 message_callback(type, msg);
678 /* For serious errors make sure message is printed or logged */
679 if (type == M_ABORT || type == M_ERROR_TERM) {
683 if (type == M_ABORT) {
684 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
689 /* Now figure out where to send the message */
692 jcr = get_jcr_from_tsd();
695 msgs = jcr->jcr_msgs;
700 for (d=msgs->dest_chain; d; d=d->next) {
701 if (bit_is_set(type, d->msg_types)) {
702 switch (d->dest_code) {
705 if (!jcr || !jcr->db) {
708 if (p_sql_query && p_sql_escape) {
709 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
710 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
712 int len = strlen(msg) + 1;
713 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
714 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
716 bstrutime(dt, sizeof(dt), mtime);
717 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
718 edit_int64(jcr->JobId, ed1), dt, esc_msg);
719 p_sql_query(jcr, cmd);
721 free_pool_memory(cmd);
722 free_pool_memory(esc_msg);
726 Dmsg1(850, "CONSOLE for following msg: %s", msg);
728 con_fd = fopen(con_fname, "a+b");
729 Dmsg0(850, "Console file not open.\n");
732 Pw(con_lock); /* get write lock on console message file */
735 (void)fwrite(dt, dtlen, 1, con_fd);
739 (void)fwrite(msg, len, 1, con_fd);
740 if (msg[len-1] != '\n') {
741 (void)fwrite("\n", 2, 1, con_fd);
744 (void)fwrite("\n", 2, 1, con_fd);
747 console_msg_pending = true;
752 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
754 * We really should do an openlog() here.
756 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
759 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
760 mcmd = get_pool_memory(PM_MESSAGE);
761 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
763 fputs(dt, bpipe->wfd);
764 fputs(msg, bpipe->wfd);
765 /* Messages to the operator go one at a time */
766 stat = close_bpipe(bpipe);
770 delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
772 "ERR=%s\n"), mcmd, be.bstrerror());
775 free_pool_memory(mcmd);
778 case MD_MAIL_ON_ERROR:
779 case MD_MAIL_ON_SUCCESS:
780 Dmsg1(850, "MAIL for following msg: %s", msg);
783 POOLMEM *name = get_pool_memory(PM_MESSAGE);
784 make_unique_mail_filename(jcr, name, d);
785 d->fd = fopen(name, "w+b");
788 delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
790 free_pool_memory(name);
794 d->mail_filename = name;
797 len = strlen(msg) + dtlen;;
798 if (len > d->max_len) {
799 d->max_len = len; /* keep max line length */
805 Dmsg1(850, "APPEND for following msg: %s", msg);
809 Dmsg1(850, "FILE for following msg: %s", msg);
813 if (!d->fd && !open_dest_file(jcr, d, mode)) {
819 /* On error, we close and reopen to handle log rotation */
823 if (open_dest_file(jcr, d, mode)) {
831 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
832 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
833 jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
834 jcr->Job, type, mtime, msg);
836 Dmsg1(800, "no jcr for following msg: %s", msg);
840 Dmsg1(850, "STDOUT for following msg: %s", msg);
841 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
848 Dmsg1(850, "STDERR for following msg: %s", msg);
860 /*********************************************************************
862 * This subroutine returns the filename portion of a Windows
863 * path. It is used because Microsoft Visual Studio sets __FILE__
868 get_basename(const char *pathname)
870 #if defined(_MSC_VER)
871 const char *basename;
873 if ((basename = strrchr(pathname, '\\')) == NULL) {
886 * print or write output to trace file
888 static void pt_out(char *buf)
891 * Used the "trace on" command in the console to turn on
892 * output to the trace file. "trace off" will close the file.
897 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
898 trace_fd = fopen(fn, "a+b");
901 fputs(buf, trace_fd);
904 /* Some problem, turn off tracing */
907 } else { /* not tracing */
913 /*********************************************************************
915 * This subroutine prints a debug message if the level number
916 * is less than or equal the debug_level. File and line numbers
917 * are included for more detail if desired, but not currently
920 * If the level is negative, the details of file and line number
924 d_msg(const char *file, int line, int level, const char *fmt,...)
937 if (level <= debug_level) {
940 bstrftimes(buf, sizeof(buf), mtime);
949 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
950 my_name, get_basename(file), line, get_jobid_from_tsd());
957 va_start(arg_ptr, fmt);
958 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
966 * Set trace flag on/off. If argument is negative, there is no change
968 void set_trace(int trace_flag)
970 if (trace_flag < 0) {
972 } else if (trace_flag > 0) {
977 if (!trace && trace_fd) {
978 FILE *ltrace_fd = trace_fd;
980 bmicrosleep(0, 100000); /* yield to prevent seg faults */
990 /*********************************************************************
992 * This subroutine prints a message regardless of the debug level
994 * If the level is negative, the details of file and line number
998 p_msg(const char *file, int line, int level, const char *fmt,...)
1004 #ifdef FULL_LOCATION
1006 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1013 va_start(arg_ptr, fmt);
1014 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1021 /*********************************************************************
1023 * subroutine writes a debug message to the trace file if the level number
1024 * is less than or equal the debug_level. File and line numbers
1025 * are included for more detail if desired, but not currently
1028 * If the level is negative, the details of file and line number
1032 t_msg(const char *file, int line, int level, const char *fmt,...)
1044 if (level <= debug_level) {
1046 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1047 trace_fd = fopen(buf, "a+b");
1050 #ifdef FULL_LOCATION
1052 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1059 va_start(arg_ptr, fmt);
1060 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1062 if (trace_fd != NULL) {
1063 fputs(buf, trace_fd);
1069 /* *********************************************************
1071 * print an error message
1075 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1082 * Check if we have a message destination defined.
1083 * We always report M_ABORT and M_ERROR_TERM
1085 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1086 !bit_is_set(type, daemon_msgs->send_msg))) {
1087 return; /* no destination */
1091 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1092 my_name, get_basename(file), line);
1095 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1096 my_name, get_basename(file), line);
1099 if (level == -1) /* skip details */
1100 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1102 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1105 if (level == -1) /* skip details */
1106 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1108 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1111 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1114 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1117 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1121 va_start(arg_ptr, fmt);
1122 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1125 dispatch_message(NULL, type, 0, buf);
1127 if (type == M_ABORT) {
1129 p[0] = 0; /* generate segmentation violation */
1131 if (type == M_ERROR_TERM) {
1136 /* *********************************************************
1138 * Generate a Job message
1142 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1151 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1153 /* Special case for the console, which has a dir_bsock and JobId==0,
1154 * in that case, we send the message directly back to the
1157 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1158 BSOCK *dir = jcr->dir_bsock;
1159 va_start(arg_ptr, fmt);
1160 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1163 jcr->dir_bsock->send();
1169 jcr = get_jcr_from_tsd();
1172 msgs = jcr->jcr_msgs;
1176 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1180 * Check if we have a message destination defined.
1181 * We always report M_ABORT and M_ERROR_TERM
1183 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1184 !bit_is_set(type, msgs->send_msg)) {
1185 return; /* no destination */
1189 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1192 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1195 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1197 set_jcr_job_status(jcr, JS_FatalError);
1201 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1207 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1213 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1217 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1221 va_start(arg_ptr, fmt);
1222 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1225 dispatch_message(jcr, type, mtime, rbuf);
1227 if (type == M_ABORT){
1229 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1230 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1231 p[0] = 0; /* generate segmentation violation */
1233 if (type == M_ERROR_TERM) {
1239 * If we come here, prefix the message with the file:line-number,
1240 * then pass it on to the normal Jmsg routine.
1242 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1248 pool_buf = get_pool_memory(PM_EMSG);
1249 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1252 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1253 va_start(arg_ptr, fmt);
1254 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1256 if (len < 0 || len >= (maxlen-5)) {
1257 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1263 Jmsg(jcr, type, mtime, "%s", pool_buf);
1264 free_memory(pool_buf);
1269 * Edit a message into a Pool memory buffer, with file:lineno
1271 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1276 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1279 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1280 va_start(arg_ptr, fmt);
1281 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1283 if (len < 0 || len >= (maxlen-5)) {
1284 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1292 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1297 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1300 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1301 va_start(arg_ptr, fmt);
1302 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1304 if (len < 0 || len >= (maxlen-5)) {
1305 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1315 * Edit a message into a Pool Memory buffer NO file:lineno
1316 * Returns: string length of what was edited.
1318 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1324 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1325 va_start(arg_ptr, fmt);
1326 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1328 if (len < 0 || len >= (maxlen-5)) {
1329 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1337 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1343 maxlen = sizeof_pool_memory(pool_buf) - 1;
1344 va_start(arg_ptr, fmt);
1345 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1347 if (len < 0 || len >= (maxlen-5)) {
1348 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1356 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1362 maxlen = pool_buf.max_size() - 1;
1363 va_start(arg_ptr, fmt);
1364 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1366 if (len < 0 || len >= (maxlen-5)) {
1367 pool_buf.realloc_pm(maxlen + maxlen/2);
1377 * We queue messages rather than print them directly. This
1378 * is generally used in low level routines (msg handler, bnet)
1379 * to prevent recursion (i.e. if you are in the middle of
1380 * sending a message, it is a bit messy to recursively call
1381 * yourself when the bnet packet is not reentrant).
1383 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1390 pool_buf = get_pool_memory(PM_EMSG);
1393 maxlen = sizeof_pool_memory(pool_buf) - 1;
1394 va_start(arg_ptr, fmt);
1395 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1397 if (len < 0 || len >= (maxlen-5)) {
1398 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1403 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1405 item->mtime = time(NULL);
1406 strcpy(item->msg, pool_buf);
1408 jcr = get_jcr_from_tsd();
1410 /* If no jcr or no queue or dequeuing send to syslog */
1411 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1412 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1415 /* Queue message for later sending */
1416 P(jcr->msg_queue_mutex);
1417 jcr->msg_queue->append(item);
1418 V(jcr->msg_queue_mutex);
1420 free_memory(pool_buf);
1426 void dequeue_messages(JCR *jcr)
1429 if (!jcr->msg_queue) {
1432 P(jcr->msg_queue_mutex);
1433 jcr->dequeuing_msgs = true;
1434 foreach_dlist(item, jcr->msg_queue) {
1435 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1437 /* Remove messages just sent */
1438 jcr->msg_queue->destroy();
1439 jcr->dequeuing_msgs = false;
1440 V(jcr->msg_queue_mutex);
1445 * If we come here, prefix the message with the file:line-number,
1446 * then pass it on to the normal Qmsg routine.
1448 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1454 pool_buf = get_pool_memory(PM_EMSG);
1455 i = Mmsg(pool_buf, "%s:%d ", file, line);
1458 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1459 va_start(arg_ptr, fmt);
1460 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1462 if (len < 0 || len >= (maxlen-5)) {
1463 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1469 Qmsg(jcr, type, mtime, "%s", pool_buf);
1470 free_memory(pool_buf);