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