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