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