2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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
38 sql_query p_sql_query = NULL;
39 sql_escape p_sql_escape = NULL;
41 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
44 * This is where we define "Globals" because all the
45 * daemons include this file.
47 const char *working_directory = NULL; /* working directory path stored here */
48 int verbose = 0; /* increase User messages */
49 int debug_level = 0; /* debug level */
50 bool dbg_timestamp = false; /* print timestamp in debug output */
51 bool prt_kaboom = false; /* Print kaboom output */
52 utime_t daemon_start_time = 0; /* Daemon start time */
53 const char *version = VERSION " (" BDATE ")";
54 char my_name[30]; /* daemon name is stored here */
55 char host_name[50]; /* host machine name */
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 /* Forward referenced functions */
65 /* Imported functions */
66 void create_jcr_key();
70 /* Allow only one thread to tweak d->fd at a time */
71 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
72 static MSGS *daemon_msgs; /* global messages */
73 static char *catalog_db = NULL; /* database type */
74 static void (*message_callback)(int type, char *msg) = NULL;
75 static FILE *trace_fd = NULL;
76 #if defined(HAVE_WIN32)
77 static bool trace = true;
79 static bool trace = false;
83 const char *host_os = HOST_OS;
84 const char *distname = DISTNAME;
85 const char *distver = DISTVER;
88 void register_message_callback(void msg_callback(int type, char *msg))
90 message_callback = msg_callback;
95 * Set daemon name. Also, find canonical execution
96 * path. Note, exepath has spare room for tacking on
97 * the exename so that we can reconstruct the full name.
99 * Note, this routine can get called multiple times
100 * The second time is to put the name as found in the
101 * Resource record. On the second call, generally,
102 * argv is NULL to avoid doing the path code twice.
104 void my_name_is(int argc, char *argv[], const char *name)
110 if (gethostname(host_name, sizeof(host_name)) != 0) {
111 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
113 bstrncpy(my_name, name, sizeof(my_name));
114 if (argc>0 && argv && argv[0]) {
115 /* strip trailing filename and save exepath */
116 for (l=p=argv[0]; *p; p++) {
117 if (IsPathSeparator(*p)) {
118 l = p; /* set pos of last slash */
121 if (IsPathSeparator(*l)) {
125 #if defined(HAVE_WIN32)
126 /* On Windows allow c: junk */
136 exename = (char *)malloc(len);
142 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
143 for (p=argv[0],q=exepath; p < l; ) {
147 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
148 if (getcwd(cpath, sizeof(cpath))) {
150 exepath = (char *)malloc(strlen(cpath) + 1 + len);
151 strcpy(exepath, cpath);
154 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
161 return catalog_db != NULL ? catalog_db : "unknown";
165 set_db_type(const char *name)
167 if (catalog_db != NULL) {
170 catalog_db = bstrdup(name);
174 * Initialize message handler for a daemon or a Job
175 * We make a copy of the MSGS resource passed, so it belows
176 * to the job or daemon and thus can be modified.
178 * NULL for jcr -> initialize global messages for daemon
179 * non-NULL -> initialize jcr using Message resource
182 init_msg(JCR *jcr, MSGS *msg)
184 DEST *d, *dnew, *temp_chain = NULL;
187 if (jcr == NULL && msg == NULL) {
188 init_last_jobs_list();
189 /* Create a daemon key then set invalid jcr */
190 /* Maybe we should give the daemon a jcr??? */
192 set_jcr_in_tsd(INVALID_JCR);
195 #if !defined(HAVE_WIN32)
197 * Make sure we have fd's 0, 1, 2 open
198 * If we don't do this one of our sockets may open
199 * there and if we then use stdout, it could
200 * send total garbage to our socket.
204 fd = open("/dev/null", O_RDONLY, 0644);
208 for(i=1; fd + i <= 2; i++) {
215 * If msg is NULL, initialize global chain for STDOUT and syslog
218 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
219 memset(daemon_msgs, 0, sizeof(MSGS));
220 for (i=1; i<=M_MAX; i++) {
221 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
223 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
228 * Walk down the message resource chain duplicating it
229 * for the current Job.
231 for (d=msg->dest_chain; d; d=d->next) {
232 dnew = (DEST *)malloc(sizeof(DEST));
233 memcpy(dnew, d, sizeof(DEST));
234 dnew->next = temp_chain;
236 dnew->mail_filename = NULL;
238 dnew->mail_cmd = bstrdup(d->mail_cmd);
241 dnew->where = bstrdup(d->where);
247 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
248 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
249 jcr->jcr_msgs->dest_chain = temp_chain;
250 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
252 /* If we have default values, release them now */
254 free_msgs_res(daemon_msgs);
256 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
257 memset(daemon_msgs, 0, sizeof(MSGS));
258 daemon_msgs->dest_chain = temp_chain;
259 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
261 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
265 /* Initialize so that the console (User Agent) can
266 * receive messages -- stored in a file.
268 void init_console_msg(const char *wd)
272 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
273 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
276 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
277 con_fname, be.bstrerror());
279 if (lseek(fd, 0, SEEK_END) > 0) {
280 console_msg_pending = 1;
283 con_fd = fopen(con_fname, "a+b");
286 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
287 con_fname, be.bstrerror());
289 if (rwl_init(&con_lock) != 0) {
291 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
297 * Called only during parsing of the config file.
299 * Add a message destination. I.e. associate a message type with
300 * a destination (code).
301 * Note, where in the case of dest_code FILE is a filename,
302 * but in the case of MAIL is a space separated list of
303 * email addresses, ...
305 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
309 * First search the existing chain and see if we
310 * can simply add this msg_type to an existing entry.
312 for (d=msg->dest_chain; d; d=d->next) {
313 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
314 (strcmp(where, d->where) == 0))) {
315 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
316 d, msg_type, dest_code, NPRT(where));
317 set_bit(msg_type, d->msg_types);
318 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
322 /* Not found, create a new entry */
323 d = (DEST *)malloc(sizeof(DEST));
324 memset(d, 0, sizeof(DEST));
325 d->next = msg->dest_chain;
326 d->dest_code = dest_code;
327 set_bit(msg_type, d->msg_types); /* set type bit in structure */
328 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
330 d->where = bstrdup(where);
333 d->mail_cmd = bstrdup(mail_cmd);
335 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
336 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
341 * Called only during parsing of the config file.
343 * Remove a message destination
345 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
349 for (d=msg->dest_chain; d; d=d->next) {
350 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
351 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
352 ((where == NULL && d->where == NULL) ||
353 (strcmp(where, d->where) == 0))) {
354 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
355 d, msg_type, dest_code);
356 clear_bit(msg_type, d->msg_types);
357 Dmsg0(850, "Return rem_msg_dest\n");
365 * Create a unique filename for the mail command
367 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
370 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
371 jcr->Job, (int)(intptr_t)d);
373 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
374 my_name, (int)(intptr_t)d);
376 Dmsg1(850, "mailname=%s\n", name);
382 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
387 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
389 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
393 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
394 /* If we had to use sendmail, add subject */
396 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
400 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
401 cmd, be.bstrerror());
407 * Close the messages for this Messages resource, which means to close
408 * any open files, and dispatch any pending email messages.
410 void close_msg(JCR *jcr)
418 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
420 if (jcr == NULL) { /* NULL -> global chain */
423 msgs = jcr->jcr_msgs;
424 jcr->jcr_msgs = NULL;
430 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
431 cmd = get_pool_memory(PM_MESSAGE);
432 for (d=msgs->dest_chain; d; ) {
434 switch (d->dest_code) {
438 fclose(d->fd); /* close open file descriptor */
443 case MD_MAIL_ON_ERROR:
444 case MD_MAIL_ON_SUCCESS:
445 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
450 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
451 (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
453 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
454 jcr->JobStatus == JS_ErrorTerminated)
459 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
460 Pmsg0(000, _("open mail pipe failed.\n"));
463 Dmsg0(850, "Opened mail pipe\n");
465 line = get_memory(len);
467 while (fgets(line, len, d->fd)) {
468 fputs(line, bpipe->wfd);
470 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
472 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
476 * Since we are closing all messages, before "recursing"
477 * make sure we are not closing the daemon messages, otherwise
480 if (msgs != daemon_msgs) {
481 /* read what mail prog returned -- should be nothing */
482 while (fgets(line, len, bpipe->rfd)) {
483 Qmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
487 stat = close_bpipe(bpipe);
488 if (stat != 0 && msgs != daemon_msgs) {
491 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
492 Qmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
494 "ERR=%s\n"), cmd, be.bstrerror());
498 /* Remove temp file */
501 unlink(d->mail_filename);
502 free_pool_memory(d->mail_filename);
503 d->mail_filename = NULL;
504 Dmsg0(850, "end mail or mail on error\n");
511 d = d->next; /* point to next buffer */
514 free_pool_memory(cmd);
515 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, utime_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 utime_t and use it.
624 mtime = time(NULL); /* get time for SQL log */
626 bstrftime_ny(dt, sizeof(dt), mtime);
632 /* If the program registered a callback, send it there */
633 if (message_callback) {
634 message_callback(type, msg);
638 if (type == M_ABORT || type == M_ERROR_TERM) {
640 fputs(msg, stdout); /* print this here to INSURE that it is printed */
642 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
646 /* Now figure out where to send the message */
649 jcr = get_jcr_from_tsd();
652 msgs = jcr->jcr_msgs;
657 for (d=msgs->dest_chain; d; d=d->next) {
658 if (bit_is_set(type, d->msg_types)) {
659 switch (d->dest_code) {
662 if (!jcr || !jcr->db) {
665 if (p_sql_query && p_sql_escape) {
666 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
667 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
669 int len = strlen(msg) + 1;
670 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
671 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
673 bstrutime(dt, sizeof(dt), mtime);
674 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
675 edit_int64(jcr->JobId, ed1), dt, esc_msg);
676 p_sql_query(jcr, cmd);
678 free_pool_memory(cmd);
679 free_pool_memory(esc_msg);
683 Dmsg1(850, "CONSOLE for following msg: %s", msg);
685 con_fd = fopen(con_fname, "a+b");
686 Dmsg0(850, "Console file not open.\n");
689 Pw(con_lock); /* get write lock on console message file */
692 (void)fwrite(dt, dtlen, 1, con_fd);
696 (void)fwrite(msg, len, 1, con_fd);
697 if (msg[len-1] != '\n') {
698 (void)fwrite("\n", 2, 1, con_fd);
701 (void)fwrite("\n", 2, 1, con_fd);
704 console_msg_pending = true;
709 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
711 * We really should do an openlog() here.
713 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
716 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
717 mcmd = get_pool_memory(PM_MESSAGE);
718 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
720 fputs(dt, bpipe->wfd);
721 fputs(msg, bpipe->wfd);
722 /* Messages to the operator go one at a time */
723 stat = close_bpipe(bpipe);
727 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
729 "ERR=%s\n"), mcmd, be.bstrerror());
732 free_pool_memory(mcmd);
735 case MD_MAIL_ON_ERROR:
736 case MD_MAIL_ON_SUCCESS:
737 Dmsg1(850, "MAIL for following msg: %s", msg);
740 POOLMEM *name = get_pool_memory(PM_MESSAGE);
741 make_unique_mail_filename(jcr, name, d);
742 d->fd = fopen(name, "w+b");
746 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
749 free_pool_memory(name);
753 d->mail_filename = name;
756 len = strlen(msg) + dtlen;;
757 if (len > d->max_len) {
758 d->max_len = len; /* keep max line length */
764 Dmsg1(850, "APPEND for following msg: %s", msg);
768 Dmsg1(850, "FILE for following msg: %s", msg);
772 if (!d->fd && !open_dest_file(jcr, d, mode)) {
778 /* On error, we close and reopen to handle log rotation */
782 if (open_dest_file(jcr, d, mode)) {
790 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
791 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
792 jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
793 jcr->Job, type, mtime, msg);
795 Dmsg1(800, "no jcr for following msg: %s", msg);
799 Dmsg1(850, "STDOUT for following msg: %s", msg);
800 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
807 Dmsg1(850, "STDERR for following msg: %s", msg);
819 /*********************************************************************
821 * This subroutine returns the filename portion of a Windows
822 * path. It is used because Microsoft Visual Studio sets __FILE__
827 get_basename(const char *pathname)
829 #if defined(_MSC_VER)
830 const char *basename;
832 if ((basename = strrchr(pathname, '\\')) == NULL) {
845 * print or write output to trace file
847 static void pt_out(char *buf)
850 * Used the "trace on" command in the console to turn on
851 * output to the trace file. "trace off" will close the file.
856 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
857 trace_fd = fopen(fn, "a+b");
860 fputs(buf, trace_fd);
863 /* Some problem, turn off tracing */
866 } else { /* not tracing */
872 /*********************************************************************
874 * This subroutine prints a debug message if the level number
875 * is less than or equal the debug_level. File and line numbers
876 * are included for more detail if desired, but not currently
879 * If the level is negative, the details of file and line number
883 d_msg(const char *file, int line, int level, const char *fmt,...)
896 if (level <= debug_level) {
899 bstrftimes(buf, sizeof(buf), mtime);
908 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
909 my_name, get_basename(file), line, get_jobid_from_tsd());
916 va_start(arg_ptr, fmt);
917 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
925 * Set trace flag on/off. If argument is negative, there is no change
927 void set_trace(int trace_flag)
929 if (trace_flag < 0) {
931 } else if (trace_flag > 0) {
936 if (!trace && trace_fd) {
937 FILE *ltrace_fd = trace_fd;
939 bmicrosleep(0, 100000); /* yield to prevent seg faults */
949 /*********************************************************************
951 * This subroutine prints a message regardless of the debug level
953 * If the level is negative, the details of file and line number
957 p_msg(const char *file, int line, int level, const char *fmt,...)
965 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
972 va_start(arg_ptr, fmt);
973 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
980 /*********************************************************************
982 * subroutine writes a debug message to the trace file if the level number
983 * is less than or equal the debug_level. File and line numbers
984 * are included for more detail if desired, but not currently
987 * If the level is negative, the details of file and line number
991 t_msg(const char *file, int line, int level, const char *fmt,...)
1003 if (level <= debug_level) {
1005 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1006 trace_fd = fopen(buf, "a+b");
1009 #ifdef FULL_LOCATION
1011 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1018 va_start(arg_ptr, fmt);
1019 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1021 if (trace_fd != NULL) {
1022 fputs(buf, trace_fd);
1028 /* *********************************************************
1030 * print an error message
1034 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1041 * Check if we have a message destination defined.
1042 * We always report M_ABORT and M_ERROR_TERM
1044 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1045 !bit_is_set(type, daemon_msgs->send_msg))) {
1046 return; /* no destination */
1050 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1051 my_name, get_basename(file), line);
1054 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1055 my_name, get_basename(file), line);
1058 if (level == -1) /* skip details */
1059 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1061 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1064 if (level == -1) /* skip details */
1065 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1067 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1070 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1073 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1076 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1080 va_start(arg_ptr, fmt);
1081 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1084 dispatch_message(NULL, type, 0, buf);
1086 if (type == M_ABORT) {
1088 p[0] = 0; /* generate segmentation violation */
1090 if (type == M_ERROR_TERM) {
1095 /* *********************************************************
1097 * Generate a Job message
1101 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1110 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1112 /* Special case for the console, which has a dir_bsock and JobId==0,
1113 * in that case, we send the message directly back to the
1116 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1117 BSOCK *dir = jcr->dir_bsock;
1118 va_start(arg_ptr, fmt);
1119 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1122 jcr->dir_bsock->send();
1128 jcr = get_jcr_from_tsd();
1131 msgs = jcr->jcr_msgs;
1135 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1139 * Check if we have a message destination defined.
1140 * We always report M_ABORT and M_ERROR_TERM
1142 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1143 !bit_is_set(type, msgs->send_msg)) {
1144 return; /* no destination */
1148 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1151 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1154 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1156 set_jcr_job_status(jcr, JS_FatalError);
1160 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1166 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1172 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1176 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1180 va_start(arg_ptr, fmt);
1181 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1184 dispatch_message(jcr, type, mtime, rbuf);
1186 if (type == M_ABORT){
1188 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1189 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1190 p[0] = 0; /* generate segmentation violation */
1192 if (type == M_ERROR_TERM) {
1198 * If we come here, prefix the message with the file:line-number,
1199 * then pass it on to the normal Jmsg routine.
1201 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1207 pool_buf = get_pool_memory(PM_EMSG);
1208 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1211 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1212 va_start(arg_ptr, fmt);
1213 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1215 if (len < 0 || len >= (maxlen-5)) {
1216 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1222 Jmsg(jcr, type, mtime, "%s", pool_buf);
1223 free_memory(pool_buf);
1228 * Edit a message into a Pool memory buffer, with file:lineno
1230 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1235 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1238 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1239 va_start(arg_ptr, fmt);
1240 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1242 if (len < 0 || len >= (maxlen-5)) {
1243 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1251 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1256 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1259 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1260 va_start(arg_ptr, fmt);
1261 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1263 if (len < 0 || len >= (maxlen-5)) {
1264 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1274 * Edit a message into a Pool Memory buffer NO file:lineno
1275 * Returns: string length of what was edited.
1277 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1283 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1284 va_start(arg_ptr, fmt);
1285 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1287 if (len < 0 || len >= (maxlen-5)) {
1288 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1296 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1302 maxlen = sizeof_pool_memory(pool_buf) - 1;
1303 va_start(arg_ptr, fmt);
1304 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1306 if (len < 0 || len >= (maxlen-5)) {
1307 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1315 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1321 maxlen = pool_buf.max_size() - 1;
1322 va_start(arg_ptr, fmt);
1323 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1325 if (len < 0 || len >= (maxlen-5)) {
1326 pool_buf.realloc_pm(maxlen + maxlen/2);
1336 * We queue messages rather than print them directly. This
1337 * is generally used in low level routines (msg handler, bnet)
1338 * to prevent recursion (i.e. if you are in the middle of
1339 * sending a message, it is a bit messy to recursively call
1340 * yourself when the bnet packet is not reentrant).
1342 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1349 pool_buf = get_pool_memory(PM_EMSG);
1352 maxlen = sizeof_pool_memory(pool_buf) - 1;
1353 va_start(arg_ptr, fmt);
1354 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1356 if (len < 0 || len >= (maxlen-5)) {
1357 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1362 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1364 item->mtime = time(NULL);
1365 strcpy(item->msg, pool_buf);
1367 jcr = get_jcr_from_tsd();
1369 /* If no jcr or no queue or dequeuing send to syslog */
1370 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1371 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1374 /* Queue message for later sending */
1375 P(jcr->msg_queue_mutex);
1376 jcr->msg_queue->append(item);
1377 V(jcr->msg_queue_mutex);
1379 free_memory(pool_buf);
1385 void dequeue_messages(JCR *jcr)
1388 if (!jcr->msg_queue) {
1391 P(jcr->msg_queue_mutex);
1392 jcr->dequeuing_msgs = true;
1393 foreach_dlist(item, jcr->msg_queue) {
1394 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1396 /* Remove messages just sent */
1397 jcr->msg_queue->destroy();
1398 jcr->dequeuing_msgs = false;
1399 V(jcr->msg_queue_mutex);
1404 * If we come here, prefix the message with the file:line-number,
1405 * then pass it on to the normal Qmsg routine.
1407 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1413 pool_buf = get_pool_memory(PM_EMSG);
1414 i = Mmsg(pool_buf, "%s:%d ", file, line);
1417 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1418 va_start(arg_ptr, fmt);
1419 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1421 if (len < 0 || len >= (maxlen-5)) {
1422 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1428 Qmsg(jcr, type, mtime, "%s", pool_buf);
1429 free_memory(pool_buf);