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