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 const char *dist_name = DISTNAME " " DISTVER;
60 const int beef = BEEF;
61 char my_name[30]; /* daemon name is stored here */
62 char host_name[50]; /* host machine name */
63 char *exepath = (char *)NULL;
64 char *exename = (char *)NULL;
65 int console_msg_pending = false;
66 char con_fname[500]; /* Console filename */
67 FILE *con_fd = NULL; /* Console file descriptor */
68 brwlock_t con_lock; /* Console lock structure */
70 /* Forward referenced functions */
72 /* Imported functions */
73 void create_jcr_key();
77 /* Allow only one thread to tweak d->fd at a time */
78 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static MSGS *daemon_msgs; /* global messages */
80 static char *catalog_db = NULL; /* database type */
81 static void (*message_callback)(int type, char *msg) = NULL;
82 static FILE *trace_fd = NULL;
83 #if defined(HAVE_WIN32)
84 static bool trace = true;
86 static bool trace = false;
90 const char *host_os = HOST_OS;
91 const char *distname = DISTNAME;
92 const char *distver = DISTVER;
95 * Handle message delivery errors
97 static void delivery_error(const char *fmt,...)
102 char dt[MAX_TIME_LENGTH];
105 pool_buf = get_pool_memory(PM_EMSG);
107 bstrftime_ny(dt, sizeof(dt), time(NULL));
112 i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
115 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
116 va_start(arg_ptr, fmt);
117 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
119 if (len < 0 || len >= (maxlen-5)) {
120 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
126 fputs(pool_buf, stdout); /* print this here to INSURE that it is printed */
128 syslog(LOG_DAEMON|LOG_ERR, "%s", pool_buf);
129 free_memory(pool_buf);
132 void register_message_callback(void msg_callback(int type, char *msg))
134 message_callback = msg_callback;
139 * Set daemon name. Also, find canonical execution
140 * path. Note, exepath has spare room for tacking on
141 * the exename so that we can reconstruct the full name.
143 * Note, this routine can get called multiple times
144 * The second time is to put the name as found in the
145 * Resource record. On the second call, generally,
146 * argv is NULL to avoid doing the path code twice.
148 void my_name_is(int argc, char *argv[], const char *name)
154 if (gethostname(host_name, sizeof(host_name)) != 0) {
155 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
157 bstrncpy(my_name, name, sizeof(my_name));
158 if (argc>0 && argv && argv[0]) {
159 /* strip trailing filename and save exepath */
160 for (l=p=argv[0]; *p; p++) {
161 if (IsPathSeparator(*p)) {
162 l = p; /* set pos of last slash */
165 if (IsPathSeparator(*l)) {
169 #if defined(HAVE_WIN32)
170 /* On Windows allow c: junk */
180 exename = (char *)malloc(len);
186 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
187 for (p=argv[0],q=exepath; p < l; ) {
191 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
192 if (getcwd(cpath, sizeof(cpath))) {
194 exepath = (char *)malloc(strlen(cpath) + 1 + len);
195 strcpy(exepath, cpath);
198 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
205 return catalog_db != NULL ? catalog_db : "unknown";
209 set_db_type(const char *name)
211 if (catalog_db != NULL) {
214 catalog_db = bstrdup(name);
218 * Initialize message handler for a daemon or a Job
219 * We make a copy of the MSGS resource passed, so it belows
220 * to the job or daemon and thus can be modified.
222 * NULL for jcr -> initialize global messages for daemon
223 * non-NULL -> initialize jcr using Message resource
226 init_msg(JCR *jcr, MSGS *msg)
228 DEST *d, *dnew, *temp_chain = NULL;
231 if (jcr == NULL && msg == NULL) {
232 init_last_jobs_list();
233 /* Create a daemon key then set invalid jcr */
234 /* Maybe we should give the daemon a jcr??? */
236 set_jcr_in_tsd(INVALID_JCR);
239 #if !defined(HAVE_WIN32)
241 * Make sure we have fd's 0, 1, 2 open
242 * If we don't do this one of our sockets may open
243 * there and if we then use stdout, it could
244 * send total garbage to our socket.
248 fd = open("/dev/null", O_RDONLY, 0644);
252 for(i=1; fd + i <= 2; i++) {
259 * If msg is NULL, initialize global chain for STDOUT and syslog
262 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
263 memset(daemon_msgs, 0, sizeof(MSGS));
264 for (i=1; i<=M_MAX; i++) {
265 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
267 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
272 * Walk down the message resource chain duplicating it
273 * for the current Job.
275 for (d=msg->dest_chain; d; d=d->next) {
276 dnew = (DEST *)malloc(sizeof(DEST));
277 memcpy(dnew, d, sizeof(DEST));
278 dnew->next = temp_chain;
280 dnew->mail_filename = NULL;
282 dnew->mail_cmd = bstrdup(d->mail_cmd);
285 dnew->where = bstrdup(d->where);
291 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
292 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
293 jcr->jcr_msgs->dest_chain = temp_chain;
294 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
296 /* If we have default values, release them now */
298 free_msgs_res(daemon_msgs);
300 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
301 memset(daemon_msgs, 0, sizeof(MSGS));
302 daemon_msgs->dest_chain = temp_chain;
303 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
305 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
309 /* Initialize so that the console (User Agent) can
310 * receive messages -- stored in a file.
312 void init_console_msg(const char *wd)
316 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
317 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
320 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
321 con_fname, be.bstrerror());
323 if (lseek(fd, 0, SEEK_END) > 0) {
324 console_msg_pending = 1;
327 con_fd = fopen(con_fname, "a+b");
330 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
331 con_fname, be.bstrerror());
333 if (rwl_init(&con_lock) != 0) {
335 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
341 * Called only during parsing of the config file.
343 * Add a message destination. I.e. associate a message type with
344 * a destination (code).
345 * Note, where in the case of dest_code FILE is a filename,
346 * but in the case of MAIL is a space separated list of
347 * email addresses, ...
349 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
353 * First search the existing chain and see if we
354 * can simply add this msg_type to an existing entry.
356 for (d=msg->dest_chain; d; d=d->next) {
357 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
358 (strcmp(where, d->where) == 0))) {
359 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
360 d, msg_type, dest_code, NPRT(where));
361 set_bit(msg_type, d->msg_types);
362 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
366 /* Not found, create a new entry */
367 d = (DEST *)malloc(sizeof(DEST));
368 memset(d, 0, sizeof(DEST));
369 d->next = msg->dest_chain;
370 d->dest_code = dest_code;
371 set_bit(msg_type, d->msg_types); /* set type bit in structure */
372 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
374 d->where = bstrdup(where);
377 d->mail_cmd = bstrdup(mail_cmd);
379 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
380 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
385 * Called only during parsing of the config file.
387 * Remove a message destination
389 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
393 for (d=msg->dest_chain; d; d=d->next) {
394 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
395 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
396 ((where == NULL && d->where == NULL) ||
397 (strcmp(where, d->where) == 0))) {
398 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
399 d, msg_type, dest_code);
400 clear_bit(msg_type, d->msg_types);
401 Dmsg0(850, "Return rem_msg_dest\n");
409 * Create a unique filename for the mail command
411 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
414 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
415 jcr->Job, (int)(intptr_t)d);
417 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
418 my_name, (int)(intptr_t)d);
420 Dmsg1(850, "mailname=%s\n", name);
426 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
431 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
433 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
437 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
438 /* If we had to use sendmail, add subject */
440 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
444 delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
445 cmd, be.bstrerror());
451 * Close the messages for this Messages resource, which means to close
452 * any open files, and dispatch any pending email messages.
454 void close_msg(JCR *jcr)
462 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
464 if (jcr == NULL) { /* NULL -> global chain */
467 msgs = jcr->jcr_msgs;
468 jcr->jcr_msgs = NULL;
474 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
475 cmd = get_pool_memory(PM_MESSAGE);
476 for (d=msgs->dest_chain; d; ) {
478 switch (d->dest_code) {
482 fclose(d->fd); /* close open file descriptor */
487 case MD_MAIL_ON_ERROR:
488 case MD_MAIL_ON_SUCCESS:
489 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
494 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
495 (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
497 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
498 jcr->JobStatus == JS_ErrorTerminated)
503 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
504 Pmsg0(000, _("open mail pipe failed.\n"));
507 Dmsg0(850, "Opened mail pipe\n");
509 line = get_memory(len);
511 while (fgets(line, len, d->fd)) {
512 fputs(line, bpipe->wfd);
514 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
516 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
520 * Since we are closing all messages, before "recursing"
521 * make sure we are not closing the daemon messages, otherwise
524 if (msgs != daemon_msgs) {
525 /* read what mail prog returned -- should be nothing */
526 while (fgets(line, len, bpipe->rfd)) {
527 delivery_error(_("Mail prog: %s"), line);
531 stat = close_bpipe(bpipe);
532 if (stat != 0 && msgs != daemon_msgs) {
535 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
536 delivery_error(_("Mail program terminated in error.\n"
538 "ERR=%s\n"), cmd, be.bstrerror());
542 /* Remove temp file */
545 unlink(d->mail_filename);
546 free_pool_memory(d->mail_filename);
547 d->mail_filename = NULL;
548 Dmsg0(850, "end mail or mail on error\n");
555 d = d->next; /* point to next buffer */
558 free_pool_memory(cmd);
559 Dmsg0(850, "Done walking message chain.\n");
564 Dmsg0(850, "===End close msg resource\n");
568 * Free memory associated with Messages resource
570 void free_msgs_res(MSGS *msgs)
574 /* Walk down the message chain releasing allocated buffers */
575 for (d=msgs->dest_chain; d; ) {
582 old = d; /* save pointer to release */
583 d = d->next; /* point to next buffer */
584 free(old); /* free the destination item */
586 msgs->dest_chain = NULL;
587 free(msgs); /* free the head */
592 * Terminate the message handler for good.
593 * Release the global destination chain.
595 * Also, clean up a few other items (cons, exepath). Note,
596 * these really should be done elsewhere.
600 Dmsg0(850, "Enter term_msg\n");
601 close_msg(NULL); /* close global chain */
602 free_msgs_res(daemon_msgs); /* free the resources */
625 term_last_jobs_list();
628 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
630 d->fd = fopen(d->where, mode);
633 delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
640 * Handle sending the message to the appropriate place
642 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
645 char dt[MAX_TIME_LENGTH];
652 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
655 * Most messages are prefixed by a date and time. If mtime is
656 * zero, then we use the current time. If mtime is 1 (special
657 * kludge), we do not prefix the date and time. Otherwise,
658 * we assume mtime is a utime_t and use it.
666 mtime = time(NULL); /* get time for SQL log */
668 bstrftime_ny(dt, sizeof(dt), mtime);
674 /* If the program registered a callback, send it there */
675 if (message_callback) {
676 message_callback(type, msg);
680 /* For serious errors make sure message is printed or logged */
681 if (type == M_ABORT || type == M_ERROR_TERM) {
685 if (type == M_ABORT) {
686 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
691 /* Now figure out where to send the message */
694 jcr = get_jcr_from_tsd();
697 msgs = jcr->jcr_msgs;
702 for (d=msgs->dest_chain; d; d=d->next) {
703 if (bit_is_set(type, d->msg_types)) {
704 switch (d->dest_code) {
707 if (!jcr || !jcr->db) {
710 if (p_sql_query && p_sql_escape) {
711 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
712 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
714 int len = strlen(msg) + 1;
715 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
716 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
718 bstrutime(dt, sizeof(dt), mtime);
719 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
720 edit_int64(jcr->JobId, ed1), dt, esc_msg);
721 p_sql_query(jcr, cmd);
723 free_pool_memory(cmd);
724 free_pool_memory(esc_msg);
728 Dmsg1(850, "CONSOLE for following msg: %s", msg);
730 con_fd = fopen(con_fname, "a+b");
731 Dmsg0(850, "Console file not open.\n");
734 Pw(con_lock); /* get write lock on console message file */
737 (void)fwrite(dt, dtlen, 1, con_fd);
741 (void)fwrite(msg, len, 1, con_fd);
742 if (msg[len-1] != '\n') {
743 (void)fwrite("\n", 2, 1, con_fd);
746 (void)fwrite("\n", 2, 1, con_fd);
749 console_msg_pending = true;
754 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
756 * We really should do an openlog() here.
758 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
761 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
762 mcmd = get_pool_memory(PM_MESSAGE);
763 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
765 fputs(dt, bpipe->wfd);
766 fputs(msg, bpipe->wfd);
767 /* Messages to the operator go one at a time */
768 stat = close_bpipe(bpipe);
772 delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
774 "ERR=%s\n"), mcmd, be.bstrerror());
777 free_pool_memory(mcmd);
780 case MD_MAIL_ON_ERROR:
781 case MD_MAIL_ON_SUCCESS:
782 Dmsg1(850, "MAIL for following msg: %s", msg);
785 POOLMEM *name = get_pool_memory(PM_MESSAGE);
786 make_unique_mail_filename(jcr, name, d);
787 d->fd = fopen(name, "w+b");
790 delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
792 free_pool_memory(name);
796 d->mail_filename = name;
799 len = strlen(msg) + dtlen;;
800 if (len > d->max_len) {
801 d->max_len = len; /* keep max line length */
807 Dmsg1(850, "APPEND for following msg: %s", msg);
811 Dmsg1(850, "FILE for following msg: %s", msg);
815 if (!d->fd && !open_dest_file(jcr, d, mode)) {
821 /* On error, we close and reopen to handle log rotation */
825 if (open_dest_file(jcr, d, mode)) {
833 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
834 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
835 jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
836 jcr->Job, type, mtime, msg);
838 Dmsg1(800, "no jcr for following msg: %s", msg);
842 Dmsg1(850, "STDOUT for following msg: %s", msg);
843 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
850 Dmsg1(850, "STDERR for following msg: %s", msg);
862 /*********************************************************************
864 * This subroutine returns the filename portion of a Windows
865 * path. It is used because Microsoft Visual Studio sets __FILE__
870 get_basename(const char *pathname)
872 #if defined(_MSC_VER)
873 const char *basename;
875 if ((basename = strrchr(pathname, '\\')) == NULL) {
888 * print or write output to trace file
890 static void pt_out(char *buf)
893 * Used the "trace on" command in the console to turn on
894 * output to the trace file. "trace off" will close the file.
899 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
900 trace_fd = fopen(fn, "a+b");
903 fputs(buf, trace_fd);
906 /* Some problem, turn off tracing */
909 } else { /* not tracing */
915 /*********************************************************************
917 * This subroutine prints a debug message if the level number
918 * is less than or equal the debug_level. File and line numbers
919 * are included for more detail if desired, but not currently
922 * If the level is negative, the details of file and line number
926 d_msg(const char *file, int line, int level, const char *fmt,...)
939 if (level <= debug_level) {
942 bstrftimes(buf, sizeof(buf), mtime);
951 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
952 my_name, get_basename(file), line, get_jobid_from_tsd());
959 va_start(arg_ptr, fmt);
960 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
968 * Set trace flag on/off. If argument is negative, there is no change
970 void set_trace(int trace_flag)
972 if (trace_flag < 0) {
974 } else if (trace_flag > 0) {
979 if (!trace && trace_fd) {
980 FILE *ltrace_fd = trace_fd;
982 bmicrosleep(0, 100000); /* yield to prevent seg faults */
992 /*********************************************************************
994 * This subroutine prints a message regardless of the debug level
996 * If the level is negative, the details of file and line number
1000 p_msg(const char *file, int line, int level, const char *fmt,...)
1006 #ifdef FULL_LOCATION
1008 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1015 va_start(arg_ptr, fmt);
1016 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1023 /*********************************************************************
1025 * subroutine writes a debug message to the trace file if the level number
1026 * is less than or equal the debug_level. File and line numbers
1027 * are included for more detail if desired, but not currently
1030 * If the level is negative, the details of file and line number
1034 t_msg(const char *file, int line, int level, const char *fmt,...)
1046 if (level <= debug_level) {
1048 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1049 trace_fd = fopen(buf, "a+b");
1052 #ifdef FULL_LOCATION
1054 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1061 va_start(arg_ptr, fmt);
1062 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1064 if (trace_fd != NULL) {
1065 fputs(buf, trace_fd);
1071 /* *********************************************************
1073 * print an error message
1077 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1084 * Check if we have a message destination defined.
1085 * We always report M_ABORT and M_ERROR_TERM
1087 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1088 !bit_is_set(type, daemon_msgs->send_msg))) {
1089 return; /* no destination */
1093 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1094 my_name, get_basename(file), line);
1097 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1098 my_name, get_basename(file), line);
1101 if (level == -1) /* skip details */
1102 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1104 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1107 if (level == -1) /* skip details */
1108 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1110 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1113 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1116 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1119 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1123 va_start(arg_ptr, fmt);
1124 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1127 dispatch_message(NULL, type, 0, buf);
1129 if (type == M_ABORT) {
1131 p[0] = 0; /* generate segmentation violation */
1133 if (type == M_ERROR_TERM) {
1138 /* *********************************************************
1140 * Generate a Job message
1144 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1153 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1155 /* Special case for the console, which has a dir_bsock and JobId==0,
1156 * in that case, we send the message directly back to the
1159 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1160 BSOCK *dir = jcr->dir_bsock;
1161 va_start(arg_ptr, fmt);
1162 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1165 jcr->dir_bsock->send();
1171 jcr = get_jcr_from_tsd();
1174 msgs = jcr->jcr_msgs;
1178 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1182 * Check if we have a message destination defined.
1183 * We always report M_ABORT and M_ERROR_TERM
1185 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1186 !bit_is_set(type, msgs->send_msg)) {
1187 return; /* no destination */
1191 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1194 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1197 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1199 set_jcr_job_status(jcr, JS_FatalError);
1203 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1209 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1215 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1219 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1223 va_start(arg_ptr, fmt);
1224 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1227 dispatch_message(jcr, type, mtime, rbuf);
1229 if (type == M_ABORT){
1231 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1232 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1233 p[0] = 0; /* generate segmentation violation */
1235 if (type == M_ERROR_TERM) {
1241 * If we come here, prefix the message with the file:line-number,
1242 * then pass it on to the normal Jmsg routine.
1244 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1250 pool_buf = get_pool_memory(PM_EMSG);
1251 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1254 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1255 va_start(arg_ptr, fmt);
1256 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1258 if (len < 0 || len >= (maxlen-5)) {
1259 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1265 Jmsg(jcr, type, mtime, "%s", pool_buf);
1266 free_memory(pool_buf);
1271 * Edit a message into a Pool memory buffer, with file:lineno
1273 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1278 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1281 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1282 va_start(arg_ptr, fmt);
1283 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1285 if (len < 0 || len >= (maxlen-5)) {
1286 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1294 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1299 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1302 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1303 va_start(arg_ptr, fmt);
1304 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1306 if (len < 0 || len >= (maxlen-5)) {
1307 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1317 * Edit a message into a Pool Memory buffer NO file:lineno
1318 * Returns: string length of what was edited.
1320 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1326 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1327 va_start(arg_ptr, fmt);
1328 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1330 if (len < 0 || len >= (maxlen-5)) {
1331 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1339 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1345 maxlen = sizeof_pool_memory(pool_buf) - 1;
1346 va_start(arg_ptr, fmt);
1347 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1349 if (len < 0 || len >= (maxlen-5)) {
1350 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1358 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1364 maxlen = pool_buf.max_size() - 1;
1365 va_start(arg_ptr, fmt);
1366 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1368 if (len < 0 || len >= (maxlen-5)) {
1369 pool_buf.realloc_pm(maxlen + maxlen/2);
1379 * We queue messages rather than print them directly. This
1380 * is generally used in low level routines (msg handler, bnet)
1381 * to prevent recursion (i.e. if you are in the middle of
1382 * sending a message, it is a bit messy to recursively call
1383 * yourself when the bnet packet is not reentrant).
1385 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1392 pool_buf = get_pool_memory(PM_EMSG);
1395 maxlen = sizeof_pool_memory(pool_buf) - 1;
1396 va_start(arg_ptr, fmt);
1397 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1399 if (len < 0 || len >= (maxlen-5)) {
1400 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1405 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1407 item->mtime = time(NULL);
1408 strcpy(item->msg, pool_buf);
1410 jcr = get_jcr_from_tsd();
1412 /* If no jcr or no queue or dequeuing send to syslog */
1413 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1414 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1417 /* Queue message for later sending */
1418 P(jcr->msg_queue_mutex);
1419 jcr->msg_queue->append(item);
1420 V(jcr->msg_queue_mutex);
1422 free_memory(pool_buf);
1428 void dequeue_messages(JCR *jcr)
1431 if (!jcr->msg_queue) {
1434 P(jcr->msg_queue_mutex);
1435 jcr->dequeuing_msgs = true;
1436 foreach_dlist(item, jcr->msg_queue) {
1437 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1439 /* Remove messages just sent */
1440 jcr->msg_queue->destroy();
1441 jcr->dequeuing_msgs = false;
1442 V(jcr->msg_queue_mutex);
1447 * If we come here, prefix the message with the file:line-number,
1448 * then pass it on to the normal Qmsg routine.
1450 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1456 pool_buf = get_pool_memory(PM_EMSG);
1457 i = Mmsg(pool_buf, "%s:%d ", file, line);
1460 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1461 va_start(arg_ptr, fmt);
1462 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1464 if (len < 0 || len >= (maxlen-5)) {
1465 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1471 Qmsg(jcr, type, mtime, "%s", pool_buf);
1472 free_memory(pool_buf);