2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
29 sql_query p_sql_query = NULL;
31 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
34 * This is where we define "Globals" because all the
35 * daemons include this file.
37 const char *working_directory = NULL; /* working directory path stored here */
38 int verbose = 0; /* increase User messages */
39 int debug_level = 0; /* debug level */
40 time_t daemon_start_time = 0; /* Daemon start time */
41 const char *version = VERSION " (" BDATE ")";
42 char my_name[30]; /* daemon name is stored here */
43 char *exepath = (char *)NULL;
44 char *exename = (char *)NULL;
45 int console_msg_pending = 0;
46 char con_fname[500]; /* Console filename */
47 FILE *con_fd = NULL; /* Console file descriptor */
48 brwlock_t con_lock; /* Console lock structure */
50 static char *catalog_db = NULL; /* database type */
52 const char *host_os = HOST_OS;
53 const char *distname = DISTNAME;
54 const char *distver = DISTVER;
55 static FILE *trace_fd = NULL;
56 #if defined(HAVE_WIN32)
57 static bool trace = true;
59 static bool trace = false;
62 /* Forward referenced functions */
64 /* Imported functions */
69 /* Used to allow only one thread close the daemon messages at a time */
70 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
71 static MSGS *daemon_msgs; /* global messages */
75 * Set daemon name. Also, find canonical execution
76 * path. Note, exepath has spare room for tacking on
77 * the exename so that we can reconstruct the full name.
79 * Note, this routine can get called multiple times
80 * The second time is to put the name as found in the
81 * Resource record. On the second call, generally,
82 * argv is NULL to avoid doing the path code twice.
84 #define BTRACE_EXTRA 20
85 void my_name_is(int argc, char *argv[], const char *name)
91 bstrncpy(my_name, name, sizeof(my_name));
92 if (argc>0 && argv && argv[0]) {
93 /* strip trailing filename and save exepath */
94 for (l=p=argv[0]; *p; p++) {
96 l = p; /* set pos of last slash */
103 #if defined(HAVE_WIN32)
104 /* On Windows allow c: junk */
114 exename = (char *)malloc(len);
120 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
121 for (p=argv[0],q=exepath; p < l; ) {
125 if (strchr(exepath, '.') || exepath[0] != '/') {
126 if (getcwd(cpath, sizeof(cpath))) {
128 exepath = (char *)malloc(strlen(cpath) + 1 + len);
129 strcpy(exepath, cpath);
132 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
139 return catalog_db != NULL ? catalog_db : "unknown";
143 set_db_type(const char *name)
145 if (catalog_db != NULL)
150 catalog_db = bstrdup(name);
154 * Initialize message handler for a daemon or a Job
155 * We make a copy of the MSGS resource passed, so it belows
156 * to the job or daemon and thus can be modified.
158 * NULL for jcr -> initialize global messages for daemon
159 * non-NULL -> initialize jcr using Message resource
162 init_msg(JCR *jcr, MSGS *msg)
164 DEST *d, *dnew, *temp_chain = NULL;
167 if (jcr == NULL && msg == NULL) {
168 init_last_jobs_list();
171 #if !defined(HAVE_WIN32)
173 * Make sure we have fd's 0, 1, 2 open
174 * If we don't do this one of our sockets may open
175 * there and if we then use stdout, it could
176 * send total garbage to our socket.
180 fd = open("/dev/null", O_RDONLY, 0644);
184 for(i=1; fd + i <= 2; i++) {
191 * If msg is NULL, initialize global chain for STDOUT and syslog
194 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
195 memset(daemon_msgs, 0, sizeof(MSGS));
196 for (i=1; i<=M_MAX; i++) {
197 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
199 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
204 * Walk down the message resource chain duplicating it
205 * for the current Job.
207 for (d=msg->dest_chain; d; d=d->next) {
208 dnew = (DEST *)malloc(sizeof(DEST));
209 memcpy(dnew, d, sizeof(DEST));
210 dnew->next = temp_chain;
212 dnew->mail_filename = NULL;
214 dnew->mail_cmd = bstrdup(d->mail_cmd);
217 dnew->where = bstrdup(d->where);
223 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
224 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
225 jcr->jcr_msgs->dest_chain = temp_chain;
226 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
228 /* If we have default values, release them now */
230 free_msgs_res(daemon_msgs);
232 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
233 memset(daemon_msgs, 0, sizeof(MSGS));
234 daemon_msgs->dest_chain = temp_chain;
235 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
237 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
241 /* Initialize so that the console (User Agent) can
242 * receive messages -- stored in a file.
244 void init_console_msg(const char *wd)
248 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
249 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
252 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
253 con_fname, be.strerror());
255 if (lseek(fd, 0, SEEK_END) > 0) {
256 console_msg_pending = 1;
259 con_fd = fopen(con_fname, "a+b");
262 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
263 con_fname, be.strerror());
265 if (rwl_init(&con_lock) != 0) {
267 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
273 * Called only during parsing of the config file.
275 * Add a message destination. I.e. associate a message type with
276 * a destination (code).
277 * Note, where in the case of dest_code FILE is a filename,
278 * but in the case of MAIL is a space separated list of
279 * email addresses, ...
281 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
285 * First search the existing chain and see if we
286 * can simply add this msg_type to an existing entry.
288 for (d=msg->dest_chain; d; d=d->next) {
289 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
290 (strcmp(where, d->where) == 0))) {
291 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
292 d, msg_type, dest_code, NPRT(where));
293 set_bit(msg_type, d->msg_types);
294 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
298 /* Not found, create a new entry */
299 d = (DEST *)malloc(sizeof(DEST));
300 memset(d, 0, sizeof(DEST));
301 d->next = msg->dest_chain;
302 d->dest_code = dest_code;
303 set_bit(msg_type, d->msg_types); /* set type bit in structure */
304 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
306 d->where = bstrdup(where);
309 d->mail_cmd = bstrdup(mail_cmd);
311 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
312 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
317 * Called only during parsing of the config file.
319 * Remove a message destination
321 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
325 for (d=msg->dest_chain; d; d=d->next) {
326 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
327 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
328 ((where == NULL && d->where == NULL) ||
329 (strcmp(where, d->where) == 0))) {
330 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
331 d, msg_type, dest_code);
332 clear_bit(msg_type, d->msg_types);
333 Dmsg0(850, "Return rem_msg_dest\n");
341 * Create a unique filename for the mail command
343 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
346 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
347 jcr->Job, (int)(long)d);
349 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
350 my_name, (int)(long)d);
352 Dmsg1(850, "mailname=%s\n", name);
358 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
363 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
365 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
369 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
371 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
375 /* If we had to use sendmail, add subject */
377 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
384 * Close the messages for this Messages resource, which means to close
385 * any open files, and dispatch any pending email messages.
387 void close_msg(JCR *jcr)
395 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
397 if (jcr == NULL) { /* NULL -> global chain */
399 P(mutex); /* only one thread walking the chain */
401 msgs = jcr->jcr_msgs;
402 jcr->jcr_msgs = NULL;
407 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
408 cmd = get_pool_memory(PM_MESSAGE);
409 for (d=msgs->dest_chain; d; ) {
411 switch (d->dest_code) {
415 fclose(d->fd); /* close open file descriptor */
419 case MD_MAIL_ON_ERROR:
420 Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
424 if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
425 jcr->JobStatus == JS_Terminated) {
429 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
430 Pmsg0(000, _("open mail pipe failed.\n"));
433 Dmsg0(850, "Opened mail pipe\n");
435 line = get_memory(len);
437 while (fgets(line, len, d->fd)) {
438 fputs(line, bpipe->wfd);
440 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
442 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
446 * Since we are closing all messages, before "recursing"
447 * make sure we are not closing the daemon messages, otherwise
450 if (msgs != daemon_msgs) {
451 /* read what mail prog returned -- should be nothing */
452 while (fgets(line, len, bpipe->rfd)) {
453 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
457 stat = close_bpipe(bpipe);
458 if (stat != 0 && msgs != daemon_msgs) {
461 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
462 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
464 "ERR=%s\n"), cmd, be.strerror());
468 /* Remove temp file */
470 unlink(d->mail_filename);
471 free_pool_memory(d->mail_filename);
472 d->mail_filename = NULL;
473 Dmsg0(850, "end mail or mail on error\n");
480 d = d->next; /* point to next buffer */
482 free_pool_memory(cmd);
483 Dmsg0(850, "Done walking message chain.\n");
490 Dmsg0(850, "===End close msg resource\n");
494 * Free memory associated with Messages resource
496 void free_msgs_res(MSGS *msgs)
500 /* Walk down the message chain releasing allocated buffers */
501 for (d=msgs->dest_chain; d; ) {
508 old = d; /* save pointer to release */
509 d = d->next; /* point to next buffer */
510 free(old); /* free the destination item */
512 msgs->dest_chain = NULL;
513 free(msgs); /* free the head */
518 * Terminate the message handler for good.
519 * Release the global destination chain.
521 * Also, clean up a few other items (cons, exepath). Note,
522 * these really should be done elsewhere.
526 Dmsg0(850, "Enter term_msg\n");
527 close_msg(NULL); /* close global chain */
528 free_msgs_res(daemon_msgs); /* free the resources */
547 term_last_jobs_list();
550 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
552 d->fd = fopen(d->where, mode);
556 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
565 * Handle sending the message to the appropriate place
567 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
570 char dt[MAX_TIME_LENGTH];
577 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
580 * Most messages are prefixed by a date and time. If mtime is
581 * zero, then we use the current time. If mtime is 1 (special
582 * kludge), we do not prefix the date and time. Otherwise,
583 * we assume mtime is a time_t and use it.
592 bstrftime_ny(dt, sizeof(dt), mtime);
598 if (type == M_ABORT || type == M_ERROR_TERM) {
600 fputs(msg, stdout); /* print this here to INSURE that it is printed */
604 /* Now figure out where to send the message */
607 msgs = jcr->jcr_msgs;
612 for (d=msgs->dest_chain; d; d=d->next) {
613 if (bit_is_set(type, d->msg_types)) {
614 switch (d->dest_code) {
617 if (!jcr || !jcr->db) {
621 POOL_MEM cmd(PM_MESSAGE);
622 bstrftimes(dt, sizeof(dt), mtime);
623 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
624 edit_int64(jcr->JobId, ed1), dt, msg);
625 p_sql_query(jcr, cmd.c_str());
629 Dmsg1(850, "CONSOLE for following msg: %s", msg);
631 con_fd = fopen(con_fname, "a+b");
632 Dmsg0(850, "Console file not open.\n");
635 Pw(con_lock); /* get write lock on console message file */
638 (void)fwrite(dt, dtlen, 1, con_fd);
642 (void)fwrite(msg, len, 1, con_fd);
643 if (msg[len-1] != '\n') {
644 (void)fwrite("\n", 2, 1, con_fd);
647 (void)fwrite("\n", 2, 1, con_fd);
650 console_msg_pending = TRUE;
655 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
657 * We really should do an openlog() here.
659 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
662 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
663 mcmd = get_pool_memory(PM_MESSAGE);
664 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
666 fputs(dt, bpipe->wfd);
667 fputs(msg, bpipe->wfd);
668 /* Messages to the operator go one at a time */
669 stat = close_bpipe(bpipe);
673 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
675 "ERR=%s\n"), mcmd, be.strerror());
678 free_pool_memory(mcmd);
681 case MD_MAIL_ON_ERROR:
682 Dmsg1(850, "MAIL for following msg: %s", msg);
684 POOLMEM *name = get_pool_memory(PM_MESSAGE);
685 make_unique_mail_filename(jcr, name, d);
686 d->fd = fopen(name, "w+b");
690 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
693 free_pool_memory(name);
696 d->mail_filename = name;
699 len = strlen(msg) + dtlen;;
700 if (len > d->max_len) {
701 d->max_len = len; /* keep max line length */
706 Dmsg1(850, "APPEND for following msg: %s", msg);
710 Dmsg1(850, "FILE for following msg: %s", msg);
713 if (!d->fd && !open_dest_file(jcr, d, mode)) {
718 /* On error, we close and reopen to handle log rotation */
721 if (open_dest_file(jcr, d, mode)) {
728 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
729 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
730 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
731 jcr->Job, type, mtime, msg);
735 Dmsg1(850, "STDOUT for following msg: %s", msg);
736 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
742 Dmsg1(850, "STDERR for following msg: %s", msg);
753 /*********************************************************************
755 * This subroutine returns the filename portion of a Windows
756 * path. It is used because Microsoft Visual Studio sets __FILE__
761 get_basename(const char *pathname)
763 #if defined(_MSC_VER)
764 const char *basename;
766 if ((basename = strrchr(pathname, '\\')) == NULL) {
778 /*********************************************************************
780 * This subroutine prints a debug message if the level number
781 * is less than or equal the debug_level. File and line numbers
782 * are included for more detail if desired, but not currently
785 * If the level is negative, the details of file and line number
789 d_msg(const char *file, int line, int level, const char *fmt,...)
801 if (level <= debug_level) {
804 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
811 va_start(arg_ptr, fmt);
812 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
816 * Used the "trace on" command in the console to turn on
817 * output to the trace file. "trace off" will close the file.
822 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
823 trace_fd = fopen(fn, "a+b");
826 fputs(buf, trace_fd);
829 /* Some problem, turn off tracing */
832 } else { /* not tracing */
839 * Set trace flag on/off. If argument is negative, there is no change
841 void set_trace(int trace_flag)
843 if (trace_flag < 0) {
845 } else if (trace_flag > 0) {
850 if (!trace && trace_fd) {
851 FILE *ltrace_fd = trace_fd;
853 bmicrosleep(0, 100000); /* yield to prevent seg faults */
863 /*********************************************************************
865 * This subroutine prints a message regardless of the debug level
867 * If the level is negative, the details of file and line number
871 p_msg(const char *file, int line, int level, const char *fmt,...)
879 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
886 va_start(arg_ptr, fmt);
887 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
893 /*********************************************************************
895 * subroutine writes a debug message to the trace file if the level number
896 * is less than or equal the debug_level. File and line numbers
897 * are included for more detail if desired, but not currently
900 * If the level is negative, the details of file and line number
904 t_msg(const char *file, int line, int level, const char *fmt,...)
916 if (level <= debug_level) {
918 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
919 trace_fd = fopen(buf, "a+b");
924 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
931 va_start(arg_ptr, fmt);
932 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
934 if (trace_fd != NULL) {
935 fputs(buf, trace_fd);
943 /* *********************************************************
945 * print an error message
949 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
956 * Check if we have a message destination defined.
957 * We always report M_ABORT and M_ERROR_TERM
959 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
960 !bit_is_set(type, daemon_msgs->send_msg))) {
961 return; /* no destination */
965 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
966 my_name, get_basename(file), line);
969 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
970 my_name, get_basename(file), line);
973 if (level == -1) /* skip details */
974 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
976 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
979 if (level == -1) /* skip details */
980 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
982 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
985 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
988 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
991 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
995 va_start(arg_ptr, fmt);
996 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
999 dispatch_message(NULL, type, 0, buf);
1001 if (type == M_ABORT) {
1003 p[0] = 0; /* generate segmentation violation */
1005 if (type == M_ERROR_TERM) {
1010 /* *********************************************************
1012 * Generate a Job message
1016 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1025 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1027 /* Special case for the console, which has a dir_bsock and JobId==0,
1028 * in that case, we send the message directly back to the
1031 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1032 BSOCK *dir = jcr->dir_bsock;
1033 va_start(arg_ptr, fmt);
1034 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1037 bnet_send(jcr->dir_bsock);
1044 msgs = jcr->jcr_msgs;
1048 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1051 job = ""; /* Set null job name if none */
1055 * Check if we have a message destination defined.
1056 * We always report M_ABORT and M_ERROR_TERM
1058 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1059 !bit_is_set(type, msgs->send_msg)) {
1060 return; /* no destination */
1064 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1067 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1070 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1072 set_jcr_job_status(jcr, JS_FatalError);
1076 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1082 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1085 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1088 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1092 va_start(arg_ptr, fmt);
1093 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1096 dispatch_message(jcr, type, mtime, rbuf);
1098 if (type == M_ABORT){
1100 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1101 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1102 p[0] = 0; /* generate segmentation violation */
1104 if (type == M_ERROR_TERM) {
1110 * If we come here, prefix the message with the file:line-number,
1111 * then pass it on to the normal Jmsg routine.
1113 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1119 pool_buf = get_pool_memory(PM_EMSG);
1120 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1123 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1124 va_start(arg_ptr, fmt);
1125 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1127 if (len < 0 || len >= (maxlen-5)) {
1128 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1134 Jmsg(jcr, type, mtime, "%s", pool_buf);
1135 free_memory(pool_buf);
1140 * Edit a message into a Pool memory buffer, with file:lineno
1142 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1147 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1150 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1151 va_start(arg_ptr, fmt);
1152 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1154 if (len < 0 || len >= (maxlen-5)) {
1155 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1163 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1168 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1171 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1172 va_start(arg_ptr, fmt);
1173 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1175 if (len < 0 || len >= (maxlen-5)) {
1176 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1186 * Edit a message into a Pool Memory buffer NO file:lineno
1187 * Returns: string length of what was edited.
1189 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1195 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1196 va_start(arg_ptr, fmt);
1197 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1199 if (len < 0 || len >= (maxlen-5)) {
1200 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1208 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1214 maxlen = sizeof_pool_memory(pool_buf) - 1;
1215 va_start(arg_ptr, fmt);
1216 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1218 if (len < 0 || len >= (maxlen-5)) {
1219 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1227 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1233 maxlen = pool_buf.max_size() - 1;
1234 va_start(arg_ptr, fmt);
1235 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1237 if (len < 0 || len >= (maxlen-5)) {
1238 pool_buf.realloc_pm(maxlen + maxlen/2);
1247 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1250 * We queue messages rather than print them directly. This
1251 * is generally used in low level routines (msg handler, bnet)
1252 * to prevent recursion (i.e. if you are in the middle of
1253 * sending a message, it is a bit messy to recursively call
1254 * yourself when the bnet packet is not reentrant).
1256 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1263 pool_buf = get_pool_memory(PM_EMSG);
1266 maxlen = sizeof_pool_memory(pool_buf) - 1;
1267 va_start(arg_ptr, fmt);
1268 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1270 if (len < 0 || len >= (maxlen-5)) {
1271 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1276 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1278 item->mtime = time(NULL);
1279 strcpy(item->msg, pool_buf);
1280 /* If no jcr or dequeuing send to daemon to avoid recursion */
1281 if (!jcr || jcr->dequeuing) {
1282 /* jcr==NULL => daemon message, safe to send now */
1283 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1286 /* Queue message for later sending */
1288 jcr->msg_queue->append(item);
1291 free_memory(pool_buf);
1297 void dequeue_messages(JCR *jcr)
1301 if (!jcr->msg_queue) {
1304 jcr->dequeuing = true;
1305 foreach_dlist(item, jcr->msg_queue) {
1306 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1308 jcr->msg_queue->destroy();
1309 jcr->dequeuing = false;
1317 * If we come here, prefix the message with the file:line-number,
1318 * then pass it on to the normal Qmsg routine.
1320 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1326 pool_buf = get_pool_memory(PM_EMSG);
1327 i = Mmsg(pool_buf, "%s:%d ", file, line);
1330 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1331 va_start(arg_ptr, fmt);
1332 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1334 if (len < 0 || len >= (maxlen-5)) {
1335 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1341 Qmsg(jcr, type, mtime, "%s", pool_buf);
1342 free_memory(pool_buf);