]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
Detect mount/junction points and ignore junctions in Windows
[bacula/bacula] / bacula / src / lib / message.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Bacula message handling routines
30  *
31  * NOTE: don't use any Jmsg or Qmsg calls within this file,
32  *   except in q_msg or j_msg (setup routines), 
33  *   otherwise you may get into recursive calls if there are
34  *   errors, and that can lead to looping or deadlocks.
35  *
36  *   Kern Sibbald, April 2000
37  *
38  */
39
40 #include "bacula.h"
41 #include "jcr.h"
42
43 sql_query_func p_sql_query = NULL;
44 sql_escape_func p_sql_escape = NULL;
45
46 #define FULL_LOCATION 1               /* set for file:line in Debug messages */
47
48 /*
49  *  This is where we define "Globals" because all the
50  *    daemons include this file.
51  */
52 const char *working_directory = NULL;       /* working directory path stored here */
53 int verbose = 0;                      /* increase User messages */
54 int debug_level = 0;                  /* debug level */
55 bool dbg_timestamp = false;           /* print timestamp in debug output */
56 bool prt_kaboom = false;              /* Print kaboom output */
57 utime_t daemon_start_time = 0;        /* Daemon start time */
58 const char *version = VERSION " (" BDATE ")";
59 const char *dist_name = DISTNAME " " DISTVER;
60 const int beef = BEEF;
61 char my_name[30] = {0};               /* daemon name is stored here */
62 char host_name[50] = {0};             /* host machine name */
63 char *exepath = (char *)NULL;
64 char *exename = (char *)NULL;
65 int console_msg_pending = false;
66 char con_fname[500];                  /* Console filename */
67 FILE *con_fd = NULL;                  /* Console file descriptor */
68 brwlock_t con_lock;                   /* Console lock structure */
69
70 /* Forward referenced functions */
71
72 /* Imported functions */
73 void create_jcr_key();
74
75 /* Static storage */
76
77 /* Allow only one thread to tweak d->fd at a time */
78 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static MSGS *daemon_msgs;              /* global messages */
80 static char *catalog_db = NULL;       /* database type */
81 static void (*message_callback)(int type, char *msg) = NULL;
82 static FILE *trace_fd = NULL;
83 #if defined(HAVE_WIN32)
84 static bool trace = true;
85 #else
86 static bool trace = false;
87 #endif
88
89 /* Constants */
90 const char *host_os = HOST_OS;
91 const char *distname = DISTNAME;
92 const char *distver = DISTVER;
93
94 /* Some message class methods */
95 void MSGS::lock()
96 {
97    P(fides_mutex);
98 }
99
100 void MSGS::unlock()
101 {
102    V(fides_mutex);
103 }
104
105 /*
106  * Wait for not in use variable to be clear
107  */
108 void MSGS::wait_not_in_use()     /* leaves fides_mutex set */
109 {
110    lock();
111    while (m_in_use) {
112       unlock();
113       bmicrosleep(0, 200);         /* wait */
114       lock();
115    }
116 }
117
118 /*
119  * Handle message delivery errors
120  */
121 static void delivery_error(const char *fmt,...)
122 {
123    va_list   arg_ptr;
124    int i, len, maxlen;
125    POOLMEM *pool_buf;
126    char dt[MAX_TIME_LENGTH];
127    int dtlen;
128
129    pool_buf = get_pool_memory(PM_EMSG);
130
131    bstrftime_ny(dt, sizeof(dt), time(NULL));
132    dtlen = strlen(dt);
133    dt[dtlen++] = ' ';
134    dt[dtlen] = 0;
135
136    i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
137
138    for (;;) {
139       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
140       va_start(arg_ptr, fmt);
141       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
142       va_end(arg_ptr);
143       if (len < 0 || len >= (maxlen-5)) {
144          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
145          continue;
146       }
147       break;
148    }
149
150    fputs(pool_buf, stdout);  /* print this here to INSURE that it is printed */
151    fflush(stdout);
152    syslog(LOG_DAEMON|LOG_ERR, "%s", pool_buf);
153    free_memory(pool_buf);
154 }                 
155
156 void register_message_callback(void msg_callback(int type, char *msg))
157 {
158    message_callback = msg_callback;
159 }
160
161
162 /*
163  * Set daemon name. Also, find canonical execution
164  *  path.  Note, exepath has spare room for tacking on
165  *  the exename so that we can reconstruct the full name.
166  *
167  * Note, this routine can get called multiple times
168  *  The second time is to put the name as found in the
169  *  Resource record. On the second call, generally,
170  *  argv is NULL to avoid doing the path code twice.
171  */
172 void my_name_is(int argc, char *argv[], const char *name)
173 {
174    char *l, *p, *q;
175    char cpath[1024];
176    int len;
177
178    if (gethostname(host_name, sizeof(host_name)) != 0) {
179       bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
180    }
181    bstrncpy(my_name, name, sizeof(my_name));
182    if (argc>0 && argv && argv[0]) {
183       /* strip trailing filename and save exepath */
184       for (l=p=argv[0]; *p; p++) {
185          if (IsPathSeparator(*p)) {
186             l = p;                       /* set pos of last slash */
187          }
188       }
189       if (IsPathSeparator(*l)) {
190          l++;
191       } else {
192          l = argv[0];
193 #if defined(HAVE_WIN32)
194          /* On Windows allow c: junk */
195          if (l[1] == ':') {
196             l += 2;
197          }
198 #endif
199       }
200       len = strlen(l) + 1;
201       if (exename) {
202          free(exename);
203       }
204       exename = (char *)malloc(len);
205       strcpy(exename, l);
206
207       if (exepath) {
208          free(exepath);
209       }
210       exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
211       for (p=argv[0],q=exepath; p < l; ) {
212          *q++ = *p++;
213       }
214       *q = 0;
215       if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
216          if (getcwd(cpath, sizeof(cpath))) {
217             free(exepath);
218             exepath = (char *)malloc(strlen(cpath) + 1 + len);
219             strcpy(exepath, cpath);
220          }
221       }
222       Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
223    }
224 }
225
226 void
227 set_db_type(const char *name)
228 {
229    if (catalog_db != NULL) {
230       free(catalog_db);
231    }
232    catalog_db = bstrdup(name);
233 }
234
235 /*
236  * Initialize message handler for a daemon or a Job
237  *   We make a copy of the MSGS resource passed, so it belows
238  *   to the job or daemon and thus can be modified.
239  *
240  *   NULL for jcr -> initialize global messages for daemon
241  *   non-NULL     -> initialize jcr using Message resource
242  */
243 void
244 init_msg(JCR *jcr, MSGS *msg)
245 {
246    DEST *d, *dnew, *temp_chain = NULL;
247    int i;
248
249    if (jcr == NULL && msg == NULL) {
250       init_last_jobs_list();
251       /* Create a daemon key then set invalid jcr */
252       /* Maybe we should give the daemon a jcr??? */
253       create_jcr_key();
254       set_jcr_in_tsd(INVALID_JCR);
255    }
256
257 #if !defined(HAVE_WIN32)
258    /*
259     * Make sure we have fd's 0, 1, 2 open
260     *  If we don't do this one of our sockets may open
261     *  there and if we then use stdout, it could
262     *  send total garbage to our socket.
263     *
264     */
265    int fd;
266    fd = open("/dev/null", O_RDONLY, 0644);
267    if (fd > 2) {
268       close(fd);
269    } else {
270       for(i=1; fd + i <= 2; i++) {
271          dup2(fd, fd+i);
272       }
273    }
274
275 #endif
276    /*
277     * If msg is NULL, initialize global chain for STDOUT and syslog
278     */
279    if (msg == NULL) {
280       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
281       memset(daemon_msgs, 0, sizeof(MSGS));
282       for (i=1; i<=M_MAX; i++) {
283          add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
284       }
285       Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
286       return;
287    }
288
289    /*
290     * Walk down the message resource chain duplicating it
291     * for the current Job.
292     */
293    for (d=msg->dest_chain; d; d=d->next) {
294       dnew = (DEST *)malloc(sizeof(DEST));
295       memcpy(dnew, d, sizeof(DEST));
296       dnew->next = temp_chain;
297       dnew->fd = NULL;
298       dnew->mail_filename = NULL;
299       if (d->mail_cmd) {
300          dnew->mail_cmd = bstrdup(d->mail_cmd);
301       }
302       if (d->where) {
303          dnew->where = bstrdup(d->where);
304       }
305       temp_chain = dnew;
306    }
307
308    if (jcr) {
309       jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
310       memset(jcr->jcr_msgs, 0, sizeof(MSGS));
311       jcr->jcr_msgs->dest_chain = temp_chain;
312       memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
313    } else {
314       /* If we have default values, release them now */
315       if (daemon_msgs) {
316          free_msgs_res(daemon_msgs);
317       }
318       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
319       memset(daemon_msgs, 0, sizeof(MSGS));
320       daemon_msgs->dest_chain = temp_chain;
321       memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
322    }
323
324    Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
325
326 }
327
328 /* Initialize so that the console (User Agent) can
329  * receive messages -- stored in a file.
330  */
331 void init_console_msg(const char *wd)
332 {
333    int fd;
334
335    bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
336    fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
337    if (fd == -1) {
338       berrno be;
339       Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
340           con_fname, be.bstrerror());
341    }
342    if (lseek(fd, 0, SEEK_END) > 0) {
343       console_msg_pending = 1;
344    }
345    close(fd);
346    con_fd = fopen(con_fname, "a+b");
347    if (!con_fd) {
348       berrno be;
349       Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
350           con_fname, be.bstrerror());
351    }
352    if (rwl_init(&con_lock) != 0) {
353       berrno be;
354       Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
355          be.bstrerror());
356    }
357 }
358
359 /*
360  * Called only during parsing of the config file.
361  *
362  * Add a message destination. I.e. associate a message type with
363  *  a destination (code).
364  * Note, where in the case of dest_code FILE is a filename,
365  *  but in the case of MAIL is a space separated list of
366  *  email addresses, ...
367  */
368 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
369 {
370    DEST *d;
371    /*
372     * First search the existing chain and see if we
373     * can simply add this msg_type to an existing entry.
374     */
375    for (d=msg->dest_chain; d; d=d->next) {
376       if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
377                      (strcmp(where, d->where) == 0))) {
378          Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
379              d, msg_type, dest_code, NPRT(where));
380          set_bit(msg_type, d->msg_types);
381          set_bit(msg_type, msg->send_msg);  /* set msg_type bit in our local */
382          return;
383       }
384    }
385    /* Not found, create a new entry */
386    d = (DEST *)malloc(sizeof(DEST));
387    memset(d, 0, sizeof(DEST));
388    d->next = msg->dest_chain;
389    d->dest_code = dest_code;
390    set_bit(msg_type, d->msg_types);      /* set type bit in structure */
391    set_bit(msg_type, msg->send_msg);     /* set type bit in our local */
392    if (where) {
393       d->where = bstrdup(where);
394    }
395    if (mail_cmd) {
396       d->mail_cmd = bstrdup(mail_cmd);
397    }
398    Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
399           d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
400    msg->dest_chain = d;
401 }
402
403 /*
404  * Called only during parsing of the config file.
405  *
406  * Remove a message destination
407  */
408 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
409 {
410    DEST *d;
411
412    for (d=msg->dest_chain; d; d=d->next) {
413       Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
414       if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
415           ((where == NULL && d->where == NULL) ||
416                      (strcmp(where, d->where) == 0))) {
417          Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
418                d, msg_type, dest_code);
419          clear_bit(msg_type, d->msg_types);
420          Dmsg0(850, "Return rem_msg_dest\n");
421          return;
422       }
423    }
424 }
425
426
427 /*
428  * Create a unique filename for the mail command
429  */
430 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
431 {
432    if (jcr) {
433       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
434                  jcr->Job, (int)(intptr_t)d);
435    } else {
436       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
437                  my_name, (int)(intptr_t)d);
438    }
439    Dmsg1(850, "mailname=%s\n", name);
440 }
441
442 /*
443  * Open a mail pipe
444  */
445 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
446 {
447    BPIPE *bpipe;
448
449    if (d->mail_cmd) {
450       cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
451    } else {
452       Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
453    }
454    fflush(stdout);
455
456    if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
457       /* If we had to use sendmail, add subject */
458       if (!d->mail_cmd) {
459          fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
460       }
461    } else {
462       berrno be;
463       delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
464          cmd, be.bstrerror());
465    }
466    return bpipe;
467 }
468
469 /*
470  * Close the messages for this Messages resource, which means to close
471  *  any open files, and dispatch any pending email messages.
472  */
473 void close_msg(JCR *jcr)
474 {
475    MSGS *msgs;
476    DEST *d;
477    BPIPE *bpipe;
478    POOLMEM *cmd, *line;
479    int len, stat;
480
481    Dmsg1(580, "Close_msg jcr=%p\n", jcr);
482
483    if (jcr == NULL) {                /* NULL -> global chain */
484       msgs = daemon_msgs;
485    } else {
486       msgs = jcr->jcr_msgs;
487       jcr->jcr_msgs = NULL;
488    }
489    if (msgs == NULL) {
490       return;
491    }
492
493    /* Wait for item to be not in use, then mark closing */
494    if (msgs->is_closing()) {
495       return;
496    }
497    msgs->wait_not_in_use();          /* leaves fides_mutex set */
498    msgs->set_closing();
499    msgs->unlock();
500
501    Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
502    cmd = get_pool_memory(PM_MESSAGE);
503    for (d=msgs->dest_chain; d; ) {
504       if (d->fd) {
505          switch (d->dest_code) {
506          case MD_FILE:
507          case MD_APPEND:
508             if (d->fd) {
509                fclose(d->fd);            /* close open file descriptor */
510                d->fd = NULL;
511             }
512             break;
513          case MD_MAIL:
514          case MD_MAIL_ON_ERROR:
515          case MD_MAIL_ON_SUCCESS:
516             Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
517             if (!d->fd) {
518                break;
519             }
520             if (
521                 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
522                   (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) 
523                 ||
524                 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
525                  jcr->JobStatus == JS_ErrorTerminated)
526                 ) {
527                goto rem_temp_file;
528             }
529
530             if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
531                Pmsg0(000, _("open mail pipe failed.\n"));
532                goto rem_temp_file;
533             }
534             Dmsg0(850, "Opened mail pipe\n");
535             len = d->max_len+10;
536             line = get_memory(len);
537             rewind(d->fd);
538             while (fgets(line, len, d->fd)) {
539                fputs(line, bpipe->wfd);
540             }
541             if (!close_wpipe(bpipe)) {       /* close write pipe sending mail */
542                berrno be;
543                Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
544             }
545
546             /*
547              * Since we are closing all messages, before "recursing"
548              * make sure we are not closing the daemon messages, otherwise
549              * kaboom.
550              */
551             if (msgs != daemon_msgs) {
552                /* read what mail prog returned -- should be nothing */
553                while (fgets(line, len, bpipe->rfd)) {
554                   delivery_error(_("Mail prog: %s"), line);
555                }
556             }
557
558             stat = close_bpipe(bpipe);
559             if (stat != 0 && msgs != daemon_msgs) {
560                berrno be;
561                be.set_errno(stat);
562                Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
563                delivery_error(_("Mail program terminated in error.\n"
564                                  "CMD=%s\n"
565                                  "ERR=%s\n"), cmd, be.bstrerror());
566             }
567             free_memory(line);
568 rem_temp_file:
569             /* Remove temp file */
570             fclose(d->fd);
571             d->fd = NULL;
572             unlink(d->mail_filename);
573             free_pool_memory(d->mail_filename);
574             d->mail_filename = NULL;
575             Dmsg0(850, "end mail or mail on error\n");
576             break;
577          default:
578             break;
579          }
580          d->fd = NULL;
581       }
582       d = d->next;                    /* point to next buffer */
583    }
584    free_pool_memory(cmd);
585    Dmsg0(850, "Done walking message chain.\n");
586    if (jcr) {
587       free_msgs_res(msgs);
588       msgs = NULL;
589    } else {
590       msgs->clear_closing();
591    }
592    Dmsg0(850, "===End close msg resource\n");
593 }
594
595 /*
596  * Free memory associated with Messages resource
597  */
598 void free_msgs_res(MSGS *msgs)
599 {
600    DEST *d, *old;
601
602    /* Walk down the message chain releasing allocated buffers */
603    for (d=msgs->dest_chain; d; ) {
604       if (d->where) {
605          free(d->where);
606       }
607       if (d->mail_cmd) {
608          free(d->mail_cmd);
609       }
610       old = d;                        /* save pointer to release */
611       d = d->next;                    /* point to next buffer */
612       free(old);                      /* free the destination item */
613    }
614    msgs->dest_chain = NULL;
615    free(msgs);                        /* free the head */
616 }
617
618
619 /*
620  * Terminate the message handler for good.
621  * Release the global destination chain.
622  *
623  * Also, clean up a few other items (cons, exepath). Note,
624  *   these really should be done elsewhere.
625  */
626 void term_msg()
627 {
628    Dmsg0(850, "Enter term_msg\n");
629    close_msg(NULL);                   /* close global chain */
630    free_msgs_res(daemon_msgs);        /* free the resources */
631    daemon_msgs = NULL;
632    if (con_fd) {
633       fflush(con_fd);
634       fclose(con_fd);
635       con_fd = NULL;
636    }
637    if (exepath) {
638       free(exepath);
639       exepath = NULL;
640    }
641    if (exename) {
642       free(exename);
643       exename = NULL;
644    }
645    if (trace_fd) {
646       fclose(trace_fd);
647       trace_fd = NULL;
648    }
649    if (catalog_db) {
650       free(catalog_db);
651       catalog_db = NULL;
652    }
653    term_last_jobs_list();
654 }
655
656 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode) 
657 {
658    d->fd = fopen(d->where, mode);
659    if (!d->fd) {
660       berrno be;
661       delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
662       return false;
663    }
664    return true;
665 }
666
667 /*
668  * Handle sending the message to the appropriate place
669  */
670 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
671 {
672     DEST *d;
673     char dt[MAX_TIME_LENGTH];
674     POOLMEM *mcmd;
675     int len, dtlen;
676     MSGS *msgs;
677     BPIPE *bpipe;
678     const char *mode;
679
680     Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
681
682     /*
683      * Most messages are prefixed by a date and time. If mtime is
684      *  zero, then we use the current time.  If mtime is 1 (special
685      *  kludge), we do not prefix the date and time. Otherwise,
686      *  we assume mtime is a utime_t and use it.
687      */
688     if (mtime == 0) {
689        mtime = time(NULL);
690     }
691     if (mtime == 1) {
692        *dt = 0;
693        dtlen = 0;
694        mtime = time(NULL);      /* get time for SQL log */
695     } else {
696        bstrftime_ny(dt, sizeof(dt), mtime);
697        dtlen = strlen(dt);
698        dt[dtlen++] = ' ';
699        dt[dtlen] = 0;
700     }
701
702     /* If the program registered a callback, send it there */
703     if (message_callback) {
704        message_callback(type, msg);
705        return;
706     }
707
708     /* For serious errors make sure message is printed or logged */
709     if (type == M_ABORT || type == M_ERROR_TERM) {
710        fputs(dt, stdout);
711        fputs(msg, stdout);
712        fflush(stdout);
713        if (type == M_ABORT) {
714           syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
715        }
716     }
717
718
719     /* Now figure out where to send the message */
720     msgs = NULL;
721     if (!jcr) {
722        jcr = get_jcr_from_tsd();
723     }
724     if (jcr) {
725        msgs = jcr->jcr_msgs;
726     }
727     if (msgs == NULL) {
728        msgs = daemon_msgs;
729     }
730     /*
731      * If closing this message resource, print and send to syslog,
732      *   then get out.
733      */
734     if (msgs->is_closing()) {
735        fputs(dt, stdout);
736        fputs(msg, stdout);
737        fflush(stdout);
738        syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
739        return;
740     }
741
742     for (d=msgs->dest_chain; d; d=d->next) {
743        if (bit_is_set(type, d->msg_types)) {
744           switch (d->dest_code) {
745              case MD_CATALOG:
746                 char ed1[50];
747                 if (!jcr || !jcr->db) {
748                    break;
749                 }
750                 if (p_sql_query && p_sql_escape) {
751                    POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
752                    POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
753                    
754                    int len = strlen(msg) + 1;
755                    esc_msg = check_pool_memory_size(esc_msg, len*2+1);
756                    p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
757
758                    bstrutime(dt, sizeof(dt), mtime);
759                    Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
760                          edit_int64(jcr->JobId, ed1), dt, esc_msg);
761                    p_sql_query(jcr, cmd);
762                    
763                    free_pool_memory(cmd);
764                    free_pool_memory(esc_msg);
765                 }
766                 break;
767              case MD_CONSOLE:
768                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
769                 if (!con_fd) {
770                    con_fd = fopen(con_fname, "a+b");
771                    Dmsg0(850, "Console file not open.\n");
772                 }
773                 if (con_fd) {
774                    Pw(con_lock);      /* get write lock on console message file */
775                    errno = 0;
776                    if (dtlen) {
777                       (void)fwrite(dt, dtlen, 1, con_fd);
778                    }
779                    len = strlen(msg);
780                    if (len > 0) {
781                       (void)fwrite(msg, len, 1, con_fd);
782                       if (msg[len-1] != '\n') {
783                          (void)fwrite("\n", 2, 1, con_fd);
784                       }
785                    } else {
786                       (void)fwrite("\n", 2, 1, con_fd);
787                    }
788                    fflush(con_fd);
789                    console_msg_pending = true;
790                    Vw(con_lock);
791                 }
792                 break;
793              case MD_SYSLOG:
794                 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
795                 /*
796                  * We really should do an openlog() here.
797                  */
798                 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
799                 break;
800              case MD_OPERATOR:
801                 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
802                 mcmd = get_pool_memory(PM_MESSAGE);
803                 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
804                    int stat;
805                    fputs(dt, bpipe->wfd);
806                    fputs(msg, bpipe->wfd);
807                    /* Messages to the operator go one at a time */
808                    stat = close_bpipe(bpipe);
809                    if (stat != 0) {
810                       berrno be;
811                       be.set_errno(stat);
812                       delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
813                             "CMD=%s\n"
814                             "ERR=%s\n"), mcmd, be.bstrerror());
815                    }
816                 }
817                 free_pool_memory(mcmd);
818                 break;
819              case MD_MAIL:
820              case MD_MAIL_ON_ERROR:
821              case MD_MAIL_ON_SUCCESS:
822                 Dmsg1(850, "MAIL for following msg: %s", msg);
823                 if (msgs->is_closing()) {
824                    break;
825                 }
826                 msgs->set_in_use();
827                 if (!d->fd) {
828                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
829                    make_unique_mail_filename(jcr, name, d);
830                    d->fd = fopen(name, "w+b");
831                    if (!d->fd) {
832                       berrno be;
833                       delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
834                             be.bstrerror());
835                       free_pool_memory(name);
836                       V(fides_mutex);
837                       break;
838                    }
839                    d->mail_filename = name;
840                 }
841                 fputs(dt, d->fd);
842                 len = strlen(msg) + dtlen;;
843                 if (len > d->max_len) {
844                    d->max_len = len;      /* keep max line length */
845                 }
846                 fputs(msg, d->fd);
847                 msgs->clear_in_use();
848                 break;
849              case MD_APPEND:
850                 Dmsg1(850, "APPEND for following msg: %s", msg);
851                 mode = "ab";
852                 goto send_to_file;
853              case MD_FILE:
854                 Dmsg1(850, "FILE for following msg: %s", msg);
855                 mode = "w+b";
856 send_to_file:
857                 if (msgs->is_closing()) {
858                    break;
859                 }
860                 msgs->set_in_use();
861                 if (!d->fd && !open_dest_file(jcr, d, mode)) {
862                    msgs->clear_in_use();
863                    break;
864                 }
865                 fputs(dt, d->fd);
866                 fputs(msg, d->fd);
867                 /* On error, we close and reopen to handle log rotation */
868                 if (ferror(d->fd)) {
869                    fclose(d->fd);
870                    d->fd = NULL;
871                    if (open_dest_file(jcr, d, mode)) {
872                       fputs(dt, d->fd);
873                       fputs(msg, d->fd);
874                    }
875                 }
876                 msgs->clear_in_use();
877                 break;
878              case MD_DIRECTOR:
879                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
880                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
881                    jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
882                       jcr->Job, type, mtime, msg);
883                 } else {
884                    Dmsg1(800, "no jcr for following msg: %s", msg);
885                 }
886                 break;
887              case MD_STDOUT:
888                 Dmsg1(850, "STDOUT for following msg: %s", msg);
889                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
890                    fputs(dt, stdout);
891                    fputs(msg, stdout);
892                    fflush(stdout);
893                 }
894                 break;
895              case MD_STDERR:
896                 Dmsg1(850, "STDERR for following msg: %s", msg);
897                 fputs(dt, stderr);
898                 fputs(msg, stderr);
899                 fflush(stdout);
900                 break;
901              default:
902                 break;
903           }
904        }
905     }
906 }
907
908 /*********************************************************************
909  *
910  *  This subroutine returns the filename portion of a Windows 
911  *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
912  *  to the full path.
913  */
914
915 inline const char *
916 get_basename(const char *pathname)
917 {
918 #if defined(_MSC_VER)
919    const char *basename;
920    
921    if ((basename = strrchr(pathname, '\\')) == NULL) {
922       basename = pathname;
923    } else {
924       basename++;
925    }
926
927    return basename;
928 #else
929    return pathname;
930 #endif
931 }
932
933 /*
934  * print or write output to trace file 
935  */
936 static void pt_out(char *buf)
937 {
938     /*
939      * Used the "trace on" command in the console to turn on
940      *  output to the trace file.  "trace off" will close the file.
941      */
942     if (trace) {
943        if (!trace_fd) {
944           char fn[200];
945           bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
946           trace_fd = fopen(fn, "a+b");
947        }
948        if (trace_fd) {
949           fputs(buf, trace_fd);
950           fflush(trace_fd);
951           return;
952        } else {
953           /* Some problem, turn off tracing */
954           trace = false;
955        }
956     }
957     /* not tracing */
958     fputs(buf, stdout);
959     fflush(stdout);
960 }
961
962 /*********************************************************************
963  *
964  *  This subroutine prints a debug message if the level number
965  *  is less than or equal the debug_level. File and line numbers
966  *  are included for more detail if desired, but not currently
967  *  printed.
968  *
969  *  If the level is negative, the details of file and line number
970  *  are not printed.
971  */
972 void
973 d_msg(const char *file, int line, int level, const char *fmt,...)
974 {
975     char      buf[5000];
976     int       len;
977     va_list   arg_ptr;
978     bool      details = true;
979     utime_t   mtime;
980
981     if (level < 0) {
982        details = false;
983        level = -level;
984     }
985
986     if (level <= debug_level) {
987        if (dbg_timestamp) {
988           mtime = time(NULL);
989           bstrftimes(buf, sizeof(buf), mtime);
990           len = strlen(buf);
991           buf[len++] = ' ';
992           buf[len] = 0;
993           fputs(buf, stdout);
994        }
995     
996 #ifdef FULL_LOCATION
997        if (details) {
998           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ", 
999                 my_name, get_basename(file), line, get_jobid_from_tsd());
1000        } else {
1001           len = 0;
1002        }
1003 #else
1004        len = 0;
1005 #endif
1006        va_start(arg_ptr, fmt);
1007        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1008        va_end(arg_ptr);
1009
1010        pt_out(buf);
1011     }
1012 }
1013
1014 /*
1015  * Set trace flag on/off. If argument is negative, there is no change
1016  */
1017 void set_trace(int trace_flag)
1018 {
1019    if (trace_flag < 0) {
1020       return;
1021    } else if (trace_flag > 0) {
1022       trace = true;
1023    } else {
1024       trace = false;
1025    }
1026    if (!trace && trace_fd) {
1027       FILE *ltrace_fd = trace_fd;
1028       trace_fd = NULL;
1029       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
1030       fclose(ltrace_fd);
1031    }
1032 }
1033
1034 bool get_trace(void)
1035 {
1036    return trace;
1037 }
1038
1039 /*********************************************************************
1040  *
1041  *  This subroutine prints a message regardless of the debug level
1042  *
1043  *  If the level is negative, the details of file and line number
1044  *  are not printed.
1045  */
1046 void
1047 p_msg(const char *file, int line, int level, const char *fmt,...)
1048 {
1049     char      buf[5000];
1050     int       len;
1051     va_list   arg_ptr;
1052
1053 #ifdef FULL_LOCATION
1054     if (level >= 0) {
1055        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1056     } else {
1057        len = 0;
1058     }
1059 #else
1060     len = 0;
1061 #endif
1062     va_start(arg_ptr, fmt);
1063     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1064     va_end(arg_ptr);
1065
1066     pt_out(buf);     
1067 }
1068
1069
1070 /*********************************************************************
1071  *
1072  *  subroutine writes a debug message to the trace file if the level number
1073  *  is less than or equal the debug_level. File and line numbers
1074  *  are included for more detail if desired, but not currently
1075  *  printed.
1076  *
1077  *  If the level is negative, the details of file and line number
1078  *  are not printed.
1079  */
1080 void
1081 t_msg(const char *file, int line, int level, const char *fmt,...)
1082 {
1083     char      buf[5000];
1084     int       len;
1085     va_list   arg_ptr;
1086     int       details = TRUE;
1087
1088     if (level < 0) {
1089        details = FALSE;
1090        level = -level;
1091     }
1092
1093     if (level <= debug_level) {
1094        if (!trace_fd) {
1095           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1096           trace_fd = fopen(buf, "a+b");
1097        }
1098
1099 #ifdef FULL_LOCATION
1100        if (details) {
1101           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1102        } else {
1103           len = 0;
1104        }
1105 #else
1106        len = 0;
1107 #endif
1108        va_start(arg_ptr, fmt);
1109        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1110        va_end(arg_ptr);
1111        if (trace_fd != NULL) {
1112            fputs(buf, trace_fd);
1113            fflush(trace_fd);
1114        }
1115    }
1116 }
1117
1118 /* *********************************************************
1119  *
1120  * print an error message
1121  *
1122  */
1123 void
1124 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1125 {
1126     char     buf[5000];
1127     va_list   arg_ptr;
1128     int len;
1129
1130     /*
1131      * Check if we have a message destination defined.
1132      * We always report M_ABORT and M_ERROR_TERM
1133      */
1134     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1135                          !bit_is_set(type, daemon_msgs->send_msg))) {
1136        return;                        /* no destination */
1137     }
1138     switch (type) {
1139     case M_ABORT:
1140        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1141                my_name, get_basename(file), line);
1142        break;
1143     case M_ERROR_TERM:
1144        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1145                my_name, get_basename(file), line);
1146        break;
1147     case M_FATAL:
1148        if (level == -1)            /* skip details */
1149           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1150        else
1151           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1152        break;
1153     case M_ERROR:
1154        if (level == -1)            /* skip details */
1155           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1156        else
1157           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1158        break;
1159     case M_WARNING:
1160        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1161        break;
1162     case M_SECURITY:
1163        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1164        break;
1165     default:
1166        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1167        break;
1168     }
1169
1170     va_start(arg_ptr, fmt);
1171     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1172     va_end(arg_ptr);
1173
1174     dispatch_message(NULL, type, 0, buf);
1175
1176     if (type == M_ABORT) {
1177        char *p = 0;
1178        p[0] = 0;                      /* generate segmentation violation */
1179     }
1180     if (type == M_ERROR_TERM) {
1181        exit(1);
1182     }
1183 }
1184
1185 /* *********************************************************
1186  *
1187  * Generate a Job message
1188  *
1189  */
1190 void
1191 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1192 {
1193     char     rbuf[5000];
1194     va_list   arg_ptr;
1195     int len;
1196     MSGS *msgs;
1197     uint32_t JobId = 0;
1198
1199
1200     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1201
1202     /* Special case for the console, which has a dir_bsock and JobId==0,
1203      *  in that case, we send the message directly back to the
1204      *  dir_bsock.
1205      */
1206     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1207        BSOCK *dir = jcr->dir_bsock;
1208        va_start(arg_ptr, fmt);
1209        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1210                                 fmt, arg_ptr);
1211        va_end(arg_ptr);
1212        jcr->dir_bsock->send();
1213        return;
1214     }
1215
1216     /* The watchdog thread can't use Jmsg directly, we always queued it */
1217     if (is_watchdog()) {
1218        va_start(arg_ptr, fmt);
1219        bvsnprintf(rbuf,  sizeof(rbuf), fmt, arg_ptr);
1220        va_end(arg_ptr);
1221        Qmsg(jcr, type, mtime, "%s", rbuf);
1222        return;
1223     }
1224
1225     msgs = NULL;
1226     if (!jcr) {
1227        jcr = get_jcr_from_tsd();
1228     }
1229     if (jcr) {
1230        if (!jcr->dequeuing_msgs) { /* Avoid recursion */
1231           /* Dequeue messages to keep the original order  */
1232           dequeue_messages(jcr); 
1233        }
1234        msgs = jcr->jcr_msgs;
1235        JobId = jcr->JobId;
1236     }
1237     if (!msgs) {
1238        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1239     }
1240
1241     /*
1242      * Check if we have a message destination defined.
1243      * We always report M_ABORT and M_ERROR_TERM
1244      */
1245     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1246          !bit_is_set(type, msgs->send_msg)) {
1247        return;                        /* no destination */
1248     }
1249     switch (type) {
1250     case M_ABORT:
1251        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1252        break;
1253     case M_ERROR_TERM:
1254        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1255        break;
1256     case M_FATAL:
1257        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1258        if (jcr) {
1259           set_jcr_job_status(jcr, JS_FatalError);
1260        }
1261        if (jcr && jcr->JobErrors == 0) {
1262           jcr->JobErrors = 1;
1263        }
1264        break;
1265     case M_ERROR:
1266        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1267        if (jcr) {
1268           jcr->JobErrors++;
1269        }
1270        break;
1271     case M_WARNING:
1272        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1273        if (jcr) {
1274           jcr->JobWarnings++;
1275        }
1276        break;
1277     case M_SECURITY:
1278        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "), 
1279                my_name, JobId);
1280        break;
1281     default:
1282        len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1283        break;
1284     }
1285
1286     va_start(arg_ptr, fmt);
1287     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1288     va_end(arg_ptr);
1289
1290     dispatch_message(jcr, type, mtime, rbuf);
1291
1292     if (type == M_ABORT){
1293        char *p = 0;
1294        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1295        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1296        p[0] = 0;                      /* generate segmentation violation */
1297     }
1298     if (type == M_ERROR_TERM) {
1299        exit(1);
1300     }
1301 }
1302
1303 /*
1304  * If we come here, prefix the message with the file:line-number,
1305  *  then pass it on to the normal Jmsg routine.
1306  */
1307 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1308 {
1309    va_list   arg_ptr;
1310    int i, len, maxlen;
1311    POOLMEM *pool_buf;
1312
1313    pool_buf = get_pool_memory(PM_EMSG);
1314    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1315
1316    for (;;) {
1317       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1318       va_start(arg_ptr, fmt);
1319       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1320       va_end(arg_ptr);
1321       if (len < 0 || len >= (maxlen-5)) {
1322          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1323          continue;
1324       }
1325       break;
1326    }
1327
1328    Jmsg(jcr, type, mtime, "%s", pool_buf);
1329    free_memory(pool_buf);
1330 }
1331
1332
1333 /*
1334  * Edit a message into a Pool memory buffer, with file:lineno
1335  */
1336 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1337 {
1338    va_list   arg_ptr;
1339    int i, len, maxlen;
1340
1341    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1342
1343    for (;;) {
1344       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1345       va_start(arg_ptr, fmt);
1346       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1347       va_end(arg_ptr);
1348       if (len < 0 || len >= (maxlen-5)) {
1349          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1350          continue;
1351       }
1352       break;
1353    }
1354    return len;
1355 }
1356
1357 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1358 {
1359    va_list   arg_ptr;
1360    int i, len, maxlen;
1361
1362    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1363
1364    for (;;) {
1365       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1366       va_start(arg_ptr, fmt);
1367       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1368       va_end(arg_ptr);
1369       if (len < 0 || len >= (maxlen-5)) {
1370          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1371          continue;
1372       }
1373       break;
1374    }
1375    return len;
1376 }
1377
1378
1379 /*
1380  * Edit a message into a Pool Memory buffer NO file:lineno
1381  *  Returns: string length of what was edited.
1382  */
1383 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1384 {
1385    va_list   arg_ptr;
1386    int len, maxlen;
1387
1388    for (;;) {
1389       maxlen = sizeof_pool_memory(*pool_buf) - 1;
1390       va_start(arg_ptr, fmt);
1391       len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1392       va_end(arg_ptr);
1393       if (len < 0 || len >= (maxlen-5)) {
1394          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1395          continue;
1396       }
1397       break;
1398    }
1399    return len;
1400 }
1401
1402 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1403 {
1404    va_list   arg_ptr;
1405    int len, maxlen;
1406
1407    for (;;) {
1408       maxlen = sizeof_pool_memory(pool_buf) - 1;
1409       va_start(arg_ptr, fmt);
1410       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1411       va_end(arg_ptr);
1412       if (len < 0 || len >= (maxlen-5)) {
1413          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1414          continue;
1415       }
1416       break;
1417    }
1418    return len;
1419 }
1420
1421 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1422 {
1423    va_list   arg_ptr;
1424    int len, maxlen;
1425
1426    for (;;) {
1427       maxlen = pool_buf.max_size() - 1;
1428       va_start(arg_ptr, fmt);
1429       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1430       va_end(arg_ptr);
1431       if (len < 0 || len >= (maxlen-5)) {
1432          pool_buf.realloc_pm(maxlen + maxlen/2);
1433          continue;
1434       }
1435       break;
1436    }
1437    return len;
1438 }
1439
1440
1441 /*
1442  * We queue messages rather than print them directly. This
1443  *  is generally used in low level routines (msg handler, bnet)
1444  *  to prevent recursion (i.e. if you are in the middle of
1445  *  sending a message, it is a bit messy to recursively call
1446  *  yourself when the bnet packet is not reentrant).
1447  */
1448 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1449 {
1450    va_list   arg_ptr;
1451    int len, maxlen;
1452    POOLMEM *pool_buf;
1453    MQUEUE_ITEM *item;
1454
1455    pool_buf = get_pool_memory(PM_EMSG);
1456
1457    for (;;) {
1458       maxlen = sizeof_pool_memory(pool_buf) - 1;
1459       va_start(arg_ptr, fmt);
1460       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1461       va_end(arg_ptr);
1462       if (len < 0 || len >= (maxlen-5)) {
1463          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1464          continue;
1465       }
1466       break;
1467    }
1468    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1469    item->type = type;
1470    item->mtime = time(NULL);
1471    strcpy(item->msg, pool_buf);
1472    if (!jcr) {
1473       jcr = get_jcr_from_tsd();
1474    }
1475    /* If no jcr or no queue or dequeuing send to syslog */
1476    if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1477       syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1478       free(item);
1479    } else {
1480       /* Queue message for later sending */
1481       P(jcr->msg_queue_mutex);
1482       jcr->msg_queue->append(item);
1483       V(jcr->msg_queue_mutex);
1484    }
1485    free_memory(pool_buf);
1486 }
1487
1488 /*
1489  * Dequeue messages
1490  */
1491 void dequeue_messages(JCR *jcr)
1492 {
1493    MQUEUE_ITEM *item;
1494    if (!jcr->msg_queue) {
1495       return;
1496    }
1497    P(jcr->msg_queue_mutex);
1498    jcr->dequeuing_msgs = true;
1499    foreach_dlist(item, jcr->msg_queue) {
1500       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1501    }
1502    /* Remove messages just sent */
1503    jcr->msg_queue->destroy();
1504    jcr->dequeuing_msgs = false;
1505    V(jcr->msg_queue_mutex);
1506 }
1507
1508
1509 /*
1510  * If we come here, prefix the message with the file:line-number,
1511  *  then pass it on to the normal Qmsg routine.
1512  */
1513 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1514 {
1515    va_list   arg_ptr;
1516    int i, len, maxlen;
1517    POOLMEM *pool_buf;
1518
1519    pool_buf = get_pool_memory(PM_EMSG);
1520    i = Mmsg(pool_buf, "%s:%d ", file, line);
1521
1522    for (;;) {
1523       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1524       va_start(arg_ptr, fmt);
1525       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1526       va_end(arg_ptr);
1527       if (len < 0 || len >= (maxlen-5)) {
1528          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1529          continue;
1530       }
1531       break;
1532    }
1533
1534    Qmsg(jcr, type, mtime, "%s", pool_buf);
1535    free_memory(pool_buf);
1536 }