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 #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 */
55 #ifdef HAVE_POSTGRESQL
56 char catalog_db[] = "PostgreSQL";
59 char catalog_db[] = "MySQL";
62 char catalog_db[] = "SQLite";
64 char catalog_db[] = "Internal";
69 const char *host_os = HOST_OS;
70 const char *distname = DISTNAME;
71 const char *distver = DISTVER;
72 static FILE *trace_fd = NULL;
74 static bool trace = true;
76 static bool trace = false;
79 /* Forward referenced functions */
81 /* Imported functions */
86 /* Used to allow only one thread close the daemon messages at a time */
87 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
88 static MSGS *daemon_msgs; /* global messages */
92 * Set daemon name. Also, find canonical execution
93 * path. Note, exepath has spare room for tacking on
94 * the exename so that we can reconstruct the full name.
96 * Note, this routine can get called multiple times
97 * The second time is to put the name as found in the
98 * Resource record. On the second call, generally,
99 * argv is NULL to avoid doing the path code twice.
101 #define BTRACE_EXTRA 20
102 void my_name_is(int argc, char *argv[], const char *name)
108 bstrncpy(my_name, name, sizeof(my_name));
109 if (argc>0 && argv && argv[0]) {
110 /* strip trailing filename and save exepath */
111 for (l=p=argv[0]; *p; p++) {
113 l = p; /* set pos of last slash */
120 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
121 /* On Windows allow c: junk */
131 exename = (char *)malloc(len);
137 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
138 for (p=argv[0],q=exepath; p < l; ) {
142 if (strchr(exepath, '.') || exepath[0] != '/') {
143 if (getcwd(cpath, sizeof(cpath))) {
145 exepath = (char *)malloc(strlen(cpath) + 1 + len);
146 strcpy(exepath, cpath);
149 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
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();
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));
197 for (i=1; i<=M_MAX; i++) {
198 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
201 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
206 * Walk down the message resource chain duplicating it
207 * for the current Job.
209 for (d=msg->dest_chain; d; d=d->next) {
210 dnew = (DEST *)malloc(sizeof(DEST));
211 memcpy(dnew, d, sizeof(DEST));
212 dnew->next = temp_chain;
214 dnew->mail_filename = NULL;
216 dnew->mail_cmd = bstrdup(d->mail_cmd);
219 dnew->where = bstrdup(d->where);
225 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
226 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
227 jcr->jcr_msgs->dest_chain = temp_chain;
228 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
230 /* If we have default values, release them now */
232 free_msgs_res(daemon_msgs);
234 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
235 memset(daemon_msgs, 0, sizeof(MSGS));
236 daemon_msgs->dest_chain = temp_chain;
237 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
239 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
243 /* Initialize so that the console (User Agent) can
244 * receive messages -- stored in a file.
246 void init_console_msg(const char *wd)
250 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
251 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
254 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
255 con_fname, be.strerror());
257 if (lseek(fd, 0, SEEK_END) > 0) {
258 console_msg_pending = 1;
261 con_fd = fopen(con_fname, "a+");
264 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
265 con_fname, be.strerror());
267 if (rwl_init(&con_lock) != 0) {
269 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
275 * Called only during parsing of the config file.
277 * Add a message destination. I.e. associate a message type with
278 * a destination (code).
279 * Note, where in the case of dest_code FILE is a filename,
280 * but in the case of MAIL is a space separated list of
281 * email addresses, ...
283 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
287 * First search the existing chain and see if we
288 * can simply add this msg_type to an existing entry.
290 for (d=msg->dest_chain; d; d=d->next) {
291 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
292 (strcmp(where, d->where) == 0))) {
293 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
294 d, msg_type, dest_code, NPRT(where));
295 set_bit(msg_type, d->msg_types);
296 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
300 /* Not found, create a new entry */
301 d = (DEST *)malloc(sizeof(DEST));
302 memset(d, 0, sizeof(DEST));
303 d->next = msg->dest_chain;
304 d->dest_code = dest_code;
305 set_bit(msg_type, d->msg_types); /* set type bit in structure */
306 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
308 d->where = bstrdup(where);
311 d->mail_cmd = bstrdup(mail_cmd);
313 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
314 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
319 * Called only during parsing of the config file.
321 * Remove a message destination
323 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
327 for (d=msg->dest_chain; d; d=d->next) {
328 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
329 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
330 ((where == NULL && d->where == NULL) ||
331 (strcmp(where, d->where) == 0))) {
332 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
333 d, msg_type, dest_code);
334 clear_bit(msg_type, d->msg_types);
335 Dmsg0(850, "Return rem_msg_dest\n");
343 * Create a unique filename for the mail command
345 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
348 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
349 jcr->Job, (int)(long)d);
351 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
352 my_name, (int)(long)d);
354 Dmsg1(850, "mailname=%s\n", name);
360 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
365 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
367 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
371 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
373 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
377 /* If we had to use sendmail, add subject */
379 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
386 * Close the messages for this Messages resource, which means to close
387 * any open files, and dispatch any pending email messages.
389 void close_msg(JCR *jcr)
397 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
399 if (jcr == NULL) { /* NULL -> global chain */
401 P(mutex); /* only one thread walking the chain */
403 msgs = jcr->jcr_msgs;
404 jcr->jcr_msgs = NULL;
409 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
410 cmd = get_pool_memory(PM_MESSAGE);
411 for (d=msgs->dest_chain; d; ) {
413 switch (d->dest_code) {
417 fclose(d->fd); /* close open file descriptor */
421 case MD_MAIL_ON_ERROR:
422 Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
426 if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
427 jcr->JobStatus == JS_Terminated) {
431 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
432 Pmsg0(000, _("open mail pipe failed.\n"));
435 Dmsg0(850, "Opened mail pipe\n");
437 line = get_memory(len);
439 while (fgets(line, len, d->fd)) {
440 fputs(line, bpipe->wfd);
442 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
444 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
448 * Since we are closing all messages, before "recursing"
449 * make sure we are not closing the daemon messages, otherwise
452 if (msgs != daemon_msgs) {
453 /* read what mail prog returned -- should be nothing */
454 while (fgets(line, len, bpipe->rfd)) {
455 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
459 stat = close_bpipe(bpipe);
460 if (stat != 0 && msgs != daemon_msgs) {
463 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
464 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
466 "ERR=%s\n"), cmd, be.strerror());
470 /* Remove temp file */
472 unlink(d->mail_filename);
473 free_pool_memory(d->mail_filename);
474 d->mail_filename = NULL;
475 Dmsg0(850, "end mail or mail on error\n");
482 d = d->next; /* point to next buffer */
484 free_pool_memory(cmd);
485 Dmsg0(850, "Done walking message chain.\n");
492 Dmsg0(850, "===End close msg resource\n");
496 * Free memory associated with Messages resource
498 void free_msgs_res(MSGS *msgs)
502 /* Walk down the message chain releasing allocated buffers */
503 for (d=msgs->dest_chain; d; ) {
510 old = d; /* save pointer to release */
511 d = d->next; /* point to next buffer */
512 free(old); /* free the destination item */
514 msgs->dest_chain = NULL;
515 free(msgs); /* free the head */
520 * Terminate the message handler for good.
521 * Release the global destination chain.
523 * Also, clean up a few other items (cons, exepath). Note,
524 * these really should be done elsewhere.
528 Dmsg0(850, "Enter term_msg\n");
529 close_msg(NULL); /* close global chain */
530 free_msgs_res(daemon_msgs); /* free the resources */
549 term_last_jobs_list();
555 * Handle sending the message to the appropriate place
557 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
560 char dt[MAX_TIME_LENGTH];
566 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
569 * Most messages are prefixed by a date and time. If mtime is
570 * zero, then we use the current time. If mtime is 1 (special
571 * kludge), we do not prefix the date and time. Otherwise,
572 * we assume mtime is a time_t and use it.
581 bstrftime_ny(dt, sizeof(dt), mtime);
587 if (type == M_ABORT || type == M_ERROR_TERM) {
590 fputs(msg, stdout); /* print this here to INSURE that it is printed */
595 /* Now figure out where to send the message */
598 msgs = jcr->jcr_msgs;
603 for (d=msgs->dest_chain; d; d=d->next) {
604 if (bit_is_set(type, d->msg_types)) {
605 switch (d->dest_code) {
607 Dmsg1(850, "CONSOLE for following msg: %s", msg);
609 con_fd = fopen(con_fname, "a+");
610 Dmsg0(850, "Console file not open.\n");
613 Pw(con_lock); /* get write lock on console message file */
616 (void)fwrite(dt, dtlen, 1, con_fd);
620 (void)fwrite(msg, len, 1, con_fd);
621 if (msg[len-1] != '\n') {
622 (void)fwrite("\n", 2, 1, con_fd);
625 (void)fwrite("\n", 2, 1, con_fd);
628 console_msg_pending = TRUE;
633 Dmsg1(850, "SYSLOG for collowing msg: %s\n", msg);
635 * We really should do an openlog() here.
637 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
640 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
641 mcmd = get_pool_memory(PM_MESSAGE);
642 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
644 fputs(dt, bpipe->wfd);
645 fputs(msg, bpipe->wfd);
646 /* Messages to the operator go one at a time */
647 stat = close_bpipe(bpipe);
651 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
653 "ERR=%s\n"), mcmd, be.strerror());
656 free_pool_memory(mcmd);
659 case MD_MAIL_ON_ERROR:
660 Dmsg1(850, "MAIL for following msg: %s", msg);
662 POOLMEM *name = get_pool_memory(PM_MESSAGE);
663 make_unique_mail_filename(jcr, name, d);
664 d->fd = fopen(name, "w+");
668 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
671 free_pool_memory(name);
674 d->mail_filename = name;
677 len = strlen(msg) + dtlen;;
678 if (len > d->max_len) {
679 d->max_len = len; /* keep max line length */
684 Dmsg1(850, "FILE for following msg: %s", msg);
686 d->fd = fopen(d->where, "w+");
690 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
700 Dmsg1(850, "APPEND for following msg: %s", msg);
702 d->fd = fopen(d->where, "a");
706 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
716 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
717 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
718 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
719 jcr->Job, type, mtime, msg);
723 Dmsg1(850, "STDOUT for following msg: %s", msg);
724 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
730 Dmsg1(850, "STDERR for following msg: %s", msg);
742 /*********************************************************************
744 * This subroutine prints a debug message if the level number
745 * is less than or equal the debug_level. File and line numbers
746 * are included for more detail if desired, but not currently
749 * If the level is negative, the details of file and line number
753 d_msg(const char *file, int line, int level, const char *fmt,...)
765 if (level <= debug_level) {
768 /* visual studio passes the whole path to the file as well
769 * which makes for very long lines
771 const char *f = strrchr(file, '\\');
773 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
780 va_start(arg_ptr, fmt);
781 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
785 * Used the "trace on" command in the console to turn on
786 * output to the trace file. "trace off" will close the file.
791 bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
792 trace_fd = fopen(fn, "a+");
795 fputs(buf, trace_fd);
798 /* Some problem, turn off tracing */
801 } else { /* not tracing */
808 * Set trace flag on/off. If argument is negative, there is no change
810 void set_trace(int trace_flag)
812 if (trace_flag < 0) {
814 } else if (trace_flag > 0) {
819 if (!trace && trace_fd) {
820 FILE *ltrace_fd = trace_fd;
822 bmicrosleep(0, 100000); /* yield to prevent seg faults */
832 /*********************************************************************
834 * This subroutine prints a message regardless of the debug level
836 * If the level is negative, the details of file and line number
840 p_msg(const char *file, int line, int level, const char *fmt,...)
848 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
855 va_start(arg_ptr, fmt);
856 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
862 /*********************************************************************
864 * subroutine writes a debug message to the trace file if the level number
865 * is less than or equal the debug_level. File and line numbers
866 * are included for more detail if desired, but not currently
869 * If the level is negative, the details of file and line number
873 t_msg(const char *file, int line, int level, const char *fmt,...)
885 if (level <= debug_level) {
887 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
888 trace_fd = fopen(buf, "a+");
893 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
900 va_start(arg_ptr, fmt);
901 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
903 if (trace_fd != NULL) {
904 fputs(buf, trace_fd);
912 /* *********************************************************
914 * print an error message
918 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
925 * Check if we have a message destination defined.
926 * We always report M_ABORT and M_ERROR_TERM
928 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
929 !bit_is_set(type, daemon_msgs->send_msg))) {
930 return; /* no destination */
934 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
935 my_name, file, line);
938 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
939 my_name, file, line);
942 if (level == -1) /* skip details */
943 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
945 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, file, line);
948 if (level == -1) /* skip details */
949 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
951 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, file, line);
954 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
957 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
960 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
964 va_start(arg_ptr, fmt);
965 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
968 dispatch_message(NULL, type, 0, buf);
970 if (type == M_ABORT) {
972 p[0] = 0; /* generate segmentation violation */
974 if (type == M_ERROR_TERM) {
979 /* *********************************************************
981 * Generate a Job message
985 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
994 Dmsg1(850, "Enter Jmsg type=%d\n", type);
996 /* Special case for the console, which has a dir_bsock and JobId==0,
997 * in that case, we send the message directly back to the
1000 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1001 BSOCK *dir = jcr->dir_bsock;
1002 va_start(arg_ptr, fmt);
1003 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1006 bnet_send(jcr->dir_bsock);
1013 msgs = jcr->jcr_msgs;
1017 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1020 job = ""; /* Set null job name if none */
1024 * Check if we have a message destination defined.
1025 * We always report M_ABORT and M_ERROR_TERM
1027 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1028 !bit_is_set(type, msgs->send_msg)) {
1029 return; /* no destination */
1033 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1036 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1039 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1041 set_jcr_job_status(jcr, JS_FatalError);
1045 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1051 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1054 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1057 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1061 va_start(arg_ptr, fmt);
1062 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1065 dispatch_message(jcr, type, mtime, rbuf);
1067 if (type == M_ABORT){
1069 p[0] = 0; /* generate segmentation violation */
1071 if (type == M_ERROR_TERM) {
1077 * If we come here, prefix the message with the file:line-number,
1078 * then pass it on to the normal Jmsg routine.
1080 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1086 pool_buf = get_pool_memory(PM_EMSG);
1087 i = Mmsg(pool_buf, "%s:%d ", file, line);
1090 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1091 va_start(arg_ptr, fmt);
1092 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1094 if (len < 0 || len >= (maxlen-5)) {
1095 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1101 Jmsg(jcr, type, mtime, "%s", pool_buf);
1102 free_memory(pool_buf);
1107 * Edit a message into a Pool memory buffer, with file:lineno
1109 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1114 i = sprintf(*pool_buf, "%s:%d ", file, line);
1117 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1118 va_start(arg_ptr, fmt);
1119 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1121 if (len < 0 || len >= (maxlen-5)) {
1122 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1130 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1135 i = sprintf(pool_buf, "%s:%d ", file, line);
1138 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1139 va_start(arg_ptr, fmt);
1140 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1142 if (len < 0 || len >= (maxlen-5)) {
1143 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1153 * Edit a message into a Pool Memory buffer NO file:lineno
1154 * Returns: string length of what was edited.
1156 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1162 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1163 va_start(arg_ptr, fmt);
1164 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1166 if (len < 0 || len >= (maxlen-5)) {
1167 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1175 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1181 maxlen = sizeof_pool_memory(pool_buf) - 1;
1182 va_start(arg_ptr, fmt);
1183 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1185 if (len < 0 || len >= (maxlen-5)) {
1186 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1194 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1200 maxlen = pool_buf.max_size() - 1;
1201 va_start(arg_ptr, fmt);
1202 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1204 if (len < 0 || len >= (maxlen-5)) {
1205 pool_buf.realloc_pm(maxlen + maxlen/2);
1214 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1217 * We queue messages rather than print them directly. This
1218 * is generally used in low level routines (msg handler, bnet)
1219 * to prevent recursion (i.e. if you are in the middle of
1220 * sending a message, it is a bit messy to recursively call
1221 * yourself when the bnet packet is not reentrant).
1223 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1230 pool_buf = get_pool_memory(PM_EMSG);
1233 maxlen = sizeof_pool_memory(pool_buf) - 1;
1234 va_start(arg_ptr, fmt);
1235 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1237 if (len < 0 || len >= (maxlen-5)) {
1238 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1243 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1245 item->mtime = time(NULL);
1246 strcpy(item->msg, pool_buf);
1247 /* If no jcr or dequeuing send to daemon to avoid recursion */
1248 if (!jcr || jcr->dequeuing) {
1249 /* jcr==NULL => daemon message, safe to send now */
1250 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1253 /* Queue message for later sending */
1255 jcr->msg_queue->append(item);
1258 free_memory(pool_buf);
1264 void dequeue_messages(JCR *jcr)
1268 jcr->dequeuing = true;
1269 foreach_dlist(item, jcr->msg_queue) {
1270 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1272 jcr->msg_queue->destroy();
1273 jcr->dequeuing = false;
1279 * If we come here, prefix the message with the file:line-number,
1280 * then pass it on to the normal Qmsg routine.
1282 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1288 pool_buf = get_pool_memory(PM_EMSG);
1289 i = Mmsg(pool_buf, "%s:%d ", file, line);
1292 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1293 va_start(arg_ptr, fmt);
1294 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1296 if (len < 0 || len >= (maxlen-5)) {
1297 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1303 Qmsg(jcr, type, mtime, "%s", pool_buf);
1304 free_memory(pool_buf);