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 ammended 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));
195 for (i=1; i<=M_MAX; i++) {
197 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
199 add_msg_dest(daemon_msgs, MD_SYSLOG, i, NULL, NULL);
201 Dmsg1(050, "Create daemon global message resource 0x%x\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 0x%x to 0x%x\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=%x 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=%x 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=%x 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=%x 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.mail.%s.%d", working_directory, my_name,
349 jcr->Job, (int)(long)d);
351 Mmsg(name, "%s/%s.mail.%s.%d", 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: Bacula Message\r\n\r\n");
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(850, "Close_msg jcr=0x%x\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 0x%x\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 fwrite(dt, dtlen, 1, con_fd);
620 fwrite(msg, len, 1, con_fd);
621 if (msg[len-1] != '\n') {
622 fwrite("\n", 2, 1, con_fd);
625 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.
790 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory ? working_directory : ".");
791 trace_fd = fopen(buf, "a+");
794 fputs(buf, trace_fd);
797 } else { /* not tracing */
804 * Set trace flag on/off. If argument is negative, there is no change
806 void set_trace(int trace_flag)
808 if (trace_flag < 0) {
810 } else if (trace_flag > 0) {
815 if (!trace && trace_fd) {
816 FILE *ltrace_fd = trace_fd;
818 bmicrosleep(0, 100000); /* yield to prevent seg faults */
828 /*********************************************************************
830 * This subroutine prints a message regardless of the debug level
832 * If the level is negative, the details of file and line number
836 p_msg(const char *file, int line, int level, const char *fmt,...)
844 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
851 va_start(arg_ptr, fmt);
852 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
858 /*********************************************************************
860 * subroutine writes a debug message to the trace file if the level number
861 * is less than or equal the debug_level. File and line numbers
862 * are included for more detail if desired, but not currently
865 * If the level is negative, the details of file and line number
869 t_msg(const char *file, int line, int level, const char *fmt,...)
881 if (level <= debug_level) {
883 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
884 trace_fd = fopen(buf, "a+");
889 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, file, line);
896 va_start(arg_ptr, fmt);
897 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
899 if (trace_fd != NULL) {
900 fputs(buf, trace_fd);
908 /* *********************************************************
910 * print an error message
914 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
921 * Check if we have a message destination defined.
922 * We always report M_ABORT and M_ERROR_TERM
924 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
925 !bit_is_set(type, daemon_msgs->send_msg))) {
926 return; /* no destination */
930 len = bsnprintf(buf, sizeof(buf), "%s: ABORTING due to ERROR in %s:%d\n",
931 my_name, file, line);
934 len = bsnprintf(buf, sizeof(buf), "%s: ERROR TERMINATION at %s:%d\n",
935 my_name, file, line);
938 if (level == -1) /* skip details */
939 len = bsnprintf(buf, sizeof(buf), "%s: Fatal Error because: ", my_name);
941 len = bsnprintf(buf, sizeof(buf), "%s: Fatal Error at %s:%d because:\n", my_name, file, line);
944 if (level == -1) /* skip details */
945 len = bsnprintf(buf, sizeof(buf), "%s: ERROR: ", my_name);
947 len = bsnprintf(buf, sizeof(buf), "%s: ERROR in %s:%d ", my_name, file, line);
950 len = bsnprintf(buf, sizeof(buf), "%s: Warning: ", my_name);
953 len = bsnprintf(buf, sizeof(buf), "%s: Security violation: ", my_name);
956 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
960 va_start(arg_ptr, fmt);
961 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
964 dispatch_message(NULL, type, 0, buf);
966 if (type == M_ABORT) {
968 p[0] = 0; /* generate segmentation violation */
970 if (type == M_ERROR_TERM) {
975 /* *********************************************************
977 * Generate a Job message
981 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
990 Dmsg1(850, "Enter Jmsg type=%d\n", type);
992 /* Special case for the console, which has a dir_bsock and JobId==0,
993 * in that case, we send the message directly back to the
996 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
997 BSOCK *dir = jcr->dir_bsock;
998 va_start(arg_ptr, fmt);
999 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1002 bnet_send(jcr->dir_bsock);
1009 msgs = jcr->jcr_msgs;
1013 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1016 job = ""; /* Set null job name if none */
1020 * Check if we have a message destination defined.
1021 * We always report M_ABORT and M_ERROR_TERM
1023 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1024 !bit_is_set(type, msgs->send_msg)) {
1025 return; /* no destination */
1029 len = bsnprintf(rbuf, sizeof(rbuf), "%s ABORTING due to ERROR\n", my_name);
1032 len = bsnprintf(rbuf, sizeof(rbuf), "%s ERROR TERMINATION\n", my_name);
1035 len = bsnprintf(rbuf, sizeof(rbuf), "%s: %s Fatal error: ", my_name, job);
1037 set_jcr_job_status(jcr, JS_FatalError);
1041 len = bsnprintf(rbuf, sizeof(rbuf), "%s: %s Error: ", my_name, job);
1047 len = bsnprintf(rbuf, sizeof(rbuf), "%s: %s Warning: ", my_name, job);
1050 len = bsnprintf(rbuf, sizeof(rbuf), "%s: %s Security violation: ", my_name, job);
1053 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1057 va_start(arg_ptr, fmt);
1058 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1061 dispatch_message(jcr, type, mtime, rbuf);
1063 if (type == M_ABORT){
1065 p[0] = 0; /* generate segmentation violation */
1067 if (type == M_ERROR_TERM) {
1073 * If we come here, prefix the message with the file:line-number,
1074 * then pass it on to the normal Jmsg routine.
1076 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1082 pool_buf = get_pool_memory(PM_EMSG);
1083 i = Mmsg(pool_buf, "%s:%d ", file, line);
1086 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1087 va_start(arg_ptr, fmt);
1088 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1090 if (len < 0 || len >= (maxlen-5)) {
1091 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1097 Jmsg(jcr, type, mtime, "%s", pool_buf);
1098 free_memory(pool_buf);
1103 * Edit a message into a Pool memory buffer, with file:lineno
1105 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1110 i = sprintf(*pool_buf, "%s:%d ", file, line);
1113 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1114 va_start(arg_ptr, fmt);
1115 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1117 if (len < 0 || len >= (maxlen-5)) {
1118 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1126 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1131 i = sprintf(pool_buf, "%s:%d ", file, line);
1134 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1135 va_start(arg_ptr, fmt);
1136 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1138 if (len < 0 || len >= (maxlen-5)) {
1139 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1149 * Edit a message into a Pool Memory buffer NO file:lineno
1150 * Returns: string length of what was edited.
1152 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1158 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1159 va_start(arg_ptr, fmt);
1160 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1162 if (len < 0 || len >= (maxlen-5)) {
1163 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1171 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1177 maxlen = sizeof_pool_memory(pool_buf) - 1;
1178 va_start(arg_ptr, fmt);
1179 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1181 if (len < 0 || len >= (maxlen-5)) {
1182 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1190 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1196 maxlen = pool_buf.max_size() - 1;
1197 va_start(arg_ptr, fmt);
1198 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1200 if (len < 0 || len >= (maxlen-5)) {
1201 pool_buf.realloc_pm(maxlen + maxlen/2);
1210 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1213 * We queue messages rather than print them directly. This
1214 * is generally used in low level routines (msg handler, bnet)
1215 * to prevent recursion (i.e. if you are in the middle of
1216 * sending a message, it is a bit messy to recursively call
1217 * yourself when the bnet packet is not reentrant).
1219 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1226 pool_buf = get_pool_memory(PM_EMSG);
1229 maxlen = sizeof_pool_memory(pool_buf) - 1;
1230 va_start(arg_ptr, fmt);
1231 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1233 if (len < 0 || len >= (maxlen-5)) {
1234 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1239 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1241 item->mtime = time(NULL);
1242 strcpy(item->msg, pool_buf);
1243 /* If no jcr or dequeuing send to daemon to avoid recursion */
1244 if (!jcr || jcr->dequeuing) {
1245 /* jcr==NULL => daemon message, safe to send now */
1246 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1249 /* Queue message for later sending */
1251 jcr->msg_queue->append(item);
1253 // Dmsg1(000, "queue item=%lu\n", (long unsigned)item);
1255 free_memory(pool_buf);
1261 void dequeue_messages(JCR *jcr)
1265 jcr->dequeuing = true;
1266 foreach_dlist(item, jcr->msg_queue) {
1267 // Dmsg1(000, "dequeue item=%lu\n", (long unsigned)item);
1268 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1270 jcr->msg_queue->destroy();
1271 jcr->dequeuing = false;
1277 * If we come here, prefix the message with the file:line-number,
1278 * then pass it on to the normal Qmsg routine.
1280 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1286 pool_buf = get_pool_memory(PM_EMSG);
1287 i = Mmsg(pool_buf, "%s:%d ", file, line);
1290 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1291 va_start(arg_ptr, fmt);
1292 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1294 if (len < 0 || len >= (maxlen-5)) {
1295 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1301 Qmsg(jcr, type, mtime, "%s", pool_buf);
1302 free_memory(pool_buf);