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