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 utime_t daemon_start_time = 0; /* Daemon start time */
52 const char *version = VERSION " (" BDATE ")";
53 char my_name[30]; /* daemon name is stored here */
54 char host_name[50]; /* host machine name */
55 char *exepath = (char *)NULL;
56 char *exename = (char *)NULL;
57 int console_msg_pending = false;
58 char con_fname[500]; /* Console filename */
59 FILE *con_fd = NULL; /* Console file descriptor */
60 brwlock_t con_lock; /* Console lock structure */
62 /* Forward referenced functions */
64 /* Imported functions */
65 void create_jcr_key();
69 /* Allow only one thread to tweak d->fd at a time */
70 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
71 static MSGS *daemon_msgs; /* global messages */
72 static char *catalog_db = NULL; /* database type */
73 static void (*message_callback)(int type, char *msg) = NULL;
74 static FILE *trace_fd = NULL;
75 #if defined(HAVE_WIN32)
76 static bool trace = true;
78 static bool trace = false;
82 const char *host_os = HOST_OS;
83 const char *distname = DISTNAME;
84 const char *distver = DISTVER;
87 void register_message_callback(void msg_callback(int type, char *msg))
89 message_callback = msg_callback;
94 * Set daemon name. Also, find canonical execution
95 * path. Note, exepath has spare room for tacking on
96 * the exename so that we can reconstruct the full name.
98 * Note, this routine can get called multiple times
99 * The second time is to put the name as found in the
100 * Resource record. On the second call, generally,
101 * argv is NULL to avoid doing the path code twice.
103 void my_name_is(int argc, char *argv[], const char *name)
109 if (gethostname(host_name, sizeof(host_name)) != 0) {
110 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
112 bstrncpy(my_name, name, sizeof(my_name));
113 if (argc>0 && argv && argv[0]) {
114 /* strip trailing filename and save exepath */
115 for (l=p=argv[0]; *p; p++) {
116 if (IsPathSeparator(*p)) {
117 l = p; /* set pos of last slash */
120 if (IsPathSeparator(*l)) {
124 #if defined(HAVE_WIN32)
125 /* On Windows allow c: junk */
135 exename = (char *)malloc(len);
141 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
142 for (p=argv[0],q=exepath; p < l; ) {
146 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
147 if (getcwd(cpath, sizeof(cpath))) {
149 exepath = (char *)malloc(strlen(cpath) + 1 + len);
150 strcpy(exepath, cpath);
153 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
160 return catalog_db != NULL ? catalog_db : "unknown";
164 set_db_type(const char *name)
166 if (catalog_db != NULL) {
169 catalog_db = bstrdup(name);
173 * Initialize message handler for a daemon or a Job
174 * We make a copy of the MSGS resource passed, so it belows
175 * to the job or daemon and thus can be modified.
177 * NULL for jcr -> initialize global messages for daemon
178 * non-NULL -> initialize jcr using Message resource
181 init_msg(JCR *jcr, MSGS *msg)
183 DEST *d, *dnew, *temp_chain = NULL;
186 if (jcr == NULL && msg == NULL) {
187 init_last_jobs_list();
188 /* Create a daemon key then set invalid jcr */
189 /* Maybe we should give the daemon a jcr??? */
191 set_jcr_in_tsd(INVALID_JCR);
194 #if !defined(HAVE_WIN32)
196 * Make sure we have fd's 0, 1, 2 open
197 * If we don't do this one of our sockets may open
198 * there and if we then use stdout, it could
199 * send total garbage to our socket.
203 fd = open("/dev/null", O_RDONLY, 0644);
207 for(i=1; fd + i <= 2; i++) {
214 * If msg is NULL, initialize global chain for STDOUT and syslog
217 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
218 memset(daemon_msgs, 0, sizeof(MSGS));
219 for (i=1; i<=M_MAX; i++) {
220 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
222 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
227 * Walk down the message resource chain duplicating it
228 * for the current Job.
230 for (d=msg->dest_chain; d; d=d->next) {
231 dnew = (DEST *)malloc(sizeof(DEST));
232 memcpy(dnew, d, sizeof(DEST));
233 dnew->next = temp_chain;
235 dnew->mail_filename = NULL;
237 dnew->mail_cmd = bstrdup(d->mail_cmd);
240 dnew->where = bstrdup(d->where);
246 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
247 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
248 jcr->jcr_msgs->dest_chain = temp_chain;
249 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
251 /* If we have default values, release them now */
253 free_msgs_res(daemon_msgs);
255 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
256 memset(daemon_msgs, 0, sizeof(MSGS));
257 daemon_msgs->dest_chain = temp_chain;
258 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
260 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
264 /* Initialize so that the console (User Agent) can
265 * receive messages -- stored in a file.
267 void init_console_msg(const char *wd)
271 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
272 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
275 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
276 con_fname, be.bstrerror());
278 if (lseek(fd, 0, SEEK_END) > 0) {
279 console_msg_pending = 1;
282 con_fd = fopen(con_fname, "a+b");
285 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
286 con_fname, be.bstrerror());
288 if (rwl_init(&con_lock) != 0) {
290 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
296 * Called only during parsing of the config file.
298 * Add a message destination. I.e. associate a message type with
299 * a destination (code).
300 * Note, where in the case of dest_code FILE is a filename,
301 * but in the case of MAIL is a space separated list of
302 * email addresses, ...
304 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
308 * First search the existing chain and see if we
309 * can simply add this msg_type to an existing entry.
311 for (d=msg->dest_chain; d; d=d->next) {
312 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
313 (strcmp(where, d->where) == 0))) {
314 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
315 d, msg_type, dest_code, NPRT(where));
316 set_bit(msg_type, d->msg_types);
317 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
321 /* Not found, create a new entry */
322 d = (DEST *)malloc(sizeof(DEST));
323 memset(d, 0, sizeof(DEST));
324 d->next = msg->dest_chain;
325 d->dest_code = dest_code;
326 set_bit(msg_type, d->msg_types); /* set type bit in structure */
327 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
329 d->where = bstrdup(where);
332 d->mail_cmd = bstrdup(mail_cmd);
334 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
335 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
340 * Called only during parsing of the config file.
342 * Remove a message destination
344 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
348 for (d=msg->dest_chain; d; d=d->next) {
349 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
350 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
351 ((where == NULL && d->where == NULL) ||
352 (strcmp(where, d->where) == 0))) {
353 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
354 d, msg_type, dest_code);
355 clear_bit(msg_type, d->msg_types);
356 Dmsg0(850, "Return rem_msg_dest\n");
364 * Create a unique filename for the mail command
366 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
369 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
370 jcr->Job, (int)(intptr_t)d);
372 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
373 my_name, (int)(intptr_t)d);
375 Dmsg1(850, "mailname=%s\n", name);
381 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
386 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
388 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
392 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
393 /* If we had to use sendmail, add subject */
395 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
399 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
400 cmd, be.bstrerror());
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 */
422 msgs = jcr->jcr_msgs;
423 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 || jcr->JobStatus == JS_Warnings))
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 Qmsg1(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 Qmsg2(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 */
513 free_pool_memory(cmd);
514 Dmsg0(850, "Done walking message chain.\n");
519 Dmsg0(850, "===End close msg resource\n");
523 * Free memory associated with Messages resource
525 void free_msgs_res(MSGS *msgs)
529 /* Walk down the message chain releasing allocated buffers */
530 for (d=msgs->dest_chain; d; ) {
537 old = d; /* save pointer to release */
538 d = d->next; /* point to next buffer */
539 free(old); /* free the destination item */
541 msgs->dest_chain = NULL;
542 free(msgs); /* free the head */
547 * Terminate the message handler for good.
548 * Release the global destination chain.
550 * Also, clean up a few other items (cons, exepath). Note,
551 * these really should be done elsewhere.
555 Dmsg0(850, "Enter term_msg\n");
556 close_msg(NULL); /* close global chain */
557 free_msgs_res(daemon_msgs); /* free the resources */
580 term_last_jobs_list();
583 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
585 d->fd = fopen(d->where, mode);
589 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
597 * Handle sending the message to the appropriate place
599 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
602 char dt[MAX_TIME_LENGTH];
609 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
612 * Most messages are prefixed by a date and time. If mtime is
613 * zero, then we use the current time. If mtime is 1 (special
614 * kludge), we do not prefix the date and time. Otherwise,
615 * we assume mtime is a utime_t and use it.
623 mtime = time(NULL); /* get time for SQL log */
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 */
641 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
645 /* Now figure out where to send the message */
648 jcr = get_jcr_from_tsd();
651 msgs = jcr->jcr_msgs;
656 for (d=msgs->dest_chain; d; d=d->next) {
657 if (bit_is_set(type, d->msg_types)) {
658 switch (d->dest_code) {
661 if (!jcr || !jcr->db) {
664 if (p_sql_query && p_sql_escape) {
665 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
666 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
668 int len = strlen(msg) + 1;
669 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
670 p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
672 bstrutime(dt, sizeof(dt), mtime);
673 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
674 edit_int64(jcr->JobId, ed1), dt, esc_msg);
675 p_sql_query(jcr, cmd);
677 free_pool_memory(cmd);
678 free_pool_memory(esc_msg);
682 Dmsg1(850, "CONSOLE for following msg: %s", msg);
684 con_fd = fopen(con_fname, "a+b");
685 Dmsg0(850, "Console file not open.\n");
688 Pw(con_lock); /* get write lock on console message file */
691 (void)fwrite(dt, dtlen, 1, con_fd);
695 (void)fwrite(msg, len, 1, con_fd);
696 if (msg[len-1] != '\n') {
697 (void)fwrite("\n", 2, 1, con_fd);
700 (void)fwrite("\n", 2, 1, con_fd);
703 console_msg_pending = true;
708 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
710 * We really should do an openlog() here.
712 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
715 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
716 mcmd = get_pool_memory(PM_MESSAGE);
717 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
719 fputs(dt, bpipe->wfd);
720 fputs(msg, bpipe->wfd);
721 /* Messages to the operator go one at a time */
722 stat = close_bpipe(bpipe);
726 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
728 "ERR=%s\n"), mcmd, be.bstrerror());
731 free_pool_memory(mcmd);
734 case MD_MAIL_ON_ERROR:
735 case MD_MAIL_ON_SUCCESS:
736 Dmsg1(850, "MAIL for following msg: %s", msg);
739 POOLMEM *name = get_pool_memory(PM_MESSAGE);
740 make_unique_mail_filename(jcr, name, d);
741 d->fd = fopen(name, "w+b");
745 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
748 free_pool_memory(name);
752 d->mail_filename = name;
755 len = strlen(msg) + dtlen;;
756 if (len > d->max_len) {
757 d->max_len = len; /* keep max line length */
763 Dmsg1(850, "APPEND for following msg: %s", msg);
767 Dmsg1(850, "FILE for following msg: %s", msg);
771 if (!d->fd && !open_dest_file(jcr, d, mode)) {
777 /* On error, we close and reopen to handle log rotation */
781 if (open_dest_file(jcr, d, mode)) {
789 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
790 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
791 jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
792 jcr->Job, type, mtime, msg);
794 Dmsg1(800, "no jcr for following msg: %s", msg);
798 Dmsg1(850, "STDOUT for following msg: %s", msg);
799 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
806 Dmsg1(850, "STDERR for following msg: %s", msg);
818 /*********************************************************************
820 * This subroutine returns the filename portion of a Windows
821 * path. It is used because Microsoft Visual Studio sets __FILE__
826 get_basename(const char *pathname)
828 #if defined(_MSC_VER)
829 const char *basename;
831 if ((basename = strrchr(pathname, '\\')) == NULL) {
843 /*********************************************************************
845 * This subroutine prints a debug message if the level number
846 * is less than or equal the debug_level. File and line numbers
847 * are included for more detail if desired, but not currently
850 * If the level is negative, the details of file and line number
854 d_msg(const char *file, int line, int level, const char *fmt,...)
867 if (level <= debug_level) {
870 bstrftimes(buf, sizeof(buf), mtime);
879 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ",
880 my_name, get_basename(file), line, get_jobid_from_tsd());
887 va_start(arg_ptr, fmt);
888 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
892 * Used the "trace on" command in the console to turn on
893 * output to the trace file. "trace off" will close the file.
898 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
899 trace_fd = fopen(fn, "a+b");
902 fputs(buf, trace_fd);
905 /* Some problem, turn off tracing */
908 } else { /* not tracing */
916 * Set trace flag on/off. If argument is negative, there is no change
918 void set_trace(int trace_flag)
920 if (trace_flag < 0) {
922 } else if (trace_flag > 0) {
927 if (!trace && trace_fd) {
928 FILE *ltrace_fd = trace_fd;
930 bmicrosleep(0, 100000); /* yield to prevent seg faults */
940 /*********************************************************************
942 * This subroutine prints a message regardless of the debug level
944 * If the level is negative, the details of file and line number
948 p_msg(const char *file, int line, int level, const char *fmt,...)
956 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
963 va_start(arg_ptr, fmt);
964 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
971 /*********************************************************************
973 * subroutine writes a debug message to the trace file if the level number
974 * is less than or equal the debug_level. File and line numbers
975 * are included for more detail if desired, but not currently
978 * If the level is negative, the details of file and line number
982 t_msg(const char *file, int line, int level, const char *fmt,...)
994 if (level <= debug_level) {
996 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
997 trace_fd = fopen(buf, "a+b");
1000 #ifdef FULL_LOCATION
1002 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1009 va_start(arg_ptr, fmt);
1010 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1012 if (trace_fd != NULL) {
1013 fputs(buf, trace_fd);
1019 /* *********************************************************
1021 * print an error message
1025 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1032 * Check if we have a message destination defined.
1033 * We always report M_ABORT and M_ERROR_TERM
1035 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1036 !bit_is_set(type, daemon_msgs->send_msg))) {
1037 return; /* no destination */
1041 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1042 my_name, get_basename(file), line);
1045 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1046 my_name, get_basename(file), line);
1049 if (level == -1) /* skip details */
1050 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1052 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1055 if (level == -1) /* skip details */
1056 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1058 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1061 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1064 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1067 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1071 va_start(arg_ptr, fmt);
1072 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1075 dispatch_message(NULL, type, 0, buf);
1077 if (type == M_ABORT) {
1079 p[0] = 0; /* generate segmentation violation */
1081 if (type == M_ERROR_TERM) {
1086 /* *********************************************************
1088 * Generate a Job message
1092 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1101 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1103 /* Special case for the console, which has a dir_bsock and JobId==0,
1104 * in that case, we send the message directly back to the
1107 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1108 BSOCK *dir = jcr->dir_bsock;
1109 va_start(arg_ptr, fmt);
1110 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1113 jcr->dir_bsock->send();
1119 jcr = get_jcr_from_tsd();
1122 msgs = jcr->jcr_msgs;
1126 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1130 * Check if we have a message destination defined.
1131 * We always report M_ABORT and M_ERROR_TERM
1133 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1134 !bit_is_set(type, msgs->send_msg)) {
1135 return; /* no destination */
1139 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1142 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1145 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1147 set_jcr_job_status(jcr, JS_FatalError);
1151 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1157 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1163 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1167 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1171 va_start(arg_ptr, fmt);
1172 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1175 dispatch_message(jcr, type, mtime, rbuf);
1177 if (type == M_ABORT){
1179 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1180 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1181 p[0] = 0; /* generate segmentation violation */
1183 if (type == M_ERROR_TERM) {
1189 * If we come here, prefix the message with the file:line-number,
1190 * then pass it on to the normal Jmsg routine.
1192 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1198 pool_buf = get_pool_memory(PM_EMSG);
1199 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1202 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1203 va_start(arg_ptr, fmt);
1204 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1206 if (len < 0 || len >= (maxlen-5)) {
1207 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1213 Jmsg(jcr, type, mtime, "%s", pool_buf);
1214 free_memory(pool_buf);
1219 * Edit a message into a Pool memory buffer, with file:lineno
1221 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1226 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1229 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1230 va_start(arg_ptr, fmt);
1231 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1233 if (len < 0 || len >= (maxlen-5)) {
1234 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1242 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1247 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1250 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1251 va_start(arg_ptr, fmt);
1252 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1254 if (len < 0 || len >= (maxlen-5)) {
1255 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1265 * Edit a message into a Pool Memory buffer NO file:lineno
1266 * Returns: string length of what was edited.
1268 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1274 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1275 va_start(arg_ptr, fmt);
1276 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1278 if (len < 0 || len >= (maxlen-5)) {
1279 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1287 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1293 maxlen = sizeof_pool_memory(pool_buf) - 1;
1294 va_start(arg_ptr, fmt);
1295 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1297 if (len < 0 || len >= (maxlen-5)) {
1298 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1306 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1312 maxlen = pool_buf.max_size() - 1;
1313 va_start(arg_ptr, fmt);
1314 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1316 if (len < 0 || len >= (maxlen-5)) {
1317 pool_buf.realloc_pm(maxlen + maxlen/2);
1327 * We queue messages rather than print them directly. This
1328 * is generally used in low level routines (msg handler, bnet)
1329 * to prevent recursion (i.e. if you are in the middle of
1330 * sending a message, it is a bit messy to recursively call
1331 * yourself when the bnet packet is not reentrant).
1333 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1340 pool_buf = get_pool_memory(PM_EMSG);
1343 maxlen = sizeof_pool_memory(pool_buf) - 1;
1344 va_start(arg_ptr, fmt);
1345 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1347 if (len < 0 || len >= (maxlen-5)) {
1348 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1353 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1355 item->mtime = time(NULL);
1356 strcpy(item->msg, pool_buf);
1358 jcr = get_jcr_from_tsd();
1360 /* If no jcr or no queue or dequeuing send to syslog */
1361 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1362 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1365 /* Queue message for later sending */
1366 P(jcr->msg_queue_mutex);
1367 jcr->msg_queue->append(item);
1368 V(jcr->msg_queue_mutex);
1370 free_memory(pool_buf);
1376 void dequeue_messages(JCR *jcr)
1379 if (!jcr->msg_queue) {
1382 P(jcr->msg_queue_mutex);
1383 jcr->dequeuing_msgs = true;
1384 foreach_dlist(item, jcr->msg_queue) {
1385 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1387 /* Remove messages just sent */
1388 jcr->msg_queue->destroy();
1389 jcr->dequeuing_msgs = false;
1390 V(jcr->msg_queue_mutex);
1395 * If we come here, prefix the message with the file:line-number,
1396 * then pass it on to the normal Qmsg routine.
1398 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1404 pool_buf = get_pool_memory(PM_EMSG);
1405 i = Mmsg(pool_buf, "%s:%d ", file, line);
1408 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1409 va_start(arg_ptr, fmt);
1410 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1412 if (len < 0 || len >= (maxlen-5)) {
1413 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1419 Qmsg(jcr, type, mtime, "%s", pool_buf);
1420 free_memory(pool_buf);