2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 John Walker.
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 * Kern Sibbald, April 2000
41 sql_query p_sql_query = NULL;
42 sql_escape p_sql_escape = NULL;
44 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
47 * This is where we define "Globals" because all the
48 * daemons include this file.
50 const char *working_directory = NULL; /* working directory path stored here */
51 int verbose = 0; /* increase User messages */
52 int debug_level = 1; /* debug level */
53 time_t daemon_start_time = 0; /* Daemon start time */
54 const char *version = VERSION " (" BDATE ")";
55 char my_name[30]; /* daemon name is stored here */
56 char *exepath = (char *)NULL;
57 char *exename = (char *)NULL;
58 int console_msg_pending = false;
59 char con_fname[500]; /* Console filename */
60 FILE *con_fd = NULL; /* Console file descriptor */
61 brwlock_t con_lock; /* Console lock structure */
63 static char *catalog_db = NULL; /* database type */
64 static void (*message_callback)(int type, char *msg) = NULL;
66 const char *host_os = HOST_OS;
67 const char *distname = DISTNAME;
68 const char *distver = DISTVER;
69 static FILE *trace_fd = NULL;
70 #if defined(HAVE_WIN32)
71 static bool trace = true;
73 static bool trace = false;
76 /* Forward referenced functions */
78 /* Imported functions */
83 /* Used to allow only one thread close the daemon messages at a time */
84 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
85 static MSGS *daemon_msgs; /* global messages */
87 void register_message_callback(void msg_callback(int type, char *msg))
89 message_callback = msg_callback;
94 * Set daemon name. Also, find canonical execution
95 * path. Note, exepath has spare room for tacking on
96 * the exename so that we can reconstruct the full name.
98 * Note, this routine can get called multiple times
99 * The second time is to put the name as found in the
100 * Resource record. On the second call, generally,
101 * argv is NULL to avoid doing the path code twice.
103 void my_name_is(int argc, char *argv[], const char *name)
109 bstrncpy(my_name, name, sizeof(my_name));
110 if (argc>0 && argv && argv[0]) {
111 /* strip trailing filename and save exepath */
112 for (l=p=argv[0]; *p; p++) {
113 if (IsPathSeparator(*p)) {
114 l = p; /* set pos of last slash */
117 if (IsPathSeparator(*l)) {
121 #if defined(HAVE_WIN32)
122 /* On Windows allow c: junk */
132 exename = (char *)malloc(len);
138 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
139 for (p=argv[0],q=exepath; p < l; ) {
143 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
144 if (getcwd(cpath, sizeof(cpath))) {
146 exepath = (char *)malloc(strlen(cpath) + 1 + len);
147 strcpy(exepath, cpath);
150 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
157 return catalog_db != NULL ? catalog_db : "unknown";
161 set_db_type(const char *name)
163 if (catalog_db != NULL) {
166 catalog_db = bstrdup(name);
170 * Initialize message handler for a daemon or a Job
171 * We make a copy of the MSGS resource passed, so it belows
172 * to the job or daemon and thus can be modified.
174 * NULL for jcr -> initialize global messages for daemon
175 * non-NULL -> initialize jcr using Message resource
178 init_msg(JCR *jcr, MSGS *msg)
180 DEST *d, *dnew, *temp_chain = NULL;
183 if (jcr == NULL && msg == NULL) {
184 init_last_jobs_list();
187 #if !defined(HAVE_WIN32)
189 * Make sure we have fd's 0, 1, 2 open
190 * If we don't do this one of our sockets may open
191 * there and if we then use stdout, it could
192 * send total garbage to our socket.
196 fd = open("/dev/null", O_RDONLY, 0644);
200 for(i=1; fd + i <= 2; i++) {
207 * If msg is NULL, initialize global chain for STDOUT and syslog
210 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
211 memset(daemon_msgs, 0, sizeof(MSGS));
212 for (i=1; i<=M_MAX; i++) {
213 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
215 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
220 * Walk down the message resource chain duplicating it
221 * for the current Job.
223 for (d=msg->dest_chain; d; d=d->next) {
224 dnew = (DEST *)malloc(sizeof(DEST));
225 memcpy(dnew, d, sizeof(DEST));
226 dnew->next = temp_chain;
228 dnew->mail_filename = NULL;
230 dnew->mail_cmd = bstrdup(d->mail_cmd);
233 dnew->where = bstrdup(d->where);
239 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
240 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
241 jcr->jcr_msgs->dest_chain = temp_chain;
242 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
244 /* If we have default values, release them now */
246 free_msgs_res(daemon_msgs);
248 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
249 memset(daemon_msgs, 0, sizeof(MSGS));
250 daemon_msgs->dest_chain = temp_chain;
251 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
253 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
257 /* Initialize so that the console (User Agent) can
258 * receive messages -- stored in a file.
260 void init_console_msg(const char *wd)
264 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
265 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
268 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
269 con_fname, be.bstrerror());
271 if (lseek(fd, 0, SEEK_END) > 0) {
272 console_msg_pending = 1;
275 con_fd = fopen(con_fname, "a+b");
278 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
279 con_fname, be.bstrerror());
281 if (rwl_init(&con_lock) != 0) {
283 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
289 * Called only during parsing of the config file.
291 * Add a message destination. I.e. associate a message type with
292 * a destination (code).
293 * Note, where in the case of dest_code FILE is a filename,
294 * but in the case of MAIL is a space separated list of
295 * email addresses, ...
297 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
301 * First search the existing chain and see if we
302 * can simply add this msg_type to an existing entry.
304 for (d=msg->dest_chain; d; d=d->next) {
305 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
306 (strcmp(where, d->where) == 0))) {
307 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
308 d, msg_type, dest_code, NPRT(where));
309 set_bit(msg_type, d->msg_types);
310 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
314 /* Not found, create a new entry */
315 d = (DEST *)malloc(sizeof(DEST));
316 memset(d, 0, sizeof(DEST));
317 d->next = msg->dest_chain;
318 d->dest_code = dest_code;
319 set_bit(msg_type, d->msg_types); /* set type bit in structure */
320 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
322 d->where = bstrdup(where);
325 d->mail_cmd = bstrdup(mail_cmd);
327 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
328 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
333 * Called only during parsing of the config file.
335 * Remove a message destination
337 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
341 for (d=msg->dest_chain; d; d=d->next) {
342 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
343 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
344 ((where == NULL && d->where == NULL) ||
345 (strcmp(where, d->where) == 0))) {
346 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
347 d, msg_type, dest_code);
348 clear_bit(msg_type, d->msg_types);
349 Dmsg0(850, "Return rem_msg_dest\n");
357 * Create a unique filename for the mail command
359 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
362 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
363 jcr->Job, (int)(long)d);
365 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
366 my_name, (int)(long)d);
368 Dmsg1(850, "mailname=%s\n", name);
374 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
379 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
381 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
385 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
387 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
388 cmd, be.bstrerror());
391 /* If we had to use sendmail, add subject */
393 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
400 * Close the messages for this Messages resource, which means to close
401 * any open files, and dispatch any pending email messages.
403 void close_msg(JCR *jcr)
411 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
413 if (jcr == NULL) { /* NULL -> global chain */
415 P(mutex); /* only one thread walking the chain */
417 msgs = jcr->jcr_msgs;
418 jcr->jcr_msgs = NULL;
423 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
424 cmd = get_pool_memory(PM_MESSAGE);
425 for (d=msgs->dest_chain; d; ) {
427 switch (d->dest_code) {
431 fclose(d->fd); /* close open file descriptor */
436 case MD_MAIL_ON_ERROR:
437 case MD_MAIL_ON_SUCCESS:
438 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
443 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
444 jcr->JobStatus == JS_Terminated)
446 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
447 jcr->JobStatus == JS_ErrorTerminated)
452 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
453 Pmsg0(000, _("open mail pipe failed.\n"));
456 Dmsg0(850, "Opened mail pipe\n");
458 line = get_memory(len);
460 while (fgets(line, len, d->fd)) {
461 fputs(line, bpipe->wfd);
463 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
465 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
469 * Since we are closing all messages, before "recursing"
470 * make sure we are not closing the daemon messages, otherwise
473 if (msgs != daemon_msgs) {
474 /* read what mail prog returned -- should be nothing */
475 while (fgets(line, len, bpipe->rfd)) {
476 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
480 stat = close_bpipe(bpipe);
481 if (stat != 0 && msgs != daemon_msgs) {
484 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
485 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
487 "ERR=%s\n"), cmd, be.bstrerror());
491 /* Remove temp file */
494 unlink(d->mail_filename);
495 free_pool_memory(d->mail_filename);
496 d->mail_filename = NULL;
497 Dmsg0(850, "end mail or mail on error\n");
504 d = d->next; /* point to next buffer */
506 free_pool_memory(cmd);
507 Dmsg0(850, "Done walking message chain.\n");
514 Dmsg0(850, "===End close msg resource\n");
518 * Free memory associated with Messages resource
520 void free_msgs_res(MSGS *msgs)
524 /* Walk down the message chain releasing allocated buffers */
525 for (d=msgs->dest_chain; d; ) {
532 old = d; /* save pointer to release */
533 d = d->next; /* point to next buffer */
534 free(old); /* free the destination item */
536 msgs->dest_chain = NULL;
537 free(msgs); /* free the head */
542 * Terminate the message handler for good.
543 * Release the global destination chain.
545 * Also, clean up a few other items (cons, exepath). Note,
546 * these really should be done elsewhere.
550 Dmsg0(850, "Enter term_msg\n");
551 close_msg(NULL); /* close global chain */
552 free_msgs_res(daemon_msgs); /* free the resources */
575 term_last_jobs_list();
578 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
580 d->fd = fopen(d->where, mode);
584 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
593 * Handle sending the message to the appropriate place
595 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
598 char dt[MAX_TIME_LENGTH];
605 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
608 * Most messages are prefixed by a date and time. If mtime is
609 * zero, then we use the current time. If mtime is 1 (special
610 * kludge), we do not prefix the date and time. Otherwise,
611 * we assume mtime is a time_t and use it.
620 bstrftime_ny(dt, sizeof(dt), mtime);
626 /* If the program registered a callback, send it there */
627 if (message_callback) {
628 message_callback(type, msg);
632 if (type == M_ABORT || type == M_ERROR_TERM) {
634 fputs(msg, stdout); /* print this here to INSURE that it is printed */
639 /* Now figure out where to send the message */
642 msgs = jcr->jcr_msgs;
647 for (d=msgs->dest_chain; d; d=d->next) {
648 if (bit_is_set(type, d->msg_types)) {
649 switch (d->dest_code) {
652 if (!jcr || !jcr->db) {
655 if (p_sql_query && p_sql_escape) {
656 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
657 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
659 int len = strlen(msg) + 1;
660 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
661 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
663 bstrutime(dt, sizeof(dt), mtime);
664 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
665 edit_int64(jcr->JobId, ed1), dt, esc_msg);
666 p_sql_query(jcr, cmd);
668 free_pool_memory(cmd);
669 free_pool_memory(esc_msg);
673 Dmsg1(850, "CONSOLE for following msg: %s", msg);
675 con_fd = fopen(con_fname, "a+b");
676 Dmsg0(850, "Console file not open.\n");
679 Pw(con_lock); /* get write lock on console message file */
682 (void)fwrite(dt, dtlen, 1, con_fd);
686 (void)fwrite(msg, len, 1, con_fd);
687 if (msg[len-1] != '\n') {
688 (void)fwrite("\n", 2, 1, con_fd);
691 (void)fwrite("\n", 2, 1, con_fd);
694 console_msg_pending = true;
699 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
701 * We really should do an openlog() here.
703 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
706 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
707 mcmd = get_pool_memory(PM_MESSAGE);
708 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
710 fputs(dt, bpipe->wfd);
711 fputs(msg, bpipe->wfd);
712 /* Messages to the operator go one at a time */
713 stat = close_bpipe(bpipe);
717 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
719 "ERR=%s\n"), mcmd, be.bstrerror());
722 free_pool_memory(mcmd);
725 case MD_MAIL_ON_ERROR:
726 case MD_MAIL_ON_SUCCESS:
727 Dmsg1(850, "MAIL for following msg: %s", msg);
729 POOLMEM *name = get_pool_memory(PM_MESSAGE);
730 make_unique_mail_filename(jcr, name, d);
731 d->fd = fopen(name, "w+b");
735 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
738 free_pool_memory(name);
741 d->mail_filename = name;
744 len = strlen(msg) + dtlen;;
745 if (len > d->max_len) {
746 d->max_len = len; /* keep max line length */
751 Dmsg1(850, "APPEND for following msg: %s", msg);
755 Dmsg1(850, "FILE for following msg: %s", msg);
758 if (!d->fd && !open_dest_file(jcr, d, mode)) {
763 /* On error, we close and reopen to handle log rotation */
767 if (open_dest_file(jcr, d, mode)) {
774 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
775 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
776 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
777 jcr->Job, type, mtime, msg);
781 Dmsg1(850, "STDOUT for following msg: %s", msg);
782 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
789 Dmsg1(850, "STDERR for following msg: %s", msg);
801 /*********************************************************************
803 * This subroutine returns the filename portion of a Windows
804 * path. It is used because Microsoft Visual Studio sets __FILE__
809 get_basename(const char *pathname)
811 #if defined(_MSC_VER)
812 const char *basename;
814 if ((basename = strrchr(pathname, '\\')) == NULL) {
826 /*********************************************************************
828 * This subroutine prints a debug message if the level number
829 * is less than or equal the debug_level. File and line numbers
830 * are included for more detail if desired, but not currently
833 * If the level is negative, the details of file and line number
837 d_msg(const char *file, int line, int level, const char *fmt,...)
849 if (level <= debug_level) {
852 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d jid=%u",
853 my_name, get_basename(file), line, get_jobid_from_tid());
860 va_start(arg_ptr, fmt);
861 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
865 * Used the "trace on" command in the console to turn on
866 * output to the trace file. "trace off" will close the file.
871 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
872 trace_fd = fopen(fn, "a+b");
875 fputs(buf, trace_fd);
878 /* Some problem, turn off tracing */
881 } else { /* not tracing */
889 * Set trace flag on/off. If argument is negative, there is no change
891 void set_trace(int trace_flag)
893 if (trace_flag < 0) {
895 } else if (trace_flag > 0) {
900 if (!trace && trace_fd) {
901 FILE *ltrace_fd = trace_fd;
903 bmicrosleep(0, 100000); /* yield to prevent seg faults */
913 /*********************************************************************
915 * This subroutine prints a message regardless of the debug level
917 * If the level is negative, the details of file and line number
921 p_msg(const char *file, int line, int level, const char *fmt,...)
929 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
936 va_start(arg_ptr, fmt);
937 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
944 /*********************************************************************
946 * subroutine writes a debug message to the trace file if the level number
947 * is less than or equal the debug_level. File and line numbers
948 * are included for more detail if desired, but not currently
951 * If the level is negative, the details of file and line number
955 t_msg(const char *file, int line, int level, const char *fmt,...)
967 if (level <= debug_level) {
969 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
970 trace_fd = fopen(buf, "a+b");
975 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
982 va_start(arg_ptr, fmt);
983 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
985 if (trace_fd != NULL) {
986 fputs(buf, trace_fd);
994 /* *********************************************************
996 * print an error message
1000 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1007 * Check if we have a message destination defined.
1008 * We always report M_ABORT and M_ERROR_TERM
1010 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1011 !bit_is_set(type, daemon_msgs->send_msg))) {
1012 return; /* no destination */
1016 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1017 my_name, get_basename(file), line);
1020 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1021 my_name, get_basename(file), line);
1024 if (level == -1) /* skip details */
1025 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1027 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1030 if (level == -1) /* skip details */
1031 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1033 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1036 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1039 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1042 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1046 va_start(arg_ptr, fmt);
1047 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1050 dispatch_message(NULL, type, 0, buf);
1052 if (type == M_ABORT) {
1054 p[0] = 0; /* generate segmentation violation */
1056 if (type == M_ERROR_TERM) {
1061 /* *********************************************************
1063 * Generate a Job message
1067 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1076 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1078 /* Special case for the console, which has a dir_bsock and JobId==0,
1079 * in that case, we send the message directly back to the
1082 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1083 BSOCK *dir = jcr->dir_bsock;
1084 va_start(arg_ptr, fmt);
1085 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1088 jcr->dir_bsock->send();
1095 msgs = jcr->jcr_msgs;
1099 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1102 job = ""; /* Set null job name if none */
1106 * Check if we have a message destination defined.
1107 * We always report M_ABORT and M_ERROR_TERM
1109 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1110 !bit_is_set(type, msgs->send_msg)) {
1111 return; /* no destination */
1115 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1118 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1121 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1123 set_jcr_job_status(jcr, JS_FatalError);
1127 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1133 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1136 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1139 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1143 va_start(arg_ptr, fmt);
1144 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1147 dispatch_message(jcr, type, mtime, rbuf);
1149 if (type == M_ABORT){
1151 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1152 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1153 p[0] = 0; /* generate segmentation violation */
1155 if (type == M_ERROR_TERM) {
1161 * If we come here, prefix the message with the file:line-number,
1162 * then pass it on to the normal Jmsg routine.
1164 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1170 pool_buf = get_pool_memory(PM_EMSG);
1171 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1174 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1175 va_start(arg_ptr, fmt);
1176 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1178 if (len < 0 || len >= (maxlen-5)) {
1179 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1185 Jmsg(jcr, type, mtime, "%s", pool_buf);
1186 free_memory(pool_buf);
1191 * Edit a message into a Pool memory buffer, with file:lineno
1193 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1198 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1201 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1202 va_start(arg_ptr, fmt);
1203 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1205 if (len < 0 || len >= (maxlen-5)) {
1206 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1214 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1219 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1222 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1223 va_start(arg_ptr, fmt);
1224 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1226 if (len < 0 || len >= (maxlen-5)) {
1227 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1237 * Edit a message into a Pool Memory buffer NO file:lineno
1238 * Returns: string length of what was edited.
1240 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1246 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1247 va_start(arg_ptr, fmt);
1248 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1250 if (len < 0 || len >= (maxlen-5)) {
1251 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1259 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1265 maxlen = sizeof_pool_memory(pool_buf) - 1;
1266 va_start(arg_ptr, fmt);
1267 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1269 if (len < 0 || len >= (maxlen-5)) {
1270 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1278 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1284 maxlen = pool_buf.max_size() - 1;
1285 va_start(arg_ptr, fmt);
1286 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1288 if (len < 0 || len >= (maxlen-5)) {
1289 pool_buf.realloc_pm(maxlen + maxlen/2);
1298 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1301 * We queue messages rather than print them directly. This
1302 * is generally used in low level routines (msg handler, bnet)
1303 * to prevent recursion (i.e. if you are in the middle of
1304 * sending a message, it is a bit messy to recursively call
1305 * yourself when the bnet packet is not reentrant).
1307 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1314 pool_buf = get_pool_memory(PM_EMSG);
1317 maxlen = sizeof_pool_memory(pool_buf) - 1;
1318 va_start(arg_ptr, fmt);
1319 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1321 if (len < 0 || len >= (maxlen-5)) {
1322 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1327 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1329 item->mtime = time(NULL);
1330 strcpy(item->msg, pool_buf);
1331 /* If no jcr or dequeuing send to daemon to avoid recursion */
1332 if (!jcr || jcr->dequeuing) {
1333 /* jcr==NULL => daemon message, safe to send now */
1334 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1337 /* Queue message for later sending */
1339 jcr->msg_queue->append(item);
1342 free_memory(pool_buf);
1348 void dequeue_messages(JCR *jcr)
1352 if (!jcr->msg_queue) {
1355 jcr->dequeuing = true;
1356 foreach_dlist(item, jcr->msg_queue) {
1357 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1359 jcr->msg_queue->destroy();
1360 jcr->dequeuing = false;
1368 * If we come here, prefix the message with the file:line-number,
1369 * then pass it on to the normal Qmsg routine.
1371 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1377 pool_buf = get_pool_memory(PM_EMSG);
1378 i = Mmsg(pool_buf, "%s:%d ", file, line);
1381 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1382 va_start(arg_ptr, fmt);
1383 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1385 if (len < 0 || len >= (maxlen-5)) {
1386 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1392 Qmsg(jcr, type, mtime, "%s", pool_buf);
1393 free_memory(pool_buf);