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