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