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(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 ", my_name, get_basename(file), line);
859 va_start(arg_ptr, fmt);
860 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
864 * Used the "trace on" command in the console to turn on
865 * output to the trace file. "trace off" will close the file.
870 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
871 trace_fd = fopen(fn, "a+b");
874 fputs(buf, trace_fd);
877 /* Some problem, turn off tracing */
880 } else { /* not tracing */
888 * Set trace flag on/off. If argument is negative, there is no change
890 void set_trace(int trace_flag)
892 if (trace_flag < 0) {
894 } else if (trace_flag > 0) {
899 if (!trace && trace_fd) {
900 FILE *ltrace_fd = trace_fd;
902 bmicrosleep(0, 100000); /* yield to prevent seg faults */
912 /*********************************************************************
914 * This subroutine prints a message regardless of the debug level
916 * If the level is negative, the details of file and line number
920 p_msg(const char *file, int line, int level, const char *fmt,...)
928 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
935 va_start(arg_ptr, fmt);
936 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
943 /*********************************************************************
945 * subroutine writes a debug message to the trace file if the level number
946 * is less than or equal the debug_level. File and line numbers
947 * are included for more detail if desired, but not currently
950 * If the level is negative, the details of file and line number
954 t_msg(const char *file, int line, int level, const char *fmt,...)
966 if (level <= debug_level) {
968 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
969 trace_fd = fopen(buf, "a+b");
974 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
981 va_start(arg_ptr, fmt);
982 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
984 if (trace_fd != NULL) {
985 fputs(buf, trace_fd);
993 /* *********************************************************
995 * print an error message
999 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1006 * Check if we have a message destination defined.
1007 * We always report M_ABORT and M_ERROR_TERM
1009 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1010 !bit_is_set(type, daemon_msgs->send_msg))) {
1011 return; /* no destination */
1015 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1016 my_name, get_basename(file), line);
1019 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1020 my_name, get_basename(file), line);
1023 if (level == -1) /* skip details */
1024 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1026 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1029 if (level == -1) /* skip details */
1030 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1032 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1035 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1038 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1041 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1045 va_start(arg_ptr, fmt);
1046 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1049 dispatch_message(NULL, type, 0, buf);
1051 if (type == M_ABORT) {
1053 p[0] = 0; /* generate segmentation violation */
1055 if (type == M_ERROR_TERM) {
1060 /* *********************************************************
1062 * Generate a Job message
1066 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1075 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1077 /* Special case for the console, which has a dir_bsock and JobId==0,
1078 * in that case, we send the message directly back to the
1081 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1082 BSOCK *dir = jcr->dir_bsock;
1083 va_start(arg_ptr, fmt);
1084 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1087 bnet_send(jcr->dir_bsock);
1094 msgs = jcr->jcr_msgs;
1098 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1101 job = ""; /* Set null job name if none */
1105 * Check if we have a message destination defined.
1106 * We always report M_ABORT and M_ERROR_TERM
1108 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1109 !bit_is_set(type, msgs->send_msg)) {
1110 return; /* no destination */
1114 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1117 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1120 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1122 set_jcr_job_status(jcr, JS_FatalError);
1126 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1132 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1135 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1138 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1142 va_start(arg_ptr, fmt);
1143 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1146 dispatch_message(jcr, type, mtime, rbuf);
1148 if (type == M_ABORT){
1150 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1151 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1152 p[0] = 0; /* generate segmentation violation */
1154 if (type == M_ERROR_TERM) {
1160 * If we come here, prefix the message with the file:line-number,
1161 * then pass it on to the normal Jmsg routine.
1163 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1169 pool_buf = get_pool_memory(PM_EMSG);
1170 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1173 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1174 va_start(arg_ptr, fmt);
1175 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1177 if (len < 0 || len >= (maxlen-5)) {
1178 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1184 Jmsg(jcr, type, mtime, "%s", pool_buf);
1185 free_memory(pool_buf);
1190 * Edit a message into a Pool memory buffer, with file:lineno
1192 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1197 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1200 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1201 va_start(arg_ptr, fmt);
1202 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1204 if (len < 0 || len >= (maxlen-5)) {
1205 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1213 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1218 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1221 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1222 va_start(arg_ptr, fmt);
1223 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1225 if (len < 0 || len >= (maxlen-5)) {
1226 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1236 * Edit a message into a Pool Memory buffer NO file:lineno
1237 * Returns: string length of what was edited.
1239 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1245 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1246 va_start(arg_ptr, fmt);
1247 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1249 if (len < 0 || len >= (maxlen-5)) {
1250 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1258 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1264 maxlen = sizeof_pool_memory(pool_buf) - 1;
1265 va_start(arg_ptr, fmt);
1266 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1268 if (len < 0 || len >= (maxlen-5)) {
1269 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1277 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1283 maxlen = pool_buf.max_size() - 1;
1284 va_start(arg_ptr, fmt);
1285 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1287 if (len < 0 || len >= (maxlen-5)) {
1288 pool_buf.realloc_pm(maxlen + maxlen/2);
1297 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1300 * We queue messages rather than print them directly. This
1301 * is generally used in low level routines (msg handler, bnet)
1302 * to prevent recursion (i.e. if you are in the middle of
1303 * sending a message, it is a bit messy to recursively call
1304 * yourself when the bnet packet is not reentrant).
1306 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1313 pool_buf = get_pool_memory(PM_EMSG);
1316 maxlen = sizeof_pool_memory(pool_buf) - 1;
1317 va_start(arg_ptr, fmt);
1318 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1320 if (len < 0 || len >= (maxlen-5)) {
1321 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1326 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1328 item->mtime = time(NULL);
1329 strcpy(item->msg, pool_buf);
1330 /* If no jcr or dequeuing send to daemon to avoid recursion */
1331 if (!jcr || jcr->dequeuing) {
1332 /* jcr==NULL => daemon message, safe to send now */
1333 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1336 /* Queue message for later sending */
1338 jcr->msg_queue->append(item);
1341 free_memory(pool_buf);
1347 void dequeue_messages(JCR *jcr)
1351 if (!jcr->msg_queue) {
1354 jcr->dequeuing = true;
1355 foreach_dlist(item, jcr->msg_queue) {
1356 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1358 jcr->msg_queue->destroy();
1359 jcr->dequeuing = false;
1367 * If we come here, prefix the message with the file:line-number,
1368 * then pass it on to the normal Qmsg routine.
1370 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1376 pool_buf = get_pool_memory(PM_EMSG);
1377 i = Mmsg(pool_buf, "%s:%d ", file, line);
1380 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1381 va_start(arg_ptr, fmt);
1382 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1384 if (len < 0 || len >= (maxlen-5)) {
1385 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1391 Qmsg(jcr, type, mtime, "%s", pool_buf);
1392 free_memory(pool_buf);