]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
Replace explicit checks for "/" with calls to IsPathSeparator, strchr with first_path...
[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                 }
769                 break;
770              case MD_STDERR:
771                 Dmsg1(850, "STDERR for following msg: %s", msg);
772                 fputs(dt, stderr);
773                 fputs(msg, stderr);
774                 break;
775              default:
776                 break;
777           }
778        }
779     }
780 }
781
782 /*********************************************************************
783  *
784  *  This subroutine returns the filename portion of a Windows 
785  *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
786  *  to the full path.
787  */
788
789 inline const char *
790 get_basename(const char *pathname)
791 {
792 #if defined(_MSC_VER)
793    const char *basename;
794    
795    if ((basename = strrchr(pathname, '\\')) == NULL) {
796       basename = pathname;
797    } else {
798       basename++;
799    }
800
801    return basename;
802 #else
803    return pathname;
804 #endif
805 }
806
807 /*********************************************************************
808  *
809  *  This subroutine prints a debug message if the level number
810  *  is less than or equal the debug_level. File and line numbers
811  *  are included for more detail if desired, but not currently
812  *  printed.
813  *
814  *  If the level is negative, the details of file and line number
815  *  are not printed.
816  */
817 void
818 d_msg(const char *file, int line, int level, const char *fmt,...)
819 {
820     char      buf[5000];
821     int       len;
822     va_list   arg_ptr;
823     bool      details = true;
824
825     if (level < 0) {
826        details = false;
827        level = -level;
828     }
829
830     if (level <= debug_level) {
831 #ifdef FULL_LOCATION
832        if (details) {
833           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
834        } else {
835           len = 0;
836        }
837 #else
838        len = 0;
839 #endif
840        va_start(arg_ptr, fmt);
841        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
842        va_end(arg_ptr);
843
844        /*
845         * Used the "trace on" command in the console to turn on
846         *  output to the trace file.  "trace off" will close the file.
847         */
848        if (trace) {
849           if (!trace_fd) {
850              char fn[200];
851              bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
852              trace_fd = fopen(fn, "a+b");
853           }
854           if (trace_fd) {
855              fputs(buf, trace_fd);
856              fflush(trace_fd);
857           } else {
858              /* Some problem, turn off tracing */
859              trace = false;
860           }
861        } else {   /* not tracing */
862           fputs(buf, stdout);
863        }
864     }
865 }
866
867 /*
868  * Set trace flag on/off. If argument is negative, there is no change
869  */
870 void set_trace(int trace_flag)
871 {
872    if (trace_flag < 0) {
873       return;
874    } else if (trace_flag > 0) {
875       trace = true;
876    } else {
877       trace = false;
878    }
879    if (!trace && trace_fd) {
880       FILE *ltrace_fd = trace_fd;
881       trace_fd = NULL;
882       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
883       fclose(ltrace_fd);
884    }
885 }
886
887 bool get_trace(void)
888 {
889    return trace;
890 }
891
892 /*********************************************************************
893  *
894  *  This subroutine prints a message regardless of the debug level
895  *
896  *  If the level is negative, the details of file and line number
897  *  are not printed.
898  */
899 void
900 p_msg(const char *file, int line, int level, const char *fmt,...)
901 {
902     char      buf[5000];
903     int       len;
904     va_list   arg_ptr;
905
906 #ifdef FULL_LOCATION
907     if (level >= 0) {
908        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
909     } else {
910        len = 0;
911     }
912 #else
913     len = 0;
914 #endif
915     va_start(arg_ptr, fmt);
916     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
917     va_end(arg_ptr);
918     fputs(buf, stdout);
919 }
920
921
922 /*********************************************************************
923  *
924  *  subroutine writes a debug message to the trace file if the level number
925  *  is less than or equal the debug_level. File and line numbers
926  *  are included for more detail if desired, but not currently
927  *  printed.
928  *
929  *  If the level is negative, the details of file and line number
930  *  are not printed.
931  */
932 void
933 t_msg(const char *file, int line, int level, const char *fmt,...)
934 {
935     char      buf[5000];
936     int       len;
937     va_list   arg_ptr;
938     int       details = TRUE;
939
940     if (level < 0) {
941        details = FALSE;
942        level = -level;
943     }
944
945     if (level <= debug_level) {
946        if (!trace_fd) {
947           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
948           trace_fd = fopen(buf, "a+b");
949        }
950
951 #ifdef FULL_LOCATION
952        if (details) {
953           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
954        } else {
955           len = 0;
956        }
957 #else
958        len = 0;
959 #endif
960        va_start(arg_ptr, fmt);
961        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
962        va_end(arg_ptr);
963        if (trace_fd != NULL) {
964            fputs(buf, trace_fd);
965            fflush(trace_fd);
966        }
967    }
968 }
969
970
971
972 /* *********************************************************
973  *
974  * print an error message
975  *
976  */
977 void
978 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
979 {
980     char     buf[5000];
981     va_list   arg_ptr;
982     int len;
983
984     /*
985      * Check if we have a message destination defined.
986      * We always report M_ABORT and M_ERROR_TERM
987      */
988     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
989                          !bit_is_set(type, daemon_msgs->send_msg))) {
990        return;                        /* no destination */
991     }
992     switch (type) {
993     case M_ABORT:
994        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
995                my_name, get_basename(file), line);
996        break;
997     case M_ERROR_TERM:
998        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
999                my_name, get_basename(file), line);
1000        break;
1001     case M_FATAL:
1002        if (level == -1)            /* skip details */
1003           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1004        else
1005           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1006        break;
1007     case M_ERROR:
1008        if (level == -1)            /* skip details */
1009           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1010        else
1011           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1012        break;
1013     case M_WARNING:
1014        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1015        break;
1016     case M_SECURITY:
1017        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1018        break;
1019     default:
1020        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1021        break;
1022     }
1023
1024     va_start(arg_ptr, fmt);
1025     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1026     va_end(arg_ptr);
1027
1028     dispatch_message(NULL, type, 0, buf);
1029
1030     if (type == M_ABORT) {
1031        char *p = 0;
1032        p[0] = 0;                      /* generate segmentation violation */
1033     }
1034     if (type == M_ERROR_TERM) {
1035        exit(1);
1036     }
1037 }
1038
1039 /* *********************************************************
1040  *
1041  * Generate a Job message
1042  *
1043  */
1044 void
1045 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1046 {
1047     char     rbuf[5000];
1048     va_list   arg_ptr;
1049     int len;
1050     MSGS *msgs;
1051     const char *job;
1052
1053
1054     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1055
1056     /* Special case for the console, which has a dir_bsock and JobId==0,
1057      *  in that case, we send the message directly back to the
1058      *  dir_bsock.
1059      */
1060     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1061        BSOCK *dir = jcr->dir_bsock;
1062        va_start(arg_ptr, fmt);
1063        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1064                                 fmt, arg_ptr);
1065        va_end(arg_ptr);
1066        bnet_send(jcr->dir_bsock);
1067        return;
1068     }
1069
1070     msgs = NULL;
1071     job = NULL;
1072     if (jcr) {
1073        msgs = jcr->jcr_msgs;
1074        job = jcr->Job;
1075     }
1076     if (!msgs) {
1077        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1078     }
1079     if (!job) {
1080        job = "";                      /* Set null job name if none */
1081     }
1082
1083     /*
1084      * Check if we have a message destination defined.
1085      * We always report M_ABORT and M_ERROR_TERM
1086      */
1087     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1088          !bit_is_set(type, msgs->send_msg)) {
1089        return;                        /* no destination */
1090     }
1091     switch (type) {
1092     case M_ABORT:
1093        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1094        break;
1095     case M_ERROR_TERM:
1096        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1097        break;
1098     case M_FATAL:
1099        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1100        if (jcr) {
1101           set_jcr_job_status(jcr, JS_FatalError);
1102        }
1103        break;
1104     case M_ERROR:
1105        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1106        if (jcr) {
1107           jcr->Errors++;
1108        }
1109        break;
1110     case M_WARNING:
1111        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1112        break;
1113     case M_SECURITY:
1114        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1115        break;
1116     default:
1117        len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1118        break;
1119     }
1120
1121     va_start(arg_ptr, fmt);
1122     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1123     va_end(arg_ptr);
1124
1125     dispatch_message(jcr, type, mtime, rbuf);
1126
1127     if (type == M_ABORT){
1128        char *p = 0;
1129        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1130        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1131        p[0] = 0;                      /* generate segmentation violation */
1132     }
1133     if (type == M_ERROR_TERM) {
1134        exit(1);
1135     }
1136 }
1137
1138 /*
1139  * If we come here, prefix the message with the file:line-number,
1140  *  then pass it on to the normal Jmsg routine.
1141  */
1142 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1143 {
1144    va_list   arg_ptr;
1145    int i, len, maxlen;
1146    POOLMEM *pool_buf;
1147
1148    pool_buf = get_pool_memory(PM_EMSG);
1149    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1150
1151    for (;;) {
1152       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1153       va_start(arg_ptr, fmt);
1154       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1155       va_end(arg_ptr);
1156       if (len < 0 || len >= (maxlen-5)) {
1157          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1158          continue;
1159       }
1160       break;
1161    }
1162
1163    Jmsg(jcr, type, mtime, "%s", pool_buf);
1164    free_memory(pool_buf);
1165 }
1166
1167
1168 /*
1169  * Edit a message into a Pool memory buffer, with file:lineno
1170  */
1171 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1172 {
1173    va_list   arg_ptr;
1174    int i, len, maxlen;
1175
1176    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1177
1178    for (;;) {
1179       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1180       va_start(arg_ptr, fmt);
1181       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1182       va_end(arg_ptr);
1183       if (len < 0 || len >= (maxlen-5)) {
1184          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1185          continue;
1186       }
1187       break;
1188    }
1189    return len;
1190 }
1191
1192 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1193 {
1194    va_list   arg_ptr;
1195    int i, len, maxlen;
1196
1197    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1198
1199    for (;;) {
1200       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1201       va_start(arg_ptr, fmt);
1202       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1203       va_end(arg_ptr);
1204       if (len < 0 || len >= (maxlen-5)) {
1205          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1206          continue;
1207       }
1208       break;
1209    }
1210    return len;
1211 }
1212
1213
1214 /*
1215  * Edit a message into a Pool Memory buffer NO file:lineno
1216  *  Returns: string length of what was edited.
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(POOLMEM *&pool_buf, const char *fmt, ...)
1238 {
1239    va_list   arg_ptr;
1240    int len, maxlen;
1241
1242    for (;;) {
1243       maxlen = sizeof_pool_memory(pool_buf) - 1;
1244       va_start(arg_ptr, fmt);
1245       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1246       va_end(arg_ptr);
1247       if (len < 0 || len >= (maxlen-5)) {
1248          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1249          continue;
1250       }
1251       break;
1252    }
1253    return len;
1254 }
1255
1256 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1257 {
1258    va_list   arg_ptr;
1259    int len, maxlen;
1260
1261    for (;;) {
1262       maxlen = pool_buf.max_size() - 1;
1263       va_start(arg_ptr, fmt);
1264       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1265       va_end(arg_ptr);
1266       if (len < 0 || len >= (maxlen-5)) {
1267          pool_buf.realloc_pm(maxlen + maxlen/2);
1268          continue;
1269       }
1270       break;
1271    }
1272    return len;
1273 }
1274
1275
1276 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1277
1278 /*
1279  * We queue messages rather than print them directly. This
1280  *  is generally used in low level routines (msg handler, bnet)
1281  *  to prevent recursion (i.e. if you are in the middle of
1282  *  sending a message, it is a bit messy to recursively call
1283  *  yourself when the bnet packet is not reentrant).
1284  */
1285 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1286 {
1287    va_list   arg_ptr;
1288    int len, maxlen;
1289    POOLMEM *pool_buf;
1290    MQUEUE_ITEM *item;
1291
1292    pool_buf = get_pool_memory(PM_EMSG);
1293
1294    for (;;) {
1295       maxlen = sizeof_pool_memory(pool_buf) - 1;
1296       va_start(arg_ptr, fmt);
1297       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1298       va_end(arg_ptr);
1299       if (len < 0 || len >= (maxlen-5)) {
1300          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1301          continue;
1302       }
1303       break;
1304    }
1305    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1306    item->type = type;
1307    item->mtime = time(NULL);
1308    strcpy(item->msg, pool_buf);
1309    /* If no jcr or dequeuing send to daemon to avoid recursion */
1310    if (!jcr || jcr->dequeuing) {
1311       /* jcr==NULL => daemon message, safe to send now */
1312       Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1313       free(item);
1314    } else {
1315       /* Queue message for later sending */
1316       P(msg_queue_mutex);
1317       jcr->msg_queue->append(item);
1318       V(msg_queue_mutex);
1319    }
1320    free_memory(pool_buf);
1321 }
1322
1323 /*
1324  * Dequeue messages
1325  */
1326 void dequeue_messages(JCR *jcr)
1327 {
1328    MQUEUE_ITEM *item;
1329    P(msg_queue_mutex);
1330    if (!jcr->msg_queue) {
1331       goto bail_out;
1332    }
1333    jcr->dequeuing = true;
1334    foreach_dlist(item, jcr->msg_queue) {
1335       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1336    }
1337    jcr->msg_queue->destroy();
1338    jcr->dequeuing = false;
1339
1340 bail_out:
1341    V(msg_queue_mutex);
1342 }
1343
1344
1345 /*
1346  * If we come here, prefix the message with the file:line-number,
1347  *  then pass it on to the normal Qmsg routine.
1348  */
1349 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1350 {
1351    va_list   arg_ptr;
1352    int i, len, maxlen;
1353    POOLMEM *pool_buf;
1354
1355    pool_buf = get_pool_memory(PM_EMSG);
1356    i = Mmsg(pool_buf, "%s:%d ", file, line);
1357
1358    for (;;) {
1359       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1360       va_start(arg_ptr, fmt);
1361       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1362       va_end(arg_ptr);
1363       if (len < 0 || len >= (maxlen-5)) {
1364          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1365          continue;
1366       }
1367       break;
1368    }
1369
1370    Qmsg(jcr, type, mtime, "%s", pool_buf);
1371    free_memory(pool_buf);
1372 }