2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula message handling routines
31 * 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 bool dbg_timestamp = false; /* print timestamp in debug output */
54 time_t daemon_start_time = 0; /* Daemon start time */
55 const char *version = VERSION " (" BDATE ")";
56 char my_name[30]; /* daemon name is stored here */
57 char host_name[50]; /* host machine name */
58 char *exepath = (char *)NULL;
59 char *exename = (char *)NULL;
60 int console_msg_pending = false;
61 char con_fname[500]; /* Console filename */
62 FILE *con_fd = NULL; /* Console file descriptor */
63 brwlock_t con_lock; /* Console lock structure */
67 * Global variables to get information about lock/unlock db access
69 utime_t _db_lock_time = 0;
70 int _db_lock_recurse_count = 0;
71 pthread_t _db_lock_threadid;
76 bstrutime(buf, sizeof(buf), _db_lock_time);
78 fprintf(stderr, "lock info: recurse_count=%i threadid=0x%x time=%s\n",
79 _db_lock_recurse_count, (int)_db_lock_threadid, buf);
82 /* Forward referenced functions */
84 /* Imported functions */
85 void create_jcr_key();
89 /* Used to allow only one thread close the daemon messages at a time */
90 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
91 static MSGS *daemon_msgs; /* global messages */
92 static char *catalog_db = NULL; /* database type */
93 static void (*message_callback)(int type, char *msg) = NULL;
94 static FILE *trace_fd = NULL;
95 #if defined(HAVE_WIN32)
96 static bool trace = true;
98 static bool trace = false;
102 const char *host_os = HOST_OS;
103 const char *distname = DISTNAME;
104 const char *distver = DISTVER;
107 void register_message_callback(void msg_callback(int type, char *msg))
109 message_callback = msg_callback;
114 * Set daemon name. Also, find canonical execution
115 * path. Note, exepath has spare room for tacking on
116 * the exename so that we can reconstruct the full name.
118 * Note, this routine can get called multiple times
119 * The second time is to put the name as found in the
120 * Resource record. On the second call, generally,
121 * argv is NULL to avoid doing the path code twice.
123 void my_name_is(int argc, char *argv[], const char *name)
129 if (gethostname(host_name, sizeof(host_name)) != 0) {
130 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
132 bstrncpy(my_name, name, sizeof(my_name));
133 if (argc>0 && argv && argv[0]) {
134 /* strip trailing filename and save exepath */
135 for (l=p=argv[0]; *p; p++) {
136 if (IsPathSeparator(*p)) {
137 l = p; /* set pos of last slash */
140 if (IsPathSeparator(*l)) {
144 #if defined(HAVE_WIN32)
145 /* On Windows allow c: junk */
155 exename = (char *)malloc(len);
161 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
162 for (p=argv[0],q=exepath; p < l; ) {
166 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
167 if (getcwd(cpath, sizeof(cpath))) {
169 exepath = (char *)malloc(strlen(cpath) + 1 + len);
170 strcpy(exepath, cpath);
173 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
180 return catalog_db != NULL ? catalog_db : "unknown";
184 set_db_type(const char *name)
186 if (catalog_db != NULL) {
189 catalog_db = bstrdup(name);
193 * Initialize message handler for a daemon or a Job
194 * We make a copy of the MSGS resource passed, so it belows
195 * to the job or daemon and thus can be modified.
197 * NULL for jcr -> initialize global messages for daemon
198 * non-NULL -> initialize jcr using Message resource
201 init_msg(JCR *jcr, MSGS *msg)
203 DEST *d, *dnew, *temp_chain = NULL;
206 if (jcr == NULL && msg == NULL) {
207 init_last_jobs_list();
208 /* Create a daemon key then set invalid jcr */
209 /* Maybe we should give the daemon a jcr??? */
211 set_jcr_in_tsd(INVALID_JCR);
214 #if !defined(HAVE_WIN32)
216 * Make sure we have fd's 0, 1, 2 open
217 * If we don't do this one of our sockets may open
218 * there and if we then use stdout, it could
219 * send total garbage to our socket.
223 fd = open("/dev/null", O_RDONLY, 0644);
227 for(i=1; fd + i <= 2; i++) {
234 * If msg is NULL, initialize global chain for STDOUT and syslog
237 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
238 memset(daemon_msgs, 0, sizeof(MSGS));
239 for (i=1; i<=M_MAX; i++) {
240 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
242 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
247 * Walk down the message resource chain duplicating it
248 * for the current Job.
250 for (d=msg->dest_chain; d; d=d->next) {
251 dnew = (DEST *)malloc(sizeof(DEST));
252 memcpy(dnew, d, sizeof(DEST));
253 dnew->next = temp_chain;
255 dnew->mail_filename = NULL;
257 dnew->mail_cmd = bstrdup(d->mail_cmd);
260 dnew->where = bstrdup(d->where);
266 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
267 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
268 jcr->jcr_msgs->dest_chain = temp_chain;
269 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
271 /* If we have default values, release them now */
273 free_msgs_res(daemon_msgs);
275 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
276 memset(daemon_msgs, 0, sizeof(MSGS));
277 daemon_msgs->dest_chain = temp_chain;
278 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
280 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
284 /* Initialize so that the console (User Agent) can
285 * receive messages -- stored in a file.
287 void init_console_msg(const char *wd)
291 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
292 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
295 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
296 con_fname, be.bstrerror());
298 if (lseek(fd, 0, SEEK_END) > 0) {
299 console_msg_pending = 1;
302 con_fd = fopen(con_fname, "a+b");
305 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
306 con_fname, be.bstrerror());
308 if (rwl_init(&con_lock) != 0) {
310 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
316 * Called only during parsing of the config file.
318 * Add a message destination. I.e. associate a message type with
319 * a destination (code).
320 * Note, where in the case of dest_code FILE is a filename,
321 * but in the case of MAIL is a space separated list of
322 * email addresses, ...
324 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
328 * First search the existing chain and see if we
329 * can simply add this msg_type to an existing entry.
331 for (d=msg->dest_chain; d; d=d->next) {
332 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
333 (strcmp(where, d->where) == 0))) {
334 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
335 d, msg_type, dest_code, NPRT(where));
336 set_bit(msg_type, d->msg_types);
337 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
341 /* Not found, create a new entry */
342 d = (DEST *)malloc(sizeof(DEST));
343 memset(d, 0, sizeof(DEST));
344 d->next = msg->dest_chain;
345 d->dest_code = dest_code;
346 set_bit(msg_type, d->msg_types); /* set type bit in structure */
347 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
349 d->where = bstrdup(where);
352 d->mail_cmd = bstrdup(mail_cmd);
354 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
355 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
360 * Called only during parsing of the config file.
362 * Remove a message destination
364 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
368 for (d=msg->dest_chain; d; d=d->next) {
369 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
370 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
371 ((where == NULL && d->where == NULL) ||
372 (strcmp(where, d->where) == 0))) {
373 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
374 d, msg_type, dest_code);
375 clear_bit(msg_type, d->msg_types);
376 Dmsg0(850, "Return rem_msg_dest\n");
384 * Create a unique filename for the mail command
386 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
389 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
390 jcr->Job, (int)(long)d);
392 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
393 my_name, (int)(long)d);
395 Dmsg1(850, "mailname=%s\n", name);
401 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
406 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
408 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
412 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
413 /* If we had to use sendmail, add subject */
415 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
419 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
420 cmd, be.bstrerror());
426 * Close the messages for this Messages resource, which means to close
427 * any open files, and dispatch any pending email messages.
429 void close_msg(JCR *jcr)
437 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
439 if (jcr == NULL) { /* NULL -> global chain */
441 P(mutex); /* only one thread walking the chain */
443 msgs = jcr->jcr_msgs;
444 jcr->jcr_msgs = NULL;
449 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
450 cmd = get_pool_memory(PM_MESSAGE);
451 for (d=msgs->dest_chain; d; ) {
453 switch (d->dest_code) {
457 fclose(d->fd); /* close open file descriptor */
462 case MD_MAIL_ON_ERROR:
463 case MD_MAIL_ON_SUCCESS:
464 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
469 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
470 jcr->JobStatus == JS_Terminated)
472 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
473 jcr->JobStatus == JS_ErrorTerminated)
478 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
479 Pmsg0(000, _("open mail pipe failed.\n"));
482 Dmsg0(850, "Opened mail pipe\n");
484 line = get_memory(len);
486 while (fgets(line, len, d->fd)) {
487 fputs(line, bpipe->wfd);
489 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
491 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
495 * Since we are closing all messages, before "recursing"
496 * make sure we are not closing the daemon messages, otherwise
499 if (msgs != daemon_msgs) {
500 /* read what mail prog returned -- should be nothing */
501 while (fgets(line, len, bpipe->rfd)) {
502 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
506 stat = close_bpipe(bpipe);
507 if (stat != 0 && msgs != daemon_msgs) {
510 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
511 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
513 "ERR=%s\n"), cmd, be.bstrerror());
517 /* Remove temp file */
520 unlink(d->mail_filename);
521 free_pool_memory(d->mail_filename);
522 d->mail_filename = NULL;
523 Dmsg0(850, "end mail or mail on error\n");
530 d = d->next; /* point to next buffer */
532 free_pool_memory(cmd);
533 Dmsg0(850, "Done walking message chain.\n");
540 Dmsg0(850, "===End close msg resource\n");
544 * Free memory associated with Messages resource
546 void free_msgs_res(MSGS *msgs)
550 /* Walk down the message chain releasing allocated buffers */
551 for (d=msgs->dest_chain; d; ) {
558 old = d; /* save pointer to release */
559 d = d->next; /* point to next buffer */
560 free(old); /* free the destination item */
562 msgs->dest_chain = NULL;
563 free(msgs); /* free the head */
568 * Terminate the message handler for good.
569 * Release the global destination chain.
571 * Also, clean up a few other items (cons, exepath). Note,
572 * these really should be done elsewhere.
576 Dmsg0(850, "Enter term_msg\n");
577 close_msg(NULL); /* close global chain */
578 free_msgs_res(daemon_msgs); /* free the resources */
601 term_last_jobs_list();
604 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
606 d->fd = fopen(d->where, mode);
610 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
618 * Handle sending the message to the appropriate place
620 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
623 char dt[MAX_TIME_LENGTH];
630 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
633 * Most messages are prefixed by a date and time. If mtime is
634 * zero, then we use the current time. If mtime is 1 (special
635 * kludge), we do not prefix the date and time. Otherwise,
636 * we assume mtime is a time_t and use it.
645 bstrftime_ny(dt, sizeof(dt), mtime);
651 /* If the program registered a callback, send it there */
652 if (message_callback) {
653 message_callback(type, msg);
657 if (type == M_ABORT || type == M_ERROR_TERM) {
659 fputs(msg, stdout); /* print this here to INSURE that it is printed */
664 /* Now figure out where to send the message */
667 jcr = get_jcr_from_tsd();
670 msgs = jcr->jcr_msgs;
675 for (d=msgs->dest_chain; d; d=d->next) {
676 if (bit_is_set(type, d->msg_types)) {
677 switch (d->dest_code) {
680 if (!jcr || !jcr->db) {
683 if (p_sql_query && p_sql_escape) {
684 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
685 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
687 int len = strlen(msg) + 1;
688 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
689 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
691 bstrutime(dt, sizeof(dt), mtime);
692 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
693 edit_int64(jcr->JobId, ed1), dt, esc_msg);
694 p_sql_query(jcr, cmd);
696 free_pool_memory(cmd);
697 free_pool_memory(esc_msg);
701 Dmsg1(850, "CONSOLE for following msg: %s", msg);
703 con_fd = fopen(con_fname, "a+b");
704 Dmsg0(850, "Console file not open.\n");
707 Pw(con_lock); /* get write lock on console message file */
710 (void)fwrite(dt, dtlen, 1, con_fd);
714 (void)fwrite(msg, len, 1, con_fd);
715 if (msg[len-1] != '\n') {
716 (void)fwrite("\n", 2, 1, con_fd);
719 (void)fwrite("\n", 2, 1, con_fd);
722 console_msg_pending = true;
727 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
729 * We really should do an openlog() here.
731 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
734 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
735 mcmd = get_pool_memory(PM_MESSAGE);
736 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
738 fputs(dt, bpipe->wfd);
739 fputs(msg, bpipe->wfd);
740 /* Messages to the operator go one at a time */
741 stat = close_bpipe(bpipe);
745 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
747 "ERR=%s\n"), mcmd, be.bstrerror());
750 free_pool_memory(mcmd);
753 case MD_MAIL_ON_ERROR:
754 case MD_MAIL_ON_SUCCESS:
755 Dmsg1(850, "MAIL for following msg: %s", msg);
757 POOLMEM *name = get_pool_memory(PM_MESSAGE);
758 make_unique_mail_filename(jcr, name, d);
759 d->fd = fopen(name, "w+b");
763 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
766 free_pool_memory(name);
769 d->mail_filename = name;
772 len = strlen(msg) + dtlen;;
773 if (len > d->max_len) {
774 d->max_len = len; /* keep max line length */
779 Dmsg1(850, "APPEND for following msg: %s", msg);
783 Dmsg1(850, "FILE for following msg: %s", msg);
786 if (!d->fd && !open_dest_file(jcr, d, mode)) {
791 /* On error, we close and reopen to handle log rotation */
795 if (open_dest_file(jcr, d, mode)) {
802 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
803 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
804 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
805 jcr->Job, type, mtime, msg);
809 Dmsg1(850, "STDOUT for following msg: %s", msg);
810 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
817 Dmsg1(850, "STDERR for following msg: %s", msg);
829 /*********************************************************************
831 * This subroutine returns the filename portion of a Windows
832 * path. It is used because Microsoft Visual Studio sets __FILE__
837 get_basename(const char *pathname)
839 #if defined(_MSC_VER)
840 const char *basename;
842 if ((basename = strrchr(pathname, '\\')) == NULL) {
854 /*********************************************************************
856 * This subroutine prints a debug message if the level number
857 * is less than or equal the debug_level. File and line numbers
858 * are included for more detail if desired, but not currently
861 * If the level is negative, the details of file and line number
865 d_msg(const char *file, int line, int level, const char *fmt,...)
878 if (level <= debug_level) {
881 bstrftimes(buf, sizeof(buf), mtime);
890 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
891 my_name, get_basename(file), line, get_jobid_from_tsd());
898 va_start(arg_ptr, fmt);
899 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
903 * Used the "trace on" command in the console to turn on
904 * output to the trace file. "trace off" will close the file.
909 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
910 trace_fd = fopen(fn, "a+b");
913 fputs(buf, trace_fd);
916 /* Some problem, turn off tracing */
919 } else { /* not tracing */
927 * Set trace flag on/off. If argument is negative, there is no change
929 void set_trace(int trace_flag)
931 if (trace_flag < 0) {
933 } else if (trace_flag > 0) {
938 if (!trace && trace_fd) {
939 FILE *ltrace_fd = trace_fd;
941 bmicrosleep(0, 100000); /* yield to prevent seg faults */
951 /*********************************************************************
953 * This subroutine prints a message regardless of the debug level
955 * If the level is negative, the details of file and line number
959 p_msg(const char *file, int line, int level, const char *fmt,...)
967 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
974 va_start(arg_ptr, fmt);
975 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
982 /*********************************************************************
984 * subroutine writes a debug message to the trace file if the level number
985 * is less than or equal the debug_level. File and line numbers
986 * are included for more detail if desired, but not currently
989 * If the level is negative, the details of file and line number
993 t_msg(const char *file, int line, int level, const char *fmt,...)
1005 if (level <= debug_level) {
1007 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1008 trace_fd = fopen(buf, "a+b");
1011 #ifdef FULL_LOCATION
1013 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1020 va_start(arg_ptr, fmt);
1021 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1023 if (trace_fd != NULL) {
1024 fputs(buf, trace_fd);
1032 /* *********************************************************
1034 * print an error message
1038 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1045 * Check if we have a message destination defined.
1046 * We always report M_ABORT and M_ERROR_TERM
1048 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1049 !bit_is_set(type, daemon_msgs->send_msg))) {
1050 return; /* no destination */
1054 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1055 my_name, get_basename(file), line);
1058 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1059 my_name, get_basename(file), line);
1062 if (level == -1) /* skip details */
1063 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1065 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1068 if (level == -1) /* skip details */
1069 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1071 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1074 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1077 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1080 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1084 va_start(arg_ptr, fmt);
1085 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1088 dispatch_message(NULL, type, 0, buf);
1090 if (type == M_ABORT) {
1092 p[0] = 0; /* generate segmentation violation */
1094 if (type == M_ERROR_TERM) {
1099 /* *********************************************************
1101 * Generate a Job message
1105 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1114 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1116 /* Special case for the console, which has a dir_bsock and JobId==0,
1117 * in that case, we send the message directly back to the
1120 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1121 BSOCK *dir = jcr->dir_bsock;
1122 va_start(arg_ptr, fmt);
1123 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1126 jcr->dir_bsock->send();
1132 jcr = get_jcr_from_tsd();
1135 msgs = jcr->jcr_msgs;
1139 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1143 * Check if we have a message destination defined.
1144 * We always report M_ABORT and M_ERROR_TERM
1146 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1147 !bit_is_set(type, msgs->send_msg)) {
1148 return; /* no destination */
1152 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1155 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1158 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1160 set_jcr_job_status(jcr, JS_FatalError);
1164 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1170 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1173 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1177 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1181 va_start(arg_ptr, fmt);
1182 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1185 dispatch_message(jcr, type, mtime, rbuf);
1187 if (type == M_ABORT){
1189 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1190 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1191 p[0] = 0; /* generate segmentation violation */
1193 if (type == M_ERROR_TERM) {
1199 * If we come here, prefix the message with the file:line-number,
1200 * then pass it on to the normal Jmsg routine.
1202 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1208 pool_buf = get_pool_memory(PM_EMSG);
1209 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1212 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1213 va_start(arg_ptr, fmt);
1214 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1216 if (len < 0 || len >= (maxlen-5)) {
1217 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1223 Jmsg(jcr, type, mtime, "%s", pool_buf);
1224 free_memory(pool_buf);
1229 * Edit a message into a Pool memory buffer, with file:lineno
1231 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1236 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1239 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1240 va_start(arg_ptr, fmt);
1241 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1243 if (len < 0 || len >= (maxlen-5)) {
1244 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1252 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1257 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1260 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1261 va_start(arg_ptr, fmt);
1262 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1264 if (len < 0 || len >= (maxlen-5)) {
1265 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1275 * Edit a message into a Pool Memory buffer NO file:lineno
1276 * Returns: string length of what was edited.
1278 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1284 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1285 va_start(arg_ptr, fmt);
1286 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1288 if (len < 0 || len >= (maxlen-5)) {
1289 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1297 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1303 maxlen = sizeof_pool_memory(pool_buf) - 1;
1304 va_start(arg_ptr, fmt);
1305 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1307 if (len < 0 || len >= (maxlen-5)) {
1308 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1316 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1322 maxlen = pool_buf.max_size() - 1;
1323 va_start(arg_ptr, fmt);
1324 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1326 if (len < 0 || len >= (maxlen-5)) {
1327 pool_buf.realloc_pm(maxlen + maxlen/2);
1336 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1339 * We queue messages rather than print them directly. This
1340 * is generally used in low level routines (msg handler, bnet)
1341 * to prevent recursion (i.e. if you are in the middle of
1342 * sending a message, it is a bit messy to recursively call
1343 * yourself when the bnet packet is not reentrant).
1345 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1352 pool_buf = get_pool_memory(PM_EMSG);
1355 maxlen = sizeof_pool_memory(pool_buf) - 1;
1356 va_start(arg_ptr, fmt);
1357 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1359 if (len < 0 || len >= (maxlen-5)) {
1360 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1365 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1367 item->mtime = time(NULL);
1368 strcpy(item->msg, pool_buf);
1370 jcr = get_jcr_from_tsd();
1372 /* If no jcr or dequeuing send to daemon to avoid recursion */
1373 if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) {
1374 /* jcr==NULL => daemon message, safe to send now */
1375 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1378 /* Queue message for later sending */
1380 jcr->msg_queue->append(item);
1383 free_memory(pool_buf);
1389 void dequeue_messages(JCR *jcr)
1393 if (!jcr->msg_queue) {
1396 jcr->dequeuing = true;
1397 foreach_dlist(item, jcr->msg_queue) {
1398 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1400 jcr->msg_queue->destroy();
1401 jcr->dequeuing = false;
1409 * If we come here, prefix the message with the file:line-number,
1410 * then pass it on to the normal Qmsg routine.
1412 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1418 pool_buf = get_pool_memory(PM_EMSG);
1419 i = Mmsg(pool_buf, "%s:%d ", file, line);
1422 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1423 va_start(arg_ptr, fmt);
1424 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1426 if (len < 0 || len >= (maxlen-5)) {
1427 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1433 Qmsg(jcr, type, mtime, "%s", pool_buf);
1434 free_memory(pool_buf);