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 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 #define get_jcr_from_tsd() NULL
42 #define get_jobid_from_tsd() 0
44 sql_query p_sql_query = NULL;
45 sql_escape p_sql_escape = NULL;
47 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
50 * This is where we define "Globals" because all the
51 * daemons include this file.
53 const char *working_directory = NULL; /* working directory path stored here */
54 int verbose = 0; /* increase User messages */
55 /* Keep debug level set to zero by default */
56 int debug_level = 0; /* debug level */
57 bool dbg_timestamp = false; /* print timestamp in debug output */
58 time_t daemon_start_time = 0; /* Daemon start time */
59 const char *version = VERSION " (" BDATE ")";
60 char my_name[30]; /* daemon name is stored here */
61 char *exepath = (char *)NULL;
62 char *exename = (char *)NULL;
63 int console_msg_pending = false;
64 char con_fname[500]; /* Console filename */
65 FILE *con_fd = NULL; /* Console file descriptor */
66 brwlock_t con_lock; /* Console lock structure */
68 /* Forward referenced functions */
70 /* Imported functions */
75 /* Used to allow only one thread close the daemon messages at a time */
76 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
77 static MSGS *daemon_msgs; /* global messages */
78 static char *catalog_db = NULL; /* database type */
79 static void (*message_callback)(int type, char *msg) = NULL;
80 static FILE *trace_fd = NULL;
81 #if defined(HAVE_WIN32)
82 static bool trace = true;
84 static bool trace = false;
88 const char *host_os = HOST_OS;
89 const char *distname = DISTNAME;
90 const char *distver = DISTVER;
93 void register_message_callback(void msg_callback(int type, char *msg))
95 message_callback = msg_callback;
100 * Set daemon name. Also, find canonical execution
101 * path. Note, exepath has spare room for tacking on
102 * the exename so that we can reconstruct the full name.
104 * Note, this routine can get called multiple times
105 * The second time is to put the name as found in the
106 * Resource record. On the second call, generally,
107 * argv is NULL to avoid doing the path code twice.
109 void my_name_is(int argc, char *argv[], const char *name)
115 bstrncpy(my_name, name, sizeof(my_name));
116 if (argc>0 && argv && argv[0]) {
117 /* strip trailing filename and save exepath */
118 for (l=p=argv[0]; *p; p++) {
119 if (IsPathSeparator(*p)) {
120 l = p; /* set pos of last slash */
123 if (IsPathSeparator(*l)) {
127 #if defined(HAVE_WIN32)
128 /* On Windows allow c: junk */
138 exename = (char *)malloc(len);
144 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
145 for (p=argv[0],q=exepath; p < l; ) {
149 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
150 if (getcwd(cpath, sizeof(cpath))) {
152 exepath = (char *)malloc(strlen(cpath) + 1 + len);
153 strcpy(exepath, cpath);
156 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
163 return catalog_db != NULL ? catalog_db : "unknown";
167 set_db_type(const char *name)
169 if (catalog_db != NULL) {
172 catalog_db = bstrdup(name);
176 * Initialize message handler for a daemon or a Job
177 * We make a copy of the MSGS resource passed, so it belows
178 * to the job or daemon and thus can be modified.
180 * NULL for jcr -> initialize global messages for daemon
181 * non-NULL -> initialize jcr using Message resource
184 init_msg(JCR *jcr, MSGS *msg)
186 DEST *d, *dnew, *temp_chain = NULL;
189 if (jcr == NULL && msg == NULL) {
190 init_last_jobs_list();
193 #if !defined(HAVE_WIN32)
195 * Make sure we have fd's 0, 1, 2 open
196 * If we don't do this one of our sockets may open
197 * there and if we then use stdout, it could
198 * send total garbage to our socket.
202 fd = open("/dev/null", O_RDONLY, 0644);
206 for(i=1; fd + i <= 2; i++) {
213 * If msg is NULL, initialize global chain for STDOUT and syslog
216 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
217 memset(daemon_msgs, 0, sizeof(MSGS));
218 for (i=1; i<=M_MAX; i++) {
219 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
221 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
226 * Walk down the message resource chain duplicating it
227 * for the current Job.
229 for (d=msg->dest_chain; d; d=d->next) {
230 dnew = (DEST *)malloc(sizeof(DEST));
231 memcpy(dnew, d, sizeof(DEST));
232 dnew->next = temp_chain;
234 dnew->mail_filename = NULL;
236 dnew->mail_cmd = bstrdup(d->mail_cmd);
239 dnew->where = bstrdup(d->where);
245 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
246 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
247 jcr->jcr_msgs->dest_chain = temp_chain;
248 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
250 /* If we have default values, release them now */
252 free_msgs_res(daemon_msgs);
254 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
255 memset(daemon_msgs, 0, sizeof(MSGS));
256 daemon_msgs->dest_chain = temp_chain;
257 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
259 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
263 /* Initialize so that the console (User Agent) can
264 * receive messages -- stored in a file.
266 void init_console_msg(const char *wd)
270 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
271 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
274 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
275 con_fname, be.bstrerror());
277 if (lseek(fd, 0, SEEK_END) > 0) {
278 console_msg_pending = 1;
281 con_fd = fopen(con_fname, "a+b");
284 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
285 con_fname, be.bstrerror());
287 if (rwl_init(&con_lock) != 0) {
289 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
295 * Called only during parsing of the config file.
297 * Add a message destination. I.e. associate a message type with
298 * a destination (code).
299 * Note, where in the case of dest_code FILE is a filename,
300 * but in the case of MAIL is a space separated list of
301 * email addresses, ...
303 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
307 * First search the existing chain and see if we
308 * can simply add this msg_type to an existing entry.
310 for (d=msg->dest_chain; d; d=d->next) {
311 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
312 (strcmp(where, d->where) == 0))) {
313 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
314 d, msg_type, dest_code, NPRT(where));
315 set_bit(msg_type, d->msg_types);
316 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
320 /* Not found, create a new entry */
321 d = (DEST *)malloc(sizeof(DEST));
322 memset(d, 0, sizeof(DEST));
323 d->next = msg->dest_chain;
324 d->dest_code = dest_code;
325 set_bit(msg_type, d->msg_types); /* set type bit in structure */
326 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
328 d->where = bstrdup(where);
331 d->mail_cmd = bstrdup(mail_cmd);
333 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
334 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
339 * Called only during parsing of the config file.
341 * Remove a message destination
343 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
347 for (d=msg->dest_chain; d; d=d->next) {
348 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
349 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
350 ((where == NULL && d->where == NULL) ||
351 (strcmp(where, d->where) == 0))) {
352 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
353 d, msg_type, dest_code);
354 clear_bit(msg_type, d->msg_types);
355 Dmsg0(850, "Return rem_msg_dest\n");
363 * Create a unique filename for the mail command
365 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
368 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
369 jcr->Job, (int)(long)d);
371 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
372 my_name, (int)(long)d);
374 Dmsg1(850, "mailname=%s\n", name);
380 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
385 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
387 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
391 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
393 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
394 cmd, be.bstrerror());
397 /* If we had to use sendmail, add subject */
399 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
406 * Close the messages for this Messages resource, which means to close
407 * any open files, and dispatch any pending email messages.
409 void close_msg(JCR *jcr)
417 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
419 if (jcr == NULL) { /* NULL -> global chain */
421 P(mutex); /* only one thread walking the chain */
423 msgs = jcr->jcr_msgs;
424 jcr->jcr_msgs = NULL;
429 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
430 cmd = get_pool_memory(PM_MESSAGE);
431 for (d=msgs->dest_chain; d; ) {
433 switch (d->dest_code) {
437 fclose(d->fd); /* close open file descriptor */
442 case MD_MAIL_ON_ERROR:
443 case MD_MAIL_ON_SUCCESS:
444 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
449 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
450 jcr->JobStatus == JS_Terminated)
452 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
453 jcr->JobStatus == JS_ErrorTerminated)
458 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
459 Pmsg0(000, _("open mail pipe failed.\n"));
462 Dmsg0(850, "Opened mail pipe\n");
464 line = get_memory(len);
466 while (fgets(line, len, d->fd)) {
467 fputs(line, bpipe->wfd);
469 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
471 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
475 * Since we are closing all messages, before "recursing"
476 * make sure we are not closing the daemon messages, otherwise
479 if (msgs != daemon_msgs) {
480 /* read what mail prog returned -- should be nothing */
481 while (fgets(line, len, bpipe->rfd)) {
482 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
486 stat = close_bpipe(bpipe);
487 if (stat != 0 && msgs != daemon_msgs) {
490 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
491 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
493 "ERR=%s\n"), cmd, be.bstrerror());
497 /* Remove temp file */
500 unlink(d->mail_filename);
501 free_pool_memory(d->mail_filename);
502 d->mail_filename = NULL;
503 Dmsg0(850, "end mail or mail on error\n");
510 d = d->next; /* point to next buffer */
512 free_pool_memory(cmd);
513 Dmsg0(850, "Done walking message chain.\n");
520 Dmsg0(850, "===End close msg resource\n");
524 * Free memory associated with Messages resource
526 void free_msgs_res(MSGS *msgs)
530 /* Walk down the message chain releasing allocated buffers */
531 for (d=msgs->dest_chain; d; ) {
538 old = d; /* save pointer to release */
539 d = d->next; /* point to next buffer */
540 free(old); /* free the destination item */
542 msgs->dest_chain = NULL;
543 free(msgs); /* free the head */
548 * Terminate the message handler for good.
549 * Release the global destination chain.
551 * Also, clean up a few other items (cons, exepath). Note,
552 * these really should be done elsewhere.
556 Dmsg0(850, "Enter term_msg\n");
557 close_msg(NULL); /* close global chain */
558 free_msgs_res(daemon_msgs); /* free the resources */
581 term_last_jobs_list();
584 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
586 d->fd = fopen(d->where, mode);
590 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
598 * Handle sending the message to the appropriate place
600 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
603 char dt[MAX_TIME_LENGTH];
610 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
613 * Most messages are prefixed by a date and time. If mtime is
614 * zero, then we use the current time. If mtime is 1 (special
615 * kludge), we do not prefix the date and time. Otherwise,
616 * we assume mtime is a time_t and use it.
625 bstrftime_ny(dt, sizeof(dt), mtime);
631 /* If the program registered a callback, send it there */
632 if (message_callback) {
633 message_callback(type, msg);
637 if (type == M_ABORT || type == M_ERROR_TERM) {
639 fputs(msg, stdout); /* print this here to INSURE that it is printed */
644 /* Now figure out where to send the message */
647 jcr = get_jcr_from_tsd();
650 msgs = jcr->jcr_msgs;
655 for (d=msgs->dest_chain; d; d=d->next) {
656 if (bit_is_set(type, d->msg_types)) {
657 switch (d->dest_code) {
660 if (!jcr || !jcr->db) {
663 if (p_sql_query && p_sql_escape) {
664 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
665 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
667 int len = strlen(msg) + 1;
668 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
669 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
671 bstrutime(dt, sizeof(dt), mtime);
672 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
673 edit_int64(jcr->JobId, ed1), dt, esc_msg);
674 p_sql_query(jcr, cmd);
676 free_pool_memory(cmd);
677 free_pool_memory(esc_msg);
681 Dmsg1(850, "CONSOLE for following msg: %s", msg);
683 con_fd = fopen(con_fname, "a+b");
684 Dmsg0(850, "Console file not open.\n");
687 Pw(con_lock); /* get write lock on console message file */
690 (void)fwrite(dt, dtlen, 1, con_fd);
694 (void)fwrite(msg, len, 1, con_fd);
695 if (msg[len-1] != '\n') {
696 (void)fwrite("\n", 2, 1, con_fd);
699 (void)fwrite("\n", 2, 1, con_fd);
702 console_msg_pending = true;
707 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
709 * We really should do an openlog() here.
711 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
714 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
715 mcmd = get_pool_memory(PM_MESSAGE);
716 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
718 fputs(dt, bpipe->wfd);
719 fputs(msg, bpipe->wfd);
720 /* Messages to the operator go one at a time */
721 stat = close_bpipe(bpipe);
725 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
727 "ERR=%s\n"), mcmd, be.bstrerror());
730 free_pool_memory(mcmd);
733 case MD_MAIL_ON_ERROR:
734 case MD_MAIL_ON_SUCCESS:
735 Dmsg1(850, "MAIL for following msg: %s", msg);
737 POOLMEM *name = get_pool_memory(PM_MESSAGE);
738 make_unique_mail_filename(jcr, name, d);
739 d->fd = fopen(name, "w+b");
743 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
746 free_pool_memory(name);
749 d->mail_filename = name;
752 len = strlen(msg) + dtlen;;
753 if (len > d->max_len) {
754 d->max_len = len; /* keep max line length */
759 Dmsg1(850, "APPEND for following msg: %s", msg);
763 Dmsg1(850, "FILE for following msg: %s", msg);
766 if (!d->fd && !open_dest_file(jcr, d, mode)) {
771 /* On error, we close and reopen to handle log rotation */
775 if (open_dest_file(jcr, d, mode)) {
782 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
783 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
784 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
785 jcr->Job, type, mtime, msg);
789 Dmsg1(850, "STDOUT for following msg: %s", msg);
790 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
797 Dmsg1(850, "STDERR for following msg: %s", msg);
809 /*********************************************************************
811 * This subroutine returns the filename portion of a Windows
812 * path. It is used because Microsoft Visual Studio sets __FILE__
817 get_basename(const char *pathname)
819 #if defined(_MSC_VER)
820 const char *basename;
822 if ((basename = strrchr(pathname, '\\')) == NULL) {
834 /*********************************************************************
836 * This subroutine prints a debug message if the level number
837 * is less than or equal the debug_level. File and line numbers
838 * are included for more detail if desired, but not currently
841 * If the level is negative, the details of file and line number
845 d_msg(const char *file, int line, int level, const char *fmt,...)
857 if (level <= debug_level) {
860 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
861 my_name, get_basename(file), line, get_jobid_from_tsd());
868 va_start(arg_ptr, fmt);
869 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
873 * Used the "trace on" command in the console to turn on
874 * output to the trace file. "trace off" will close the file.
879 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
880 trace_fd = fopen(fn, "a+b");
883 fputs(buf, trace_fd);
886 /* Some problem, turn off tracing */
889 } else { /* not tracing */
897 * Set trace flag on/off. If argument is negative, there is no change
899 void set_trace(int trace_flag)
901 if (trace_flag < 0) {
903 } else if (trace_flag > 0) {
908 if (!trace && trace_fd) {
909 FILE *ltrace_fd = trace_fd;
911 bmicrosleep(0, 100000); /* yield to prevent seg faults */
921 /*********************************************************************
923 * This subroutine prints a message regardless of the debug level
925 * If the level is negative, the details of file and line number
929 p_msg(const char *file, int line, int level, const char *fmt,...)
937 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
944 va_start(arg_ptr, fmt);
945 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
952 /*********************************************************************
954 * subroutine writes a debug message to the trace file if the level number
955 * is less than or equal the debug_level. File and line numbers
956 * are included for more detail if desired, but not currently
959 * If the level is negative, the details of file and line number
963 t_msg(const char *file, int line, int level, const char *fmt,...)
975 if (level <= debug_level) {
977 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
978 trace_fd = fopen(buf, "a+b");
983 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
990 va_start(arg_ptr, fmt);
991 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
993 if (trace_fd != NULL) {
994 fputs(buf, trace_fd);
1002 /* *********************************************************
1004 * print an error message
1008 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1015 * Check if we have a message destination defined.
1016 * We always report M_ABORT and M_ERROR_TERM
1018 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1019 !bit_is_set(type, daemon_msgs->send_msg))) {
1020 return; /* no destination */
1024 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1025 my_name, get_basename(file), line);
1028 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1029 my_name, get_basename(file), line);
1032 if (level == -1) /* skip details */
1033 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1035 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1038 if (level == -1) /* skip details */
1039 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1041 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1044 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1047 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1050 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1054 va_start(arg_ptr, fmt);
1055 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1058 dispatch_message(NULL, type, 0, buf);
1060 if (type == M_ABORT) {
1062 p[0] = 0; /* generate segmentation violation */
1064 if (type == M_ERROR_TERM) {
1069 /* *********************************************************
1071 * Generate a Job message
1075 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1084 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1086 /* Special case for the console, which has a dir_bsock and JobId==0,
1087 * in that case, we send the message directly back to the
1090 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1091 BSOCK *dir = jcr->dir_bsock;
1092 va_start(arg_ptr, fmt);
1093 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1096 jcr->dir_bsock->send();
1102 jcr = get_jcr_from_tsd();
1105 msgs = jcr->jcr_msgs;
1109 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1113 * Check if we have a message destination defined.
1114 * We always report M_ABORT and M_ERROR_TERM
1116 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1117 !bit_is_set(type, msgs->send_msg)) {
1118 return; /* no destination */
1122 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1125 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1128 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1130 set_jcr_job_status(jcr, JS_FatalError);
1134 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1140 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1143 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1147 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1151 va_start(arg_ptr, fmt);
1152 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1155 dispatch_message(jcr, type, mtime, rbuf);
1157 if (type == M_ABORT){
1159 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1160 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1161 p[0] = 0; /* generate segmentation violation */
1163 if (type == M_ERROR_TERM) {
1169 * If we come here, prefix the message with the file:line-number,
1170 * then pass it on to the normal Jmsg routine.
1172 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1178 pool_buf = get_pool_memory(PM_EMSG);
1179 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1182 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1183 va_start(arg_ptr, fmt);
1184 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1186 if (len < 0 || len >= (maxlen-5)) {
1187 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1193 Jmsg(jcr, type, mtime, "%s", pool_buf);
1194 free_memory(pool_buf);
1199 * Edit a message into a Pool memory buffer, with file:lineno
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);
1222 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1227 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1230 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1231 va_start(arg_ptr, fmt);
1232 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1234 if (len < 0 || len >= (maxlen-5)) {
1235 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1245 * Edit a message into a Pool Memory buffer NO file:lineno
1246 * Returns: string length of what was edited.
1248 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1254 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1255 va_start(arg_ptr, fmt);
1256 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1258 if (len < 0 || len >= (maxlen-5)) {
1259 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1267 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1273 maxlen = sizeof_pool_memory(pool_buf) - 1;
1274 va_start(arg_ptr, fmt);
1275 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1277 if (len < 0 || len >= (maxlen-5)) {
1278 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1286 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1292 maxlen = pool_buf.max_size() - 1;
1293 va_start(arg_ptr, fmt);
1294 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1296 if (len < 0 || len >= (maxlen-5)) {
1297 pool_buf.realloc_pm(maxlen + maxlen/2);
1306 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1309 * We queue messages rather than print them directly. This
1310 * is generally used in low level routines (msg handler, bnet)
1311 * to prevent recursion (i.e. if you are in the middle of
1312 * sending a message, it is a bit messy to recursively call
1313 * yourself when the bnet packet is not reentrant).
1315 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1322 pool_buf = get_pool_memory(PM_EMSG);
1325 maxlen = sizeof_pool_memory(pool_buf) - 1;
1326 va_start(arg_ptr, fmt);
1327 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1329 if (len < 0 || len >= (maxlen-5)) {
1330 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1335 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1337 item->mtime = time(NULL);
1338 strcpy(item->msg, pool_buf);
1340 jcr = get_jcr_from_tsd();
1342 /* If no jcr or dequeuing send to daemon to avoid recursion */
1343 if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) {
1344 /* jcr==NULL => daemon message, safe to send now */
1345 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1348 /* Queue message for later sending */
1350 jcr->msg_queue->append(item);
1353 free_memory(pool_buf);
1359 void dequeue_messages(JCR *jcr)
1363 if (!jcr->msg_queue) {
1366 jcr->dequeuing = true;
1367 foreach_dlist(item, jcr->msg_queue) {
1368 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1370 jcr->msg_queue->destroy();
1371 jcr->dequeuing = false;
1379 * If we come here, prefix the message with the file:line-number,
1380 * then pass it on to the normal Qmsg routine.
1382 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1388 pool_buf = get_pool_memory(PM_EMSG);
1389 i = Mmsg(pool_buf, "%s:%d ", file, line);
1392 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1393 va_start(arg_ptr, fmt);
1394 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1396 if (len < 0 || len >= (maxlen-5)) {
1397 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1403 Qmsg(jcr, type, mtime, "%s", pool_buf);
1404 free_memory(pool_buf);