]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
Fix typo in message.c
[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 const char *dist_name = DISTNAME " " DISTVER;
60 const int beef = BEEF;
61 char my_name[30];                     /* daemon name is stored here */
62 char host_name[50];                   /* 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        } else {
958           /* Some problem, turn off tracing */
959           trace = false;
960        }
961     } else {   /* not tracing */
962        fputs(buf, stdout);
963        fflush(stdout);
964     }
965 }
966
967 /*********************************************************************
968  *
969  *  This subroutine prints a debug message if the level number
970  *  is less than or equal the debug_level. File and line numbers
971  *  are included for more detail if desired, but not currently
972  *  printed.
973  *
974  *  If the level is negative, the details of file and line number
975  *  are not printed.
976  */
977 void
978 d_msg(const char *file, int line, int level, const char *fmt,...)
979 {
980     char      buf[5000];
981     int       len;
982     va_list   arg_ptr;
983     bool      details = true;
984     utime_t   mtime;
985
986     if (level < 0) {
987        details = false;
988        level = -level;
989     }
990
991     if (level <= debug_level) {
992        if (dbg_timestamp) {
993           mtime = time(NULL);
994           bstrftimes(buf, sizeof(buf), mtime);
995           len = strlen(buf);
996           buf[len++] = ' ';
997           buf[len] = 0;
998           fputs(buf, stdout);
999        }
1000     
1001 #ifdef FULL_LOCATION
1002        if (details) {
1003           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ", 
1004                 my_name, get_basename(file), line, get_jobid_from_tsd());
1005        } else {
1006           len = 0;
1007        }
1008 #else
1009        len = 0;
1010 #endif
1011        va_start(arg_ptr, fmt);
1012        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1013        va_end(arg_ptr);
1014
1015        pt_out(buf);
1016     }
1017 }
1018
1019 /*
1020  * Set trace flag on/off. If argument is negative, there is no change
1021  */
1022 void set_trace(int trace_flag)
1023 {
1024    if (trace_flag < 0) {
1025       return;
1026    } else if (trace_flag > 0) {
1027       trace = true;
1028    } else {
1029       trace = false;
1030    }
1031    if (!trace && trace_fd) {
1032       FILE *ltrace_fd = trace_fd;
1033       trace_fd = NULL;
1034       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
1035       fclose(ltrace_fd);
1036    }
1037 }
1038
1039 bool get_trace(void)
1040 {
1041    return trace;
1042 }
1043
1044 /*********************************************************************
1045  *
1046  *  This subroutine prints a message regardless of the debug level
1047  *
1048  *  If the level is negative, the details of file and line number
1049  *  are not printed.
1050  */
1051 void
1052 p_msg(const char *file, int line, int level, const char *fmt,...)
1053 {
1054     char      buf[5000];
1055     int       len;
1056     va_list   arg_ptr;
1057
1058 #ifdef FULL_LOCATION
1059     if (level >= 0) {
1060        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1061     } else {
1062        len = 0;
1063     }
1064 #else
1065     len = 0;
1066 #endif
1067     va_start(arg_ptr, fmt);
1068     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1069     va_end(arg_ptr);
1070
1071     pt_out(buf);     
1072 }
1073
1074
1075 /*********************************************************************
1076  *
1077  *  subroutine writes a debug message to the trace file if the level number
1078  *  is less than or equal the debug_level. File and line numbers
1079  *  are included for more detail if desired, but not currently
1080  *  printed.
1081  *
1082  *  If the level is negative, the details of file and line number
1083  *  are not printed.
1084  */
1085 void
1086 t_msg(const char *file, int line, int level, const char *fmt,...)
1087 {
1088     char      buf[5000];
1089     int       len;
1090     va_list   arg_ptr;
1091     int       details = TRUE;
1092
1093     if (level < 0) {
1094        details = FALSE;
1095        level = -level;
1096     }
1097
1098     if (level <= debug_level) {
1099        if (!trace_fd) {
1100           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1101           trace_fd = fopen(buf, "a+b");
1102        }
1103
1104 #ifdef FULL_LOCATION
1105        if (details) {
1106           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1107        } else {
1108           len = 0;
1109        }
1110 #else
1111        len = 0;
1112 #endif
1113        va_start(arg_ptr, fmt);
1114        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1115        va_end(arg_ptr);
1116        if (trace_fd != NULL) {
1117            fputs(buf, trace_fd);
1118            fflush(trace_fd);
1119        }
1120    }
1121 }
1122
1123 /* *********************************************************
1124  *
1125  * print an error message
1126  *
1127  */
1128 void
1129 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1130 {
1131     char     buf[5000];
1132     va_list   arg_ptr;
1133     int len;
1134
1135     /*
1136      * Check if we have a message destination defined.
1137      * We always report M_ABORT and M_ERROR_TERM
1138      */
1139     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1140                          !bit_is_set(type, daemon_msgs->send_msg))) {
1141        return;                        /* no destination */
1142     }
1143     switch (type) {
1144     case M_ABORT:
1145        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1146                my_name, get_basename(file), line);
1147        break;
1148     case M_ERROR_TERM:
1149        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1150                my_name, get_basename(file), line);
1151        break;
1152     case M_FATAL:
1153        if (level == -1)            /* skip details */
1154           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1155        else
1156           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1157        break;
1158     case M_ERROR:
1159        if (level == -1)            /* skip details */
1160           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1161        else
1162           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1163        break;
1164     case M_WARNING:
1165        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1166        break;
1167     case M_SECURITY:
1168        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1169        break;
1170     default:
1171        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1172        break;
1173     }
1174
1175     va_start(arg_ptr, fmt);
1176     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1177     va_end(arg_ptr);
1178
1179     dispatch_message(NULL, type, 0, buf);
1180
1181     if (type == M_ABORT) {
1182        char *p = 0;
1183        p[0] = 0;                      /* generate segmentation violation */
1184     }
1185     if (type == M_ERROR_TERM) {
1186        exit(1);
1187     }
1188 }
1189
1190 /* *********************************************************
1191  *
1192  * Generate a Job message
1193  *
1194  */
1195 void
1196 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1197 {
1198     char     rbuf[5000];
1199     va_list   arg_ptr;
1200     int len;
1201     MSGS *msgs;
1202     uint32_t JobId = 0;
1203
1204
1205     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1206
1207     /* Special case for the console, which has a dir_bsock and JobId==0,
1208      *  in that case, we send the message directly back to the
1209      *  dir_bsock.
1210      */
1211     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1212        BSOCK *dir = jcr->dir_bsock;
1213        va_start(arg_ptr, fmt);
1214        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1215                                 fmt, arg_ptr);
1216        va_end(arg_ptr);
1217        jcr->dir_bsock->send();
1218        return;
1219     }
1220
1221     /* The watchdog thread can't use Jmsg directly, we always queued it */
1222     if (is_watchdog()) {
1223        va_start(arg_ptr, fmt);
1224        bvsnprintf(rbuf,  sizeof(rbuf), fmt, arg_ptr);
1225        va_end(arg_ptr);
1226        Qmsg(jcr, type, mtime, "%s", rbuf);
1227        return;
1228     }
1229
1230     msgs = NULL;
1231     if (!jcr) {
1232        jcr = get_jcr_from_tsd();
1233     }
1234     if (jcr) {
1235        if (!jcr->dequeuing_msgs) { /* Avoid recursion */
1236           /* Dequeue messages to keep the original order  */
1237           dequeue_messages(jcr); 
1238        }
1239        msgs = jcr->jcr_msgs;
1240        JobId = jcr->JobId;
1241     }
1242     if (!msgs) {
1243        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1244     }
1245
1246     /*
1247      * Check if we have a message destination defined.
1248      * We always report M_ABORT and M_ERROR_TERM
1249      */
1250     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1251          !bit_is_set(type, msgs->send_msg)) {
1252        return;                        /* no destination */
1253     }
1254     switch (type) {
1255     case M_ABORT:
1256        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1257        break;
1258     case M_ERROR_TERM:
1259        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1260        break;
1261     case M_FATAL:
1262        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1263        if (jcr) {
1264           set_jcr_job_status(jcr, JS_FatalError);
1265        }
1266        break;
1267     case M_ERROR:
1268        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1269        if (jcr) {
1270           jcr->JobErrors++;
1271        }
1272        break;
1273     case M_WARNING:
1274        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1275        if (jcr) {
1276           jcr->JobWarnings++;
1277        }
1278        break;
1279     case M_SECURITY:
1280        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "), 
1281                my_name, JobId);
1282        break;
1283     default:
1284        len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1285        break;
1286     }
1287
1288     va_start(arg_ptr, fmt);
1289     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1290     va_end(arg_ptr);
1291
1292     dispatch_message(jcr, type, mtime, rbuf);
1293
1294     if (type == M_ABORT){
1295        char *p = 0;
1296        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1297        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1298        p[0] = 0;                      /* generate segmentation violation */
1299     }
1300     if (type == M_ERROR_TERM) {
1301        exit(1);
1302     }
1303 }
1304
1305 /*
1306  * If we come here, prefix the message with the file:line-number,
1307  *  then pass it on to the normal Jmsg routine.
1308  */
1309 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1310 {
1311    va_list   arg_ptr;
1312    int i, len, maxlen;
1313    POOLMEM *pool_buf;
1314
1315    pool_buf = get_pool_memory(PM_EMSG);
1316    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1317
1318    for (;;) {
1319       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1320       va_start(arg_ptr, fmt);
1321       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1322       va_end(arg_ptr);
1323       if (len < 0 || len >= (maxlen-5)) {
1324          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1325          continue;
1326       }
1327       break;
1328    }
1329
1330    Jmsg(jcr, type, mtime, "%s", pool_buf);
1331    free_memory(pool_buf);
1332 }
1333
1334
1335 /*
1336  * Edit a message into a Pool memory buffer, with file:lineno
1337  */
1338 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1339 {
1340    va_list   arg_ptr;
1341    int i, len, maxlen;
1342
1343    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1344
1345    for (;;) {
1346       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1347       va_start(arg_ptr, fmt);
1348       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1349       va_end(arg_ptr);
1350       if (len < 0 || len >= (maxlen-5)) {
1351          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1352          continue;
1353       }
1354       break;
1355    }
1356    return len;
1357 }
1358
1359 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1360 {
1361    va_list   arg_ptr;
1362    int i, len, maxlen;
1363
1364    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1365
1366    for (;;) {
1367       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1368       va_start(arg_ptr, fmt);
1369       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1370       va_end(arg_ptr);
1371       if (len < 0 || len >= (maxlen-5)) {
1372          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1373          continue;
1374       }
1375       break;
1376    }
1377    return len;
1378 }
1379
1380
1381 /*
1382  * Edit a message into a Pool Memory buffer NO file:lineno
1383  *  Returns: string length of what was edited.
1384  */
1385 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1386 {
1387    va_list   arg_ptr;
1388    int len, maxlen;
1389
1390    for (;;) {
1391       maxlen = sizeof_pool_memory(*pool_buf) - 1;
1392       va_start(arg_ptr, fmt);
1393       len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1394       va_end(arg_ptr);
1395       if (len < 0 || len >= (maxlen-5)) {
1396          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1397          continue;
1398       }
1399       break;
1400    }
1401    return len;
1402 }
1403
1404 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1405 {
1406    va_list   arg_ptr;
1407    int len, maxlen;
1408
1409    for (;;) {
1410       maxlen = sizeof_pool_memory(pool_buf) - 1;
1411       va_start(arg_ptr, fmt);
1412       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1413       va_end(arg_ptr);
1414       if (len < 0 || len >= (maxlen-5)) {
1415          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1416          continue;
1417       }
1418       break;
1419    }
1420    return len;
1421 }
1422
1423 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1424 {
1425    va_list   arg_ptr;
1426    int len, maxlen;
1427
1428    for (;;) {
1429       maxlen = pool_buf.max_size() - 1;
1430       va_start(arg_ptr, fmt);
1431       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1432       va_end(arg_ptr);
1433       if (len < 0 || len >= (maxlen-5)) {
1434          pool_buf.realloc_pm(maxlen + maxlen/2);
1435          continue;
1436       }
1437       break;
1438    }
1439    return len;
1440 }
1441
1442
1443 /*
1444  * We queue messages rather than print them directly. This
1445  *  is generally used in low level routines (msg handler, bnet)
1446  *  to prevent recursion (i.e. if you are in the middle of
1447  *  sending a message, it is a bit messy to recursively call
1448  *  yourself when the bnet packet is not reentrant).
1449  */
1450 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1451 {
1452    va_list   arg_ptr;
1453    int len, maxlen;
1454    POOLMEM *pool_buf;
1455    MQUEUE_ITEM *item;
1456
1457    pool_buf = get_pool_memory(PM_EMSG);
1458
1459    for (;;) {
1460       maxlen = sizeof_pool_memory(pool_buf) - 1;
1461       va_start(arg_ptr, fmt);
1462       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1463       va_end(arg_ptr);
1464       if (len < 0 || len >= (maxlen-5)) {
1465          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1466          continue;
1467       }
1468       break;
1469    }
1470    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1471    item->type = type;
1472    item->mtime = time(NULL);
1473    strcpy(item->msg, pool_buf);
1474    if (!jcr) {
1475       jcr = get_jcr_from_tsd();
1476    }
1477    /* If no jcr or no queue or dequeuing send to syslog */
1478    if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1479       syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1480       free(item);
1481    } else {
1482       /* Queue message for later sending */
1483       P(jcr->msg_queue_mutex);
1484       jcr->msg_queue->append(item);
1485       V(jcr->msg_queue_mutex);
1486    }
1487    free_memory(pool_buf);
1488 }
1489
1490 /*
1491  * Dequeue messages
1492  */
1493 void dequeue_messages(JCR *jcr)
1494 {
1495    MQUEUE_ITEM *item;
1496    if (!jcr->msg_queue) {
1497       return;
1498    }
1499    P(jcr->msg_queue_mutex);
1500    jcr->dequeuing_msgs = true;
1501    foreach_dlist(item, jcr->msg_queue) {
1502       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1503    }
1504    /* Remove messages just sent */
1505    jcr->msg_queue->destroy();
1506    jcr->dequeuing_msgs = false;
1507    V(jcr->msg_queue_mutex);
1508 }
1509
1510
1511 /*
1512  * If we come here, prefix the message with the file:line-number,
1513  *  then pass it on to the normal Qmsg routine.
1514  */
1515 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1516 {
1517    va_list   arg_ptr;
1518    int i, len, maxlen;
1519    POOLMEM *pool_buf;
1520
1521    pool_buf = get_pool_memory(PM_EMSG);
1522    i = Mmsg(pool_buf, "%s:%d ", file, line);
1523
1524    for (;;) {
1525       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1526       va_start(arg_ptr, fmt);
1527       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1528       va_end(arg_ptr);
1529       if (len < 0 || len >= (maxlen-5)) {
1530          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1531          continue;
1532       }
1533       break;
1534    }
1535
1536    Qmsg(jcr, type, mtime, "%s", pool_buf);
1537    free_memory(pool_buf);
1538 }