2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2007 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.
37 * Bacula message handling routines
39 * Kern Sibbald, April 2000
49 sql_query p_sql_query = NULL;
50 sql_escape p_sql_escape = NULL;
52 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
55 * This is where we define "Globals" because all the
56 * daemons include this file.
58 const char *working_directory = NULL; /* working directory path stored here */
59 int verbose = 0; /* increase User messages */
60 int debug_level = 0; /* debug level */
61 time_t daemon_start_time = 0; /* Daemon start time */
62 const char *version = VERSION " (" BDATE ")";
63 char my_name[30]; /* daemon name is stored here */
64 char *exepath = (char *)NULL;
65 char *exename = (char *)NULL;
66 int console_msg_pending = 0;
67 char con_fname[500]; /* Console filename */
68 FILE *con_fd = NULL; /* Console file descriptor */
69 brwlock_t con_lock; /* Console lock structure */
71 static char *catalog_db = NULL; /* database type */
73 const char *host_os = HOST_OS;
74 const char *distname = DISTNAME;
75 const char *distver = DISTVER;
76 static FILE *trace_fd = NULL;
77 #if defined(HAVE_WIN32)
78 static bool trace = true;
80 static bool trace = false;
83 /* Forward referenced functions */
85 /* Imported functions */
90 /* Used to allow only one thread close the daemon messages at a time */
91 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
92 static MSGS *daemon_msgs; /* global messages */
96 * Set daemon name. Also, find canonical execution
97 * path. Note, exepath has spare room for tacking on
98 * the exename so that we can reconstruct the full name.
100 * Note, this routine can get called multiple times
101 * The second time is to put the name as found in the
102 * Resource record. On the second call, generally,
103 * argv is NULL to avoid doing the path code twice.
105 #define BTRACE_EXTRA 20
106 void my_name_is(int argc, char *argv[], const char *name)
112 bstrncpy(my_name, name, sizeof(my_name));
113 if (argc>0 && argv && argv[0]) {
114 /* strip trailing filename and save exepath */
115 for (l=p=argv[0]; *p; p++) {
116 if (IsPathSeparator(*p)) {
117 l = p; /* set pos of last slash */
120 if (IsPathSeparator(*l)) {
124 #if defined(HAVE_WIN32)
125 /* On Windows allow c: junk */
135 exename = (char *)malloc(len);
141 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
142 for (p=argv[0],q=exepath; p < l; ) {
146 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
147 if (getcwd(cpath, sizeof(cpath))) {
149 exepath = (char *)malloc(strlen(cpath) + 1 + len);
150 strcpy(exepath, cpath);
153 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
160 return catalog_db != NULL ? catalog_db : "unknown";
164 set_db_type(const char *name)
166 if (catalog_db != NULL)
171 catalog_db = bstrdup(name);
175 * Initialize message handler for a daemon or a Job
176 * We make a copy of the MSGS resource passed, so it belows
177 * to the job or daemon and thus can be modified.
179 * NULL for jcr -> initialize global messages for daemon
180 * non-NULL -> initialize jcr using Message resource
183 init_msg(JCR *jcr, MSGS *msg)
185 DEST *d, *dnew, *temp_chain = NULL;
188 if (jcr == NULL && msg == NULL) {
189 init_last_jobs_list();
192 #if !defined(HAVE_WIN32)
194 * Make sure we have fd's 0, 1, 2 open
195 * If we don't do this one of our sockets may open
196 * there and if we then use stdout, it could
197 * send total garbage to our socket.
201 fd = open("/dev/null", O_RDONLY, 0644);
205 for(i=1; fd + i <= 2; i++) {
212 * If msg is NULL, initialize global chain for STDOUT and syslog
215 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
216 memset(daemon_msgs, 0, sizeof(MSGS));
217 for (i=1; i<=M_MAX; i++) {
218 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
220 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
225 * Walk down the message resource chain duplicating it
226 * for the current Job.
228 for (d=msg->dest_chain; d; d=d->next) {
229 dnew = (DEST *)malloc(sizeof(DEST));
230 memcpy(dnew, d, sizeof(DEST));
231 dnew->next = temp_chain;
233 dnew->mail_filename = NULL;
235 dnew->mail_cmd = bstrdup(d->mail_cmd);
238 dnew->where = bstrdup(d->where);
244 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
245 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
246 jcr->jcr_msgs->dest_chain = temp_chain;
247 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
249 /* If we have default values, release them now */
251 free_msgs_res(daemon_msgs);
253 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
254 memset(daemon_msgs, 0, sizeof(MSGS));
255 daemon_msgs->dest_chain = temp_chain;
256 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
258 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
262 /* Initialize so that the console (User Agent) can
263 * receive messages -- stored in a file.
265 void init_console_msg(const char *wd)
269 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
270 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
273 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
274 con_fname, be.strerror());
276 if (lseek(fd, 0, SEEK_END) > 0) {
277 console_msg_pending = 1;
280 con_fd = fopen(con_fname, "a+b");
283 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
284 con_fname, be.strerror());
286 if (rwl_init(&con_lock) != 0) {
288 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
294 * Called only during parsing of the config file.
296 * Add a message destination. I.e. associate a message type with
297 * a destination (code).
298 * Note, where in the case of dest_code FILE is a filename,
299 * but in the case of MAIL is a space separated list of
300 * email addresses, ...
302 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
306 * First search the existing chain and see if we
307 * can simply add this msg_type to an existing entry.
309 for (d=msg->dest_chain; d; d=d->next) {
310 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
311 (strcmp(where, d->where) == 0))) {
312 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
313 d, msg_type, dest_code, NPRT(where));
314 set_bit(msg_type, d->msg_types);
315 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
319 /* Not found, create a new entry */
320 d = (DEST *)malloc(sizeof(DEST));
321 memset(d, 0, sizeof(DEST));
322 d->next = msg->dest_chain;
323 d->dest_code = dest_code;
324 set_bit(msg_type, d->msg_types); /* set type bit in structure */
325 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
327 d->where = bstrdup(where);
330 d->mail_cmd = bstrdup(mail_cmd);
332 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
333 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
338 * Called only during parsing of the config file.
340 * Remove a message destination
342 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
346 for (d=msg->dest_chain; d; d=d->next) {
347 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
348 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
349 ((where == NULL && d->where == NULL) ||
350 (strcmp(where, d->where) == 0))) {
351 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
352 d, msg_type, dest_code);
353 clear_bit(msg_type, d->msg_types);
354 Dmsg0(850, "Return rem_msg_dest\n");
362 * Create a unique filename for the mail command
364 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
367 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
368 jcr->Job, (int)(long)d);
370 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
371 my_name, (int)(long)d);
373 Dmsg1(850, "mailname=%s\n", name);
379 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
384 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
386 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
390 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
392 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
396 /* If we had to use sendmail, add subject */
398 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
405 * Close the messages for this Messages resource, which means to close
406 * any open files, and dispatch any pending email messages.
408 void close_msg(JCR *jcr)
416 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
418 if (jcr == NULL) { /* NULL -> global chain */
420 P(mutex); /* only one thread walking the chain */
422 msgs = jcr->jcr_msgs;
423 jcr->jcr_msgs = NULL;
428 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
429 cmd = get_pool_memory(PM_MESSAGE);
430 for (d=msgs->dest_chain; d; ) {
432 switch (d->dest_code) {
436 fclose(d->fd); /* close open file descriptor */
441 case MD_MAIL_ON_ERROR:
442 case MD_MAIL_ON_SUCCESS:
443 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
448 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
449 jcr->JobStatus == JS_Terminated)
451 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
452 jcr->JobStatus == JS_ErrorTerminated)
457 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
458 Pmsg0(000, _("open mail pipe failed.\n"));
461 Dmsg0(850, "Opened mail pipe\n");
463 line = get_memory(len);
465 while (fgets(line, len, d->fd)) {
466 fputs(line, bpipe->wfd);
468 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
470 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
474 * Since we are closing all messages, before "recursing"
475 * make sure we are not closing the daemon messages, otherwise
478 if (msgs != daemon_msgs) {
479 /* read what mail prog returned -- should be nothing */
480 while (fgets(line, len, bpipe->rfd)) {
481 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
485 stat = close_bpipe(bpipe);
486 if (stat != 0 && msgs != daemon_msgs) {
489 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
490 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
492 "ERR=%s\n"), cmd, be.strerror());
496 /* Remove temp file */
499 unlink(d->mail_filename);
500 free_pool_memory(d->mail_filename);
501 d->mail_filename = NULL;
502 Dmsg0(850, "end mail or mail on error\n");
509 d = d->next; /* point to next buffer */
511 free_pool_memory(cmd);
512 Dmsg0(850, "Done walking message chain.\n");
519 Dmsg0(850, "===End close msg resource\n");
523 * Free memory associated with Messages resource
525 void free_msgs_res(MSGS *msgs)
529 /* Walk down the message chain releasing allocated buffers */
530 for (d=msgs->dest_chain; d; ) {
537 old = d; /* save pointer to release */
538 d = d->next; /* point to next buffer */
539 free(old); /* free the destination item */
541 msgs->dest_chain = NULL;
542 free(msgs); /* free the head */
547 * Terminate the message handler for good.
548 * Release the global destination chain.
550 * Also, clean up a few other items (cons, exepath). Note,
551 * these really should be done elsewhere.
555 Dmsg0(850, "Enter term_msg\n");
556 close_msg(NULL); /* close global chain */
557 free_msgs_res(daemon_msgs); /* free the resources */
576 term_last_jobs_list();
579 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
581 d->fd = fopen(d->where, mode);
585 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
594 * Handle sending the message to the appropriate place
596 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
599 char dt[MAX_TIME_LENGTH];
606 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
609 * Most messages are prefixed by a date and time. If mtime is
610 * zero, then we use the current time. If mtime is 1 (special
611 * kludge), we do not prefix the date and time. Otherwise,
612 * we assume mtime is a time_t and use it.
621 bstrftime_ny(dt, sizeof(dt), mtime);
627 if (type == M_ABORT || type == M_ERROR_TERM) {
629 fputs(msg, stdout); /* print this here to INSURE that it is printed */
633 /* Now figure out where to send the message */
636 msgs = jcr->jcr_msgs;
641 for (d=msgs->dest_chain; d; d=d->next) {
642 if (bit_is_set(type, d->msg_types)) {
643 switch (d->dest_code) {
646 if (!jcr || !jcr->db) {
649 if (p_sql_query && p_sql_escape) {
650 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
651 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
653 int len = strlen(msg) + 1;
654 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
655 p_sql_escape(esc_msg, msg, len);
657 bstrutime(dt, sizeof(dt), mtime);
658 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
659 edit_int64(jcr->JobId, ed1), dt, esc_msg);
660 p_sql_query(jcr, cmd);
662 free_pool_memory(cmd);
663 free_pool_memory(esc_msg);
667 Dmsg1(850, "CONSOLE for following msg: %s", msg);
669 con_fd = fopen(con_fname, "a+b");
670 Dmsg0(850, "Console file not open.\n");
673 Pw(con_lock); /* get write lock on console message file */
676 (void)fwrite(dt, dtlen, 1, con_fd);
680 (void)fwrite(msg, len, 1, con_fd);
681 if (msg[len-1] != '\n') {
682 (void)fwrite("\n", 2, 1, con_fd);
685 (void)fwrite("\n", 2, 1, con_fd);
688 console_msg_pending = TRUE;
693 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
695 * We really should do an openlog() here.
697 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
700 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
701 mcmd = get_pool_memory(PM_MESSAGE);
702 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
704 fputs(dt, bpipe->wfd);
705 fputs(msg, bpipe->wfd);
706 /* Messages to the operator go one at a time */
707 stat = close_bpipe(bpipe);
711 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
713 "ERR=%s\n"), mcmd, be.strerror());
716 free_pool_memory(mcmd);
719 case MD_MAIL_ON_ERROR:
720 case MD_MAIL_ON_SUCCESS:
721 Dmsg1(850, "MAIL for following msg: %s", msg);
723 POOLMEM *name = get_pool_memory(PM_MESSAGE);
724 make_unique_mail_filename(jcr, name, d);
725 d->fd = fopen(name, "w+b");
729 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
732 free_pool_memory(name);
735 d->mail_filename = name;
738 len = strlen(msg) + dtlen;;
739 if (len > d->max_len) {
740 d->max_len = len; /* keep max line length */
745 Dmsg1(850, "APPEND for following msg: %s", msg);
749 Dmsg1(850, "FILE for following msg: %s", msg);
752 if (!d->fd && !open_dest_file(jcr, d, mode)) {
757 /* On error, we close and reopen to handle log rotation */
761 if (open_dest_file(jcr, d, mode)) {
768 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
769 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
770 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
771 jcr->Job, type, mtime, msg);
775 Dmsg1(850, "STDOUT for following msg: %s", msg);
776 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
783 Dmsg1(850, "STDERR for following msg: %s", msg);
795 /*********************************************************************
797 * This subroutine returns the filename portion of a Windows
798 * path. It is used because Microsoft Visual Studio sets __FILE__
803 get_basename(const char *pathname)
805 #if defined(_MSC_VER)
806 const char *basename;
808 if ((basename = strrchr(pathname, '\\')) == NULL) {
820 /*********************************************************************
822 * This subroutine prints a debug message if the level number
823 * is less than or equal the debug_level. File and line numbers
824 * are included for more detail if desired, but not currently
827 * If the level is negative, the details of file and line number
831 d_msg(const char *file, int line, int level, const char *fmt,...)
843 if (level <= debug_level) {
846 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
853 va_start(arg_ptr, fmt);
854 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
858 * Used the "trace on" command in the console to turn on
859 * output to the trace file. "trace off" will close the file.
864 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
865 trace_fd = fopen(fn, "a+b");
868 fputs(buf, trace_fd);
871 /* Some problem, turn off tracing */
874 } else { /* not tracing */
882 * Set trace flag on/off. If argument is negative, there is no change
884 void set_trace(int trace_flag)
886 if (trace_flag < 0) {
888 } else if (trace_flag > 0) {
893 if (!trace && trace_fd) {
894 FILE *ltrace_fd = trace_fd;
896 bmicrosleep(0, 100000); /* yield to prevent seg faults */
906 /*********************************************************************
908 * This subroutine prints a message regardless of the debug level
910 * If the level is negative, the details of file and line number
914 p_msg(const char *file, int line, int level, const char *fmt,...)
922 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
929 va_start(arg_ptr, fmt);
930 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
937 /*********************************************************************
939 * subroutine writes a debug message to the trace file if the level number
940 * is less than or equal the debug_level. File and line numbers
941 * are included for more detail if desired, but not currently
944 * If the level is negative, the details of file and line number
948 t_msg(const char *file, int line, int level, const char *fmt,...)
960 if (level <= debug_level) {
962 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
963 trace_fd = fopen(buf, "a+b");
968 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
975 va_start(arg_ptr, fmt);
976 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
978 if (trace_fd != NULL) {
979 fputs(buf, trace_fd);
987 /* *********************************************************
989 * print an error message
993 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1000 * Check if we have a message destination defined.
1001 * We always report M_ABORT and M_ERROR_TERM
1003 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1004 !bit_is_set(type, daemon_msgs->send_msg))) {
1005 return; /* no destination */
1009 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1010 my_name, get_basename(file), line);
1013 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1014 my_name, get_basename(file), line);
1017 if (level == -1) /* skip details */
1018 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1020 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1023 if (level == -1) /* skip details */
1024 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1026 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1029 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1032 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1035 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1039 va_start(arg_ptr, fmt);
1040 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1043 dispatch_message(NULL, type, 0, buf);
1045 if (type == M_ABORT) {
1047 p[0] = 0; /* generate segmentation violation */
1049 if (type == M_ERROR_TERM) {
1054 /* *********************************************************
1056 * Generate a Job message
1060 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1069 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1071 /* Special case for the console, which has a dir_bsock and JobId==0,
1072 * in that case, we send the message directly back to the
1075 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1076 BSOCK *dir = jcr->dir_bsock;
1077 va_start(arg_ptr, fmt);
1078 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1081 bnet_send(jcr->dir_bsock);
1088 msgs = jcr->jcr_msgs;
1092 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1095 job = ""; /* Set null job name if none */
1099 * Check if we have a message destination defined.
1100 * We always report M_ABORT and M_ERROR_TERM
1102 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1103 !bit_is_set(type, msgs->send_msg)) {
1104 return; /* no destination */
1108 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1111 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1114 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1116 set_jcr_job_status(jcr, JS_FatalError);
1120 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1126 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1129 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1132 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1136 va_start(arg_ptr, fmt);
1137 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1140 dispatch_message(jcr, type, mtime, rbuf);
1142 if (type == M_ABORT){
1144 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1145 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1146 p[0] = 0; /* generate segmentation violation */
1148 if (type == M_ERROR_TERM) {
1154 * If we come here, prefix the message with the file:line-number,
1155 * then pass it on to the normal Jmsg routine.
1157 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1163 pool_buf = get_pool_memory(PM_EMSG);
1164 i = Mmsg(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);
1178 Jmsg(jcr, type, mtime, "%s", pool_buf);
1179 free_memory(pool_buf);
1184 * Edit a message into a Pool memory buffer, with file:lineno
1186 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1191 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1194 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1195 va_start(arg_ptr, fmt);
1196 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1198 if (len < 0 || len >= (maxlen-5)) {
1199 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1207 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1212 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1215 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1216 va_start(arg_ptr, fmt);
1217 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1219 if (len < 0 || len >= (maxlen-5)) {
1220 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1230 * Edit a message into a Pool Memory buffer NO file:lineno
1231 * Returns: string length of what was edited.
1233 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1239 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1240 va_start(arg_ptr, fmt);
1241 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1243 if (len < 0 || len >= (maxlen-5)) {
1244 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1252 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1258 maxlen = sizeof_pool_memory(pool_buf) - 1;
1259 va_start(arg_ptr, fmt);
1260 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1262 if (len < 0 || len >= (maxlen-5)) {
1263 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1271 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1277 maxlen = pool_buf.max_size() - 1;
1278 va_start(arg_ptr, fmt);
1279 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1281 if (len < 0 || len >= (maxlen-5)) {
1282 pool_buf.realloc_pm(maxlen + maxlen/2);
1291 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1294 * We queue messages rather than print them directly. This
1295 * is generally used in low level routines (msg handler, bnet)
1296 * to prevent recursion (i.e. if you are in the middle of
1297 * sending a message, it is a bit messy to recursively call
1298 * yourself when the bnet packet is not reentrant).
1300 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1307 pool_buf = get_pool_memory(PM_EMSG);
1310 maxlen = sizeof_pool_memory(pool_buf) - 1;
1311 va_start(arg_ptr, fmt);
1312 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1314 if (len < 0 || len >= (maxlen-5)) {
1315 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1320 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1322 item->mtime = time(NULL);
1323 strcpy(item->msg, pool_buf);
1324 /* If no jcr or dequeuing send to daemon to avoid recursion */
1325 if (!jcr || jcr->dequeuing) {
1326 /* jcr==NULL => daemon message, safe to send now */
1327 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1330 /* Queue message for later sending */
1332 jcr->msg_queue->append(item);
1335 free_memory(pool_buf);
1341 void dequeue_messages(JCR *jcr)
1345 if (!jcr->msg_queue) {
1348 jcr->dequeuing = true;
1349 foreach_dlist(item, jcr->msg_queue) {
1350 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1352 jcr->msg_queue->destroy();
1353 jcr->dequeuing = false;
1361 * If we come here, prefix the message with the file:line-number,
1362 * then pass it on to the normal Qmsg routine.
1364 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1370 pool_buf = get_pool_memory(PM_EMSG);
1371 i = Mmsg(pool_buf, "%s:%d ", file, line);
1374 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1375 va_start(arg_ptr, fmt);
1376 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1378 if (len < 0 || len >= (maxlen-5)) {
1379 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1385 Qmsg(jcr, type, mtime, "%s", pool_buf);
1386 free_memory(pool_buf);