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