2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Copyright (C) 2000-2005 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 #if !defined(HAVE_CONSOLE)
30 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
35 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
38 * This is where we define "Globals" because all the
39 * daemons include this file.
41 const char *working_directory = NULL; /* working directory path stored here */
42 int verbose = 0; /* increase User messages */
43 int debug_level = 0; /* debug level */
44 time_t daemon_start_time = 0; /* Daemon start time */
45 const char *version = VERSION " (" BDATE ")";
46 char my_name[30]; /* daemon name is stored here */
47 char *exepath = (char *)NULL;
48 char *exename = (char *)NULL;
49 int console_msg_pending = 0;
50 char con_fname[500]; /* Console filename */
51 FILE *con_fd = NULL; /* Console file descriptor */
52 brwlock_t con_lock; /* Console lock structure */
54 #ifdef HAVE_POSTGRESQL
55 char catalog_db[] = "PostgreSQL";
58 char catalog_db[] = "MySQL";
61 char catalog_db[] = "SQLite";
63 char catalog_db[] = "Internal";
68 const char *host_os = HOST_OS;
69 const char *distname = DISTNAME;
70 const char *distver = DISTVER;
71 static FILE *trace_fd = NULL;
73 static bool trace = true;
75 static bool trace = false;
78 /* Forward referenced functions */
80 /* Imported functions */
85 /* Used to allow only one thread close the daemon messages at a time */
86 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
87 static MSGS *daemon_msgs; /* global messages */
91 * Set daemon name. Also, find canonical execution
92 * path. Note, exepath has spare room for tacking on
93 * the exename so that we can reconstruct the full name.
95 * Note, this routine can get called multiple times
96 * The second time is to put the name as found in the
97 * Resource record. On the second call, generally,
98 * argv is NULL to avoid doing the path code twice.
100 #define BTRACE_EXTRA 20
101 void my_name_is(int argc, char *argv[], const char *name)
107 bstrncpy(my_name, name, sizeof(my_name));
108 if (argc>0 && argv && argv[0]) {
109 /* strip trailing filename and save exepath */
110 for (l=p=argv[0]; *p; p++) {
112 l = p; /* set pos of last slash */
119 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
120 /* On Windows allow c: junk */
130 exename = (char *)malloc(len);
136 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
137 for (p=argv[0],q=exepath; p < l; ) {
141 if (strchr(exepath, '.') || exepath[0] != '/') {
142 if (getcwd(cpath, sizeof(cpath))) {
144 exepath = (char *)malloc(strlen(cpath) + 1 + len);
145 strcpy(exepath, cpath);
148 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
153 * Initialize message handler for a daemon or a Job
154 * We make a copy of the MSGS resource passed, so it belows
155 * to the job or daemon and thus can be modified.
157 * NULL for jcr -> initialize global messages for daemon
158 * non-NULL -> initialize jcr using Message resource
161 init_msg(JCR *jcr, MSGS *msg)
163 DEST *d, *dnew, *temp_chain = NULL;
166 if (jcr == NULL && msg == NULL) {
167 init_last_jobs_list();
172 * Make sure we have fd's 0, 1, 2 open
173 * If we don't do this one of our sockets may open
174 * there and if we then use stdout, it could
175 * send total garbage to our socket.
179 fd = open("/dev/null", O_RDONLY, 0644);
183 for(i=1; fd + i <= 2; i++) {
190 * If msg is NULL, initialize global chain for STDOUT and syslog
193 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
194 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);
200 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
205 * Walk down the message resource chain duplicating it
206 * for the current Job.
208 for (d=msg->dest_chain; d; d=d->next) {
209 dnew = (DEST *)malloc(sizeof(DEST));
210 memcpy(dnew, d, sizeof(DEST));
211 dnew->next = temp_chain;
213 dnew->mail_filename = NULL;
215 dnew->mail_cmd = bstrdup(d->mail_cmd);
218 dnew->where = bstrdup(d->where);
224 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
225 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
226 jcr->jcr_msgs->dest_chain = temp_chain;
227 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
229 /* If we have default values, release them now */
231 free_msgs_res(daemon_msgs);
233 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
234 memset(daemon_msgs, 0, sizeof(MSGS));
235 daemon_msgs->dest_chain = temp_chain;
236 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
238 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
242 /* Initialize so that the console (User Agent) can
243 * receive messages -- stored in a file.
245 void init_console_msg(const char *wd)
249 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
250 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
253 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
254 con_fname, be.strerror());
256 if (lseek(fd, 0, SEEK_END) > 0) {
257 console_msg_pending = 1;
260 con_fd = fopen(con_fname, "a+");
263 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
264 con_fname, be.strerror());
266 if (rwl_init(&con_lock) != 0) {
268 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
274 * Called only during parsing of the config file.
276 * Add a message destination. I.e. associate a message type with
277 * a destination (code).
278 * Note, where in the case of dest_code FILE is a filename,
279 * but in the case of MAIL is a space separated list of
280 * email addresses, ...
282 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
286 * First search the existing chain and see if we
287 * can simply add this msg_type to an existing entry.
289 for (d=msg->dest_chain; d; d=d->next) {
290 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
291 (strcmp(where, d->where) == 0))) {
292 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
293 d, msg_type, dest_code, NPRT(where));
294 set_bit(msg_type, d->msg_types);
295 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
299 /* Not found, create a new entry */
300 d = (DEST *)malloc(sizeof(DEST));
301 memset(d, 0, sizeof(DEST));
302 d->next = msg->dest_chain;
303 d->dest_code = dest_code;
304 set_bit(msg_type, d->msg_types); /* set type bit in structure */
305 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
307 d->where = bstrdup(where);
310 d->mail_cmd = bstrdup(mail_cmd);
312 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
313 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
318 * Called only during parsing of the config file.
320 * Remove a message destination
322 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
326 for (d=msg->dest_chain; d; d=d->next) {
327 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
328 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
329 ((where == NULL && d->where == NULL) ||
330 (strcmp(where, d->where) == 0))) {
331 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
332 d, msg_type, dest_code);
333 clear_bit(msg_type, d->msg_types);
334 Dmsg0(850, "Return rem_msg_dest\n");
342 * Create a unique filename for the mail command
344 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
347 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
348 jcr->Job, (int)(long)d);
350 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
351 my_name, (int)(long)d);
353 Dmsg1(850, "mailname=%s\n", name);
359 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
364 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
366 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
370 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
372 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
376 /* If we had to use sendmail, add subject */
378 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
385 * Close the messages for this Messages resource, which means to close
386 * any open files, and dispatch any pending email messages.
388 void close_msg(JCR *jcr)
396 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
398 if (jcr == NULL) { /* NULL -> global chain */
400 P(mutex); /* only one thread walking the chain */
402 msgs = jcr->jcr_msgs;
403 jcr->jcr_msgs = NULL;
408 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
409 cmd = get_pool_memory(PM_MESSAGE);
410 for (d=msgs->dest_chain; d; ) {
412 switch (d->dest_code) {
416 fclose(d->fd); /* close open file descriptor */
420 case MD_MAIL_ON_ERROR:
421 Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
425 if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
426 jcr->JobStatus == JS_Terminated) {
430 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
431 Pmsg0(000, _("open mail pipe failed.\n"));
434 Dmsg0(850, "Opened mail pipe\n");
436 line = get_memory(len);
438 while (fgets(line, len, d->fd)) {
439 fputs(line, bpipe->wfd);
441 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
443 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
447 * Since we are closing all messages, before "recursing"
448 * make sure we are not closing the daemon messages, otherwise
451 if (msgs != daemon_msgs) {
452 /* read what mail prog returned -- should be nothing */
453 while (fgets(line, len, bpipe->rfd)) {
454 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
458 stat = close_bpipe(bpipe);
459 if (stat != 0 && msgs != daemon_msgs) {
462 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
463 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
465 "ERR=%s\n"), cmd, be.strerror());
469 /* Remove temp file */
471 unlink(d->mail_filename);
472 free_pool_memory(d->mail_filename);
473 d->mail_filename = NULL;
474 Dmsg0(850, "end mail or mail on error\n");
481 d = d->next; /* point to next buffer */
483 free_pool_memory(cmd);
484 Dmsg0(850, "Done walking message chain.\n");
491 Dmsg0(850, "===End close msg resource\n");
495 * Free memory associated with Messages resource
497 void free_msgs_res(MSGS *msgs)
501 /* Walk down the message chain releasing allocated buffers */
502 for (d=msgs->dest_chain; d; ) {
509 old = d; /* save pointer to release */
510 d = d->next; /* point to next buffer */
511 free(old); /* free the destination item */
513 msgs->dest_chain = NULL;
514 free(msgs); /* free the head */
519 * Terminate the message handler for good.
520 * Release the global destination chain.
522 * Also, clean up a few other items (cons, exepath). Note,
523 * these really should be done elsewhere.
527 Dmsg0(850, "Enter term_msg\n");
528 close_msg(NULL); /* close global chain */
529 free_msgs_res(daemon_msgs); /* free the resources */
548 term_last_jobs_list();
554 * Handle sending the message to the appropriate place
556 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
559 char dt[MAX_TIME_LENGTH];
565 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
568 * Most messages are prefixed by a date and time. If mtime is
569 * zero, then we use the current time. If mtime is 1 (special
570 * kludge), we do not prefix the date and time. Otherwise,
571 * we assume mtime is a time_t and use it.
580 bstrftime_ny(dt, sizeof(dt), mtime);
586 if (type == M_ABORT || type == M_ERROR_TERM) {
589 fputs(msg, stdout); /* print this here to INSURE that it is printed */
594 /* Now figure out where to send the message */
597 msgs = jcr->jcr_msgs;
602 for (d=msgs->dest_chain; d; d=d->next) {
603 if (bit_is_set(type, d->msg_types)) {
604 switch (d->dest_code) {
606 Dmsg1(850, "CONSOLE for following msg: %s", msg);
608 con_fd = fopen(con_fname, "a+");
609 Dmsg0(850, "Console file not open.\n");
612 Pw(con_lock); /* get write lock on console message file */
615 (void)fwrite(dt, dtlen, 1, con_fd);
619 (void)fwrite(msg, len, 1, con_fd);
620 if (msg[len-1] != '\n') {
621 (void)fwrite("\n", 2, 1, con_fd);
624 (void)fwrite("\n", 2, 1, con_fd);
627 console_msg_pending = TRUE;
632 Dmsg1(850, "SYSLOG for collowing msg: %s\n", msg);
634 * We really should do an openlog() here.
636 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
639 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
640 mcmd = get_pool_memory(PM_MESSAGE);
641 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
643 fputs(dt, bpipe->wfd);
644 fputs(msg, bpipe->wfd);
645 /* Messages to the operator go one at a time */
646 stat = close_bpipe(bpipe);
650 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
652 "ERR=%s\n"), mcmd, be.strerror());
655 free_pool_memory(mcmd);
658 case MD_MAIL_ON_ERROR:
659 Dmsg1(850, "MAIL for following msg: %s", msg);
661 POOLMEM *name = get_pool_memory(PM_MESSAGE);
662 make_unique_mail_filename(jcr, name, d);
663 d->fd = fopen(name, "w+");
667 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
670 free_pool_memory(name);
673 d->mail_filename = name;
676 len = strlen(msg) + dtlen;;
677 if (len > d->max_len) {
678 d->max_len = len; /* keep max line length */
683 Dmsg1(850, "FILE for following msg: %s", msg);
685 d->fd = fopen(d->where, "w+");
689 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
699 Dmsg1(850, "APPEND for following msg: %s", msg);
701 d->fd = fopen(d->where, "a");
705 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
715 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
716 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
717 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
718 jcr->Job, type, mtime, msg);
722 Dmsg1(850, "STDOUT for following msg: %s", msg);
723 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
729 Dmsg1(850, "STDERR for following msg: %s", msg);
741 /*********************************************************************
743 * This subroutine prints a debug message if the level number
744 * is less than or equal the debug_level. File and line numbers
745 * are included for more detail if desired, but not currently
748 * If the level is negative, the details of file and line number
752 d_msg(const char *file, int line, int level, const char *fmt,...)
764 if (level <= debug_level) {
767 /* visual studio passes the whole path to the file as well
768 * which makes for very long lines
770 const char *f = strrchr(file, '\\');
772 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
779 va_start(arg_ptr, fmt);
780 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
784 * Used the "trace on" command in the console to turn on
785 * output to the trace file. "trace off" will close the file.
790 bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
791 trace_fd = fopen(fn, "a+");
794 fputs(buf, trace_fd);
797 /* Some problem, turn off tracing */
800 } else { /* not tracing */
807 * Set trace flag on/off. If argument is negative, there is no change
809 void set_trace(int trace_flag)
811 if (trace_flag < 0) {
813 } else if (trace_flag > 0) {
818 if (!trace && trace_fd) {
819 FILE *ltrace_fd = trace_fd;
821 bmicrosleep(0, 100000); /* yield to prevent seg faults */
831 /*********************************************************************
833 * This subroutine prints a message regardless of the debug level
835 * If the level is negative, the details of file and line number
839 p_msg(const char *file, int line, int level, const char *fmt,...)
847 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
854 va_start(arg_ptr, fmt);
855 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
861 /*********************************************************************
863 * subroutine writes a debug message to the trace file if the level number
864 * is less than or equal the debug_level. File and line numbers
865 * are included for more detail if desired, but not currently
868 * If the level is negative, the details of file and line number
872 t_msg(const char *file, int line, int level, const char *fmt,...)
884 if (level <= debug_level) {
886 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
887 trace_fd = fopen(buf, "a+");
892 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
899 va_start(arg_ptr, fmt);
900 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
902 if (trace_fd != NULL) {
903 fputs(buf, trace_fd);
911 /* *********************************************************
913 * print an error message
917 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
924 * Check if we have a message destination defined.
925 * We always report M_ABORT and M_ERROR_TERM
927 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
928 !bit_is_set(type, daemon_msgs->send_msg))) {
929 return; /* no destination */
933 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
934 my_name, file, line);
937 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
938 my_name, file, line);
941 if (level == -1) /* skip details */
942 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
944 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, file, line);
947 if (level == -1) /* skip details */
948 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
950 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, file, line);
953 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
956 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
959 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
963 va_start(arg_ptr, fmt);
964 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
967 dispatch_message(NULL, type, 0, buf);
969 if (type == M_ABORT) {
971 p[0] = 0; /* generate segmentation violation */
973 if (type == M_ERROR_TERM) {
978 /* *********************************************************
980 * Generate a Job message
984 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
993 Dmsg1(850, "Enter Jmsg type=%d\n", type);
995 /* Special case for the console, which has a dir_bsock and JobId==0,
996 * in that case, we send the message directly back to the
999 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1000 BSOCK *dir = jcr->dir_bsock;
1001 va_start(arg_ptr, fmt);
1002 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1005 bnet_send(jcr->dir_bsock);
1012 msgs = jcr->jcr_msgs;
1016 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1019 job = ""; /* Set null job name if none */
1023 * Check if we have a message destination defined.
1024 * We always report M_ABORT and M_ERROR_TERM
1026 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1027 !bit_is_set(type, msgs->send_msg)) {
1028 return; /* no destination */
1032 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1035 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1038 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1040 set_jcr_job_status(jcr, JS_FatalError);
1044 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1050 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1053 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1056 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1060 va_start(arg_ptr, fmt);
1061 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1064 dispatch_message(jcr, type, mtime, rbuf);
1066 if (type == M_ABORT){
1068 p[0] = 0; /* generate segmentation violation */
1070 if (type == M_ERROR_TERM) {
1076 * If we come here, prefix the message with the file:line-number,
1077 * then pass it on to the normal Jmsg routine.
1079 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1085 pool_buf = get_pool_memory(PM_EMSG);
1086 i = Mmsg(pool_buf, "%s:%d ", file, line);
1089 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1090 va_start(arg_ptr, fmt);
1091 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1093 if (len < 0 || len >= (maxlen-5)) {
1094 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1100 Jmsg(jcr, type, mtime, "%s", pool_buf);
1101 free_memory(pool_buf);
1106 * Edit a message into a Pool memory buffer, with file:lineno
1108 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1113 i = sprintf(*pool_buf, "%s:%d ", file, line);
1116 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1117 va_start(arg_ptr, fmt);
1118 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1120 if (len < 0 || len >= (maxlen-5)) {
1121 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1129 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1134 i = sprintf(pool_buf, "%s:%d ", file, line);
1137 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1138 va_start(arg_ptr, fmt);
1139 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1141 if (len < 0 || len >= (maxlen-5)) {
1142 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1152 * Edit a message into a Pool Memory buffer NO file:lineno
1153 * Returns: string length of what was edited.
1155 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1161 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1162 va_start(arg_ptr, fmt);
1163 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1165 if (len < 0 || len >= (maxlen-5)) {
1166 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1174 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1180 maxlen = sizeof_pool_memory(pool_buf) - 1;
1181 va_start(arg_ptr, fmt);
1182 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1184 if (len < 0 || len >= (maxlen-5)) {
1185 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1193 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1199 maxlen = pool_buf.max_size() - 1;
1200 va_start(arg_ptr, fmt);
1201 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1203 if (len < 0 || len >= (maxlen-5)) {
1204 pool_buf.realloc_pm(maxlen + maxlen/2);
1213 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1216 * We queue messages rather than print them directly. This
1217 * is generally used in low level routines (msg handler, bnet)
1218 * to prevent recursion (i.e. if you are in the middle of
1219 * sending a message, it is a bit messy to recursively call
1220 * yourself when the bnet packet is not reentrant).
1222 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1229 pool_buf = get_pool_memory(PM_EMSG);
1232 maxlen = sizeof_pool_memory(pool_buf) - 1;
1233 va_start(arg_ptr, fmt);
1234 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1236 if (len < 0 || len >= (maxlen-5)) {
1237 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1242 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1244 item->mtime = time(NULL);
1245 strcpy(item->msg, pool_buf);
1246 /* If no jcr or dequeuing send to daemon to avoid recursion */
1247 if (!jcr || jcr->dequeuing) {
1248 /* jcr==NULL => daemon message, safe to send now */
1249 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1252 /* Queue message for later sending */
1254 jcr->msg_queue->append(item);
1257 free_memory(pool_buf);
1263 void dequeue_messages(JCR *jcr)
1267 jcr->dequeuing = true;
1268 foreach_dlist(item, jcr->msg_queue) {
1269 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1271 jcr->msg_queue->destroy();
1272 jcr->dequeuing = false;
1278 * If we come here, prefix the message with the file:line-number,
1279 * then pass it on to the normal Qmsg routine.
1281 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1287 pool_buf = get_pool_memory(PM_EMSG);
1288 i = Mmsg(pool_buf, "%s:%d ", file, line);
1291 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1292 va_start(arg_ptr, fmt);
1293 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1295 if (len < 0 || len >= (maxlen-5)) {
1296 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1302 Qmsg(jcr, type, mtime, "%s", pool_buf);
1303 free_memory(pool_buf);