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