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 plus additions
11 that are listed in the file LICENSE.
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 = 0; /* 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 */
65 const char *host_os = HOST_OS;
66 const char *distname = DISTNAME;
67 const char *distver = DISTVER;
68 static FILE *trace_fd = NULL;
69 #if defined(HAVE_WIN32)
70 static bool trace = true;
72 static bool trace = false;
75 /* Forward referenced functions */
77 /* Imported functions */
82 /* Used to allow only one thread close the daemon messages at a time */
83 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
84 static MSGS *daemon_msgs; /* global messages */
88 * Set daemon name. Also, find canonical execution
89 * path. Note, exepath has spare room for tacking on
90 * the exename so that we can reconstruct the full name.
92 * Note, this routine can get called multiple times
93 * The second time is to put the name as found in the
94 * Resource record. On the second call, generally,
95 * argv is NULL to avoid doing the path code twice.
97 #define BTRACE_EXTRA 20
98 void my_name_is(int argc, char *argv[], const char *name)
104 bstrncpy(my_name, name, sizeof(my_name));
105 if (argc>0 && argv && argv[0]) {
106 /* strip trailing filename and save exepath */
107 for (l=p=argv[0]; *p; p++) {
108 if (IsPathSeparator(*p)) {
109 l = p; /* set pos of last slash */
112 if (IsPathSeparator(*l)) {
116 #if defined(HAVE_WIN32)
117 /* On Windows allow c: junk */
127 exename = (char *)malloc(len);
133 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
134 for (p=argv[0],q=exepath; p < l; ) {
138 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
139 if (getcwd(cpath, sizeof(cpath))) {
141 exepath = (char *)malloc(strlen(cpath) + 1 + len);
142 strcpy(exepath, cpath);
145 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
152 return catalog_db != NULL ? catalog_db : "unknown";
156 set_db_type(const char *name)
158 if (catalog_db != NULL) {
161 catalog_db = bstrdup(name);
165 * Initialize message handler for a daemon or a Job
166 * We make a copy of the MSGS resource passed, so it belows
167 * to the job or daemon and thus can be modified.
169 * NULL for jcr -> initialize global messages for daemon
170 * non-NULL -> initialize jcr using Message resource
173 init_msg(JCR *jcr, MSGS *msg)
175 DEST *d, *dnew, *temp_chain = NULL;
178 if (jcr == NULL && msg == NULL) {
179 init_last_jobs_list();
182 #if !defined(HAVE_WIN32)
184 * Make sure we have fd's 0, 1, 2 open
185 * If we don't do this one of our sockets may open
186 * there and if we then use stdout, it could
187 * send total garbage to our socket.
191 fd = open("/dev/null", O_RDONLY, 0644);
195 for(i=1; fd + i <= 2; i++) {
202 * If msg is NULL, initialize global chain for STDOUT and syslog
205 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
206 memset(daemon_msgs, 0, sizeof(MSGS));
207 for (i=1; i<=M_MAX; i++) {
208 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
210 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
215 * Walk down the message resource chain duplicating it
216 * for the current Job.
218 for (d=msg->dest_chain; d; d=d->next) {
219 dnew = (DEST *)malloc(sizeof(DEST));
220 memcpy(dnew, d, sizeof(DEST));
221 dnew->next = temp_chain;
223 dnew->mail_filename = NULL;
225 dnew->mail_cmd = bstrdup(d->mail_cmd);
228 dnew->where = bstrdup(d->where);
234 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
235 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
236 jcr->jcr_msgs->dest_chain = temp_chain;
237 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
239 /* If we have default values, release them now */
241 free_msgs_res(daemon_msgs);
243 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
244 memset(daemon_msgs, 0, sizeof(MSGS));
245 daemon_msgs->dest_chain = temp_chain;
246 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
248 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
252 /* Initialize so that the console (User Agent) can
253 * receive messages -- stored in a file.
255 void init_console_msg(const char *wd)
259 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
260 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
263 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
264 con_fname, be.strerror());
266 if (lseek(fd, 0, SEEK_END) > 0) {
267 console_msg_pending = 1;
270 con_fd = fopen(con_fname, "a+b");
273 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
274 con_fname, be.strerror());
276 if (rwl_init(&con_lock) != 0) {
278 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
284 * Called only during parsing of the config file.
286 * Add a message destination. I.e. associate a message type with
287 * a destination (code).
288 * Note, where in the case of dest_code FILE is a filename,
289 * but in the case of MAIL is a space separated list of
290 * email addresses, ...
292 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
296 * First search the existing chain and see if we
297 * can simply add this msg_type to an existing entry.
299 for (d=msg->dest_chain; d; d=d->next) {
300 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
301 (strcmp(where, d->where) == 0))) {
302 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
303 d, msg_type, dest_code, NPRT(where));
304 set_bit(msg_type, d->msg_types);
305 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
309 /* Not found, create a new entry */
310 d = (DEST *)malloc(sizeof(DEST));
311 memset(d, 0, sizeof(DEST));
312 d->next = msg->dest_chain;
313 d->dest_code = dest_code;
314 set_bit(msg_type, d->msg_types); /* set type bit in structure */
315 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
317 d->where = bstrdup(where);
320 d->mail_cmd = bstrdup(mail_cmd);
322 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
323 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
328 * Called only during parsing of the config file.
330 * Remove a message destination
332 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
336 for (d=msg->dest_chain; d; d=d->next) {
337 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
338 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
339 ((where == NULL && d->where == NULL) ||
340 (strcmp(where, d->where) == 0))) {
341 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
342 d, msg_type, dest_code);
343 clear_bit(msg_type, d->msg_types);
344 Dmsg0(850, "Return rem_msg_dest\n");
352 * Create a unique filename for the mail command
354 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
357 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
358 jcr->Job, (int)(long)d);
360 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
361 my_name, (int)(long)d);
363 Dmsg1(850, "mailname=%s\n", name);
369 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
374 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
376 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
380 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
382 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
386 /* If we had to use sendmail, add subject */
388 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
395 * Close the messages for this Messages resource, which means to close
396 * any open files, and dispatch any pending email messages.
398 void close_msg(JCR *jcr)
406 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
408 if (jcr == NULL) { /* NULL -> global chain */
410 P(mutex); /* only one thread walking the chain */
412 msgs = jcr->jcr_msgs;
413 jcr->jcr_msgs = NULL;
418 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
419 cmd = get_pool_memory(PM_MESSAGE);
420 for (d=msgs->dest_chain; d; ) {
422 switch (d->dest_code) {
426 fclose(d->fd); /* close open file descriptor */
431 case MD_MAIL_ON_ERROR:
432 case MD_MAIL_ON_SUCCESS:
433 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
438 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
439 jcr->JobStatus == JS_Terminated)
441 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
442 jcr->JobStatus == JS_ErrorTerminated)
447 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
448 Pmsg0(000, _("open mail pipe failed.\n"));
451 Dmsg0(850, "Opened mail pipe\n");
453 line = get_memory(len);
455 while (fgets(line, len, d->fd)) {
456 fputs(line, bpipe->wfd);
458 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
460 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
464 * Since we are closing all messages, before "recursing"
465 * make sure we are not closing the daemon messages, otherwise
468 if (msgs != daemon_msgs) {
469 /* read what mail prog returned -- should be nothing */
470 while (fgets(line, len, bpipe->rfd)) {
471 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
475 stat = close_bpipe(bpipe);
476 if (stat != 0 && msgs != daemon_msgs) {
479 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
480 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
482 "ERR=%s\n"), cmd, be.strerror());
486 /* Remove temp file */
489 unlink(d->mail_filename);
490 free_pool_memory(d->mail_filename);
491 d->mail_filename = NULL;
492 Dmsg0(850, "end mail or mail on error\n");
499 d = d->next; /* point to next buffer */
501 free_pool_memory(cmd);
502 Dmsg0(850, "Done walking message chain.\n");
509 Dmsg0(850, "===End close msg resource\n");
513 * Free memory associated with Messages resource
515 void free_msgs_res(MSGS *msgs)
519 /* Walk down the message chain releasing allocated buffers */
520 for (d=msgs->dest_chain; d; ) {
527 old = d; /* save pointer to release */
528 d = d->next; /* point to next buffer */
529 free(old); /* free the destination item */
531 msgs->dest_chain = NULL;
532 free(msgs); /* free the head */
537 * Terminate the message handler for good.
538 * Release the global destination chain.
540 * Also, clean up a few other items (cons, exepath). Note,
541 * these really should be done elsewhere.
545 Dmsg0(850, "Enter term_msg\n");
546 close_msg(NULL); /* close global chain */
547 free_msgs_res(daemon_msgs); /* free the resources */
570 term_last_jobs_list();
573 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
575 d->fd = fopen(d->where, mode);
579 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
588 * Handle sending the message to the appropriate place
590 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
593 char dt[MAX_TIME_LENGTH];
600 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
603 * Most messages are prefixed by a date and time. If mtime is
604 * zero, then we use the current time. If mtime is 1 (special
605 * kludge), we do not prefix the date and time. Otherwise,
606 * we assume mtime is a time_t and use it.
615 bstrftime_ny(dt, sizeof(dt), mtime);
621 if (type == M_ABORT || type == M_ERROR_TERM) {
623 fputs(msg, stdout); /* print this here to INSURE that it is printed */
627 /* Now figure out where to send the message */
630 msgs = jcr->jcr_msgs;
635 for (d=msgs->dest_chain; d; d=d->next) {
636 if (bit_is_set(type, d->msg_types)) {
637 switch (d->dest_code) {
640 if (!jcr || !jcr->db) {
643 if (p_sql_query && p_sql_escape) {
644 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
645 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
647 int len = strlen(msg) + 1;
648 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
649 p_sql_escape(esc_msg, msg, len);
651 bstrutime(dt, sizeof(dt), mtime);
652 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
653 edit_int64(jcr->JobId, ed1), dt, esc_msg);
654 p_sql_query(jcr, cmd);
656 free_pool_memory(cmd);
657 free_pool_memory(esc_msg);
661 Dmsg1(850, "CONSOLE for following msg: %s", msg);
663 con_fd = fopen(con_fname, "a+b");
664 Dmsg0(850, "Console file not open.\n");
667 Pw(con_lock); /* get write lock on console message file */
670 (void)fwrite(dt, dtlen, 1, con_fd);
674 (void)fwrite(msg, len, 1, con_fd);
675 if (msg[len-1] != '\n') {
676 (void)fwrite("\n", 2, 1, con_fd);
679 (void)fwrite("\n", 2, 1, con_fd);
682 console_msg_pending = true;
687 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
689 * We really should do an openlog() here.
691 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
694 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
695 mcmd = get_pool_memory(PM_MESSAGE);
696 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
698 fputs(dt, bpipe->wfd);
699 fputs(msg, bpipe->wfd);
700 /* Messages to the operator go one at a time */
701 stat = close_bpipe(bpipe);
705 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
707 "ERR=%s\n"), mcmd, be.strerror());
710 free_pool_memory(mcmd);
713 case MD_MAIL_ON_ERROR:
714 case MD_MAIL_ON_SUCCESS:
715 Dmsg1(850, "MAIL for following msg: %s", msg);
717 POOLMEM *name = get_pool_memory(PM_MESSAGE);
718 make_unique_mail_filename(jcr, name, d);
719 d->fd = fopen(name, "w+b");
723 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
726 free_pool_memory(name);
729 d->mail_filename = name;
732 len = strlen(msg) + dtlen;;
733 if (len > d->max_len) {
734 d->max_len = len; /* keep max line length */
739 Dmsg1(850, "APPEND for following msg: %s", msg);
743 Dmsg1(850, "FILE for following msg: %s", msg);
746 if (!d->fd && !open_dest_file(jcr, d, mode)) {
751 /* On error, we close and reopen to handle log rotation */
755 if (open_dest_file(jcr, d, mode)) {
762 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
763 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
764 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
765 jcr->Job, type, mtime, msg);
769 Dmsg1(850, "STDOUT for following msg: %s", msg);
770 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
777 Dmsg1(850, "STDERR for following msg: %s", msg);
789 /*********************************************************************
791 * This subroutine returns the filename portion of a Windows
792 * path. It is used because Microsoft Visual Studio sets __FILE__
797 get_basename(const char *pathname)
799 #if defined(_MSC_VER)
800 const char *basename;
802 if ((basename = strrchr(pathname, '\\')) == NULL) {
814 /*********************************************************************
816 * This subroutine prints a debug message if the level number
817 * is less than or equal the debug_level. File and line numbers
818 * are included for more detail if desired, but not currently
821 * If the level is negative, the details of file and line number
825 d_msg(const char *file, int line, int level, const char *fmt,...)
837 if (level <= debug_level) {
840 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
847 va_start(arg_ptr, fmt);
848 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
852 * Used the "trace on" command in the console to turn on
853 * output to the trace file. "trace off" will close the file.
858 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
859 trace_fd = fopen(fn, "a+b");
862 fputs(buf, trace_fd);
865 /* Some problem, turn off tracing */
868 } else { /* not tracing */
876 * Set trace flag on/off. If argument is negative, there is no change
878 void set_trace(int trace_flag)
880 if (trace_flag < 0) {
882 } else if (trace_flag > 0) {
887 if (!trace && trace_fd) {
888 FILE *ltrace_fd = trace_fd;
890 bmicrosleep(0, 100000); /* yield to prevent seg faults */
900 /*********************************************************************
902 * This subroutine prints a message regardless of the debug level
904 * If the level is negative, the details of file and line number
908 p_msg(const char *file, int line, int level, const char *fmt,...)
916 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
923 va_start(arg_ptr, fmt);
924 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
931 /*********************************************************************
933 * subroutine writes a debug message to the trace file if the level number
934 * is less than or equal the debug_level. File and line numbers
935 * are included for more detail if desired, but not currently
938 * If the level is negative, the details of file and line number
942 t_msg(const char *file, int line, int level, const char *fmt,...)
954 if (level <= debug_level) {
956 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
957 trace_fd = fopen(buf, "a+b");
962 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
969 va_start(arg_ptr, fmt);
970 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
972 if (trace_fd != NULL) {
973 fputs(buf, trace_fd);
981 /* *********************************************************
983 * print an error message
987 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
994 * Check if we have a message destination defined.
995 * We always report M_ABORT and M_ERROR_TERM
997 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
998 !bit_is_set(type, daemon_msgs->send_msg))) {
999 return; /* no destination */
1003 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1004 my_name, get_basename(file), line);
1007 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1008 my_name, get_basename(file), line);
1011 if (level == -1) /* skip details */
1012 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1014 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1017 if (level == -1) /* skip details */
1018 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1020 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1023 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1026 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1029 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1033 va_start(arg_ptr, fmt);
1034 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1037 dispatch_message(NULL, type, 0, buf);
1039 if (type == M_ABORT) {
1041 p[0] = 0; /* generate segmentation violation */
1043 if (type == M_ERROR_TERM) {
1048 /* *********************************************************
1050 * Generate a Job message
1054 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1063 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1065 /* Special case for the console, which has a dir_bsock and JobId==0,
1066 * in that case, we send the message directly back to the
1069 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1070 BSOCK *dir = jcr->dir_bsock;
1071 va_start(arg_ptr, fmt);
1072 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1075 bnet_send(jcr->dir_bsock);
1082 msgs = jcr->jcr_msgs;
1086 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1089 job = ""; /* Set null job name if none */
1093 * Check if we have a message destination defined.
1094 * We always report M_ABORT and M_ERROR_TERM
1096 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1097 !bit_is_set(type, msgs->send_msg)) {
1098 return; /* no destination */
1102 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1105 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1108 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1110 set_jcr_job_status(jcr, JS_FatalError);
1114 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1120 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1123 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1126 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1130 va_start(arg_ptr, fmt);
1131 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1134 dispatch_message(jcr, type, mtime, rbuf);
1136 if (type == M_ABORT){
1138 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1139 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1140 p[0] = 0; /* generate segmentation violation */
1142 if (type == M_ERROR_TERM) {
1148 * If we come here, prefix the message with the file:line-number,
1149 * then pass it on to the normal Jmsg routine.
1151 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1157 pool_buf = get_pool_memory(PM_EMSG);
1158 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1161 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1162 va_start(arg_ptr, fmt);
1163 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1165 if (len < 0 || len >= (maxlen-5)) {
1166 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1172 Jmsg(jcr, type, mtime, "%s", pool_buf);
1173 free_memory(pool_buf);
1178 * Edit a message into a Pool memory buffer, with file:lineno
1180 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1185 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1188 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1189 va_start(arg_ptr, fmt);
1190 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1192 if (len < 0 || len >= (maxlen-5)) {
1193 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1201 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1206 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1209 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1210 va_start(arg_ptr, fmt);
1211 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1213 if (len < 0 || len >= (maxlen-5)) {
1214 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1224 * Edit a message into a Pool Memory buffer NO file:lineno
1225 * Returns: string length of what was edited.
1227 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1233 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1234 va_start(arg_ptr, fmt);
1235 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1237 if (len < 0 || len >= (maxlen-5)) {
1238 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1246 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1252 maxlen = sizeof_pool_memory(pool_buf) - 1;
1253 va_start(arg_ptr, fmt);
1254 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1256 if (len < 0 || len >= (maxlen-5)) {
1257 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1265 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1271 maxlen = pool_buf.max_size() - 1;
1272 va_start(arg_ptr, fmt);
1273 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1275 if (len < 0 || len >= (maxlen-5)) {
1276 pool_buf.realloc_pm(maxlen + maxlen/2);
1285 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1288 * We queue messages rather than print them directly. This
1289 * is generally used in low level routines (msg handler, bnet)
1290 * to prevent recursion (i.e. if you are in the middle of
1291 * sending a message, it is a bit messy to recursively call
1292 * yourself when the bnet packet is not reentrant).
1294 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1301 pool_buf = get_pool_memory(PM_EMSG);
1304 maxlen = sizeof_pool_memory(pool_buf) - 1;
1305 va_start(arg_ptr, fmt);
1306 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1308 if (len < 0 || len >= (maxlen-5)) {
1309 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1314 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1316 item->mtime = time(NULL);
1317 strcpy(item->msg, pool_buf);
1318 /* If no jcr or dequeuing send to daemon to avoid recursion */
1319 if (!jcr || jcr->dequeuing) {
1320 /* jcr==NULL => daemon message, safe to send now */
1321 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1324 /* Queue message for later sending */
1326 jcr->msg_queue->append(item);
1329 free_memory(pool_buf);
1335 void dequeue_messages(JCR *jcr)
1339 if (!jcr->msg_queue) {
1342 jcr->dequeuing = true;
1343 foreach_dlist(item, jcr->msg_queue) {
1344 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1346 jcr->msg_queue->destroy();
1347 jcr->dequeuing = false;
1355 * If we come here, prefix the message with the file:line-number,
1356 * then pass it on to the normal Qmsg routine.
1358 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1364 pool_buf = get_pool_memory(PM_EMSG);
1365 i = Mmsg(pool_buf, "%s:%d ", file, line);
1368 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1369 va_start(arg_ptr, fmt);
1370 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1372 if (len < 0 || len >= (maxlen-5)) {
1373 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1379 Qmsg(jcr, type, mtime, "%s", pool_buf);
1380 free_memory(pool_buf);