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