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