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