]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
kes Make database name and user configurable
[bacula/bacula] / bacula / src / lib / message.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Bacula message handling routines
30  *
31  *   Kern Sibbald, April 2000
32  *
33  *   Version $Id$
34  *
35  */
36
37
38 #include "bacula.h"
39 #include "jcr.h"
40
41 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       free(catalog_db);
160    }
161    catalog_db = bstrdup(name);
162 }
163
164 /*
165  * Initialize message handler for a daemon or a Job
166  *   We make a copy of the MSGS resource passed, so it belows
167  *   to the job or daemon and thus can be modified.
168  *
169  *   NULL for jcr -> initialize global messages for daemon
170  *   non-NULL     -> initialize jcr using Message resource
171  */
172 void
173 init_msg(JCR *jcr, MSGS *msg)
174 {
175    DEST *d, *dnew, *temp_chain = NULL;
176    int i;
177
178    if (jcr == NULL && msg == NULL) {
179       init_last_jobs_list();
180    }
181
182 #if !defined(HAVE_WIN32)
183    /*
184     * Make sure we have fd's 0, 1, 2 open
185     *  If we don't do this one of our sockets may open
186     *  there and if we then use stdout, it could
187     *  send total garbage to our socket.
188     *
189     */
190    int fd;
191    fd = open("/dev/null", O_RDONLY, 0644);
192    if (fd > 2) {
193       close(fd);
194    } else {
195       for(i=1; fd + i <= 2; i++) {
196          dup2(fd, fd+i);
197       }
198    }
199
200 #endif
201    /*
202     * If msg is NULL, initialize global chain for STDOUT and syslog
203     */
204    if (msg == NULL) {
205       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
206       memset(daemon_msgs, 0, sizeof(MSGS));
207       for (i=1; i<=M_MAX; i++) {
208          add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
209       }
210       Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
211       return;
212    }
213
214    /*
215     * Walk down the message resource chain duplicating it
216     * for the current Job.
217     */
218    for (d=msg->dest_chain; d; d=d->next) {
219       dnew = (DEST *)malloc(sizeof(DEST));
220       memcpy(dnew, d, sizeof(DEST));
221       dnew->next = temp_chain;
222       dnew->fd = NULL;
223       dnew->mail_filename = NULL;
224       if (d->mail_cmd) {
225          dnew->mail_cmd = bstrdup(d->mail_cmd);
226       }
227       if (d->where) {
228          dnew->where = bstrdup(d->where);
229       }
230       temp_chain = dnew;
231    }
232
233    if (jcr) {
234       jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
235       memset(jcr->jcr_msgs, 0, sizeof(MSGS));
236       jcr->jcr_msgs->dest_chain = temp_chain;
237       memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
238    } else {
239       /* If we have default values, release them now */
240       if (daemon_msgs) {
241          free_msgs_res(daemon_msgs);
242       }
243       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
244       memset(daemon_msgs, 0, sizeof(MSGS));
245       daemon_msgs->dest_chain = temp_chain;
246       memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
247    }
248    Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
249
250 }
251
252 /* Initialize so that the console (User Agent) can
253  * receive messages -- stored in a file.
254  */
255 void init_console_msg(const char *wd)
256 {
257    int fd;
258
259    bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
260    fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
261    if (fd == -1) {
262       berrno be;
263       Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
264           con_fname, be.strerror());
265    }
266    if (lseek(fd, 0, SEEK_END) > 0) {
267       console_msg_pending = 1;
268    }
269    close(fd);
270    con_fd = fopen(con_fname, "a+b");
271    if (!con_fd) {
272       berrno be;
273       Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
274           con_fname, be.strerror());
275    }
276    if (rwl_init(&con_lock) != 0) {
277       berrno be;
278       Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
279          be.strerror());
280    }
281 }
282
283 /*
284  * Called only during parsing of the config file.
285  *
286  * Add a message destination. I.e. associate a message type with
287  *  a destination (code).
288  * Note, where in the case of dest_code FILE is a filename,
289  *  but in the case of MAIL is a space separated list of
290  *  email addresses, ...
291  */
292 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
293 {
294    DEST *d;
295    /*
296     * First search the existing chain and see if we
297     * can simply add this msg_type to an existing entry.
298     */
299    for (d=msg->dest_chain; d; d=d->next) {
300       if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
301                      (strcmp(where, d->where) == 0))) {
302          Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
303              d, msg_type, dest_code, NPRT(where));
304          set_bit(msg_type, d->msg_types);
305          set_bit(msg_type, msg->send_msg);  /* set msg_type bit in our local */
306          return;
307       }
308    }
309    /* Not found, create a new entry */
310    d = (DEST *)malloc(sizeof(DEST));
311    memset(d, 0, sizeof(DEST));
312    d->next = msg->dest_chain;
313    d->dest_code = dest_code;
314    set_bit(msg_type, d->msg_types);      /* set type bit in structure */
315    set_bit(msg_type, msg->send_msg);     /* set type bit in our local */
316    if (where) {
317       d->where = bstrdup(where);
318    }
319    if (mail_cmd) {
320       d->mail_cmd = bstrdup(mail_cmd);
321    }
322    Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
323           d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
324    msg->dest_chain = d;
325 }
326
327 /*
328  * Called only during parsing of the config file.
329  *
330  * Remove a message destination
331  */
332 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
333 {
334    DEST *d;
335
336    for (d=msg->dest_chain; d; d=d->next) {
337       Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
338       if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
339           ((where == NULL && d->where == NULL) ||
340                      (strcmp(where, d->where) == 0))) {
341          Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
342                d, msg_type, dest_code);
343          clear_bit(msg_type, d->msg_types);
344          Dmsg0(850, "Return rem_msg_dest\n");
345          return;
346       }
347    }
348 }
349
350
351 /*
352  * Create a unique filename for the mail command
353  */
354 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
355 {
356    if (jcr) {
357       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
358                  jcr->Job, (int)(long)d);
359    } else {
360       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
361                  my_name, (int)(long)d);
362    }
363    Dmsg1(850, "mailname=%s\n", name);
364 }
365
366 /*
367  * Open a mail pipe
368  */
369 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
370 {
371    BPIPE *bpipe;
372
373    if (d->mail_cmd) {
374       cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
375    } else {
376       Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
377    }
378    fflush(stdout);
379
380    if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
381       berrno be;
382       Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
383          cmd, be.strerror());
384    }
385
386    /* If we had to use sendmail, add subject */
387    if (!d->mail_cmd) {
388        fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
389    }
390
391    return bpipe;
392 }
393
394 /*
395  * Close the messages for this Messages resource, which means to close
396  *  any open files, and dispatch any pending email messages.
397  */
398 void close_msg(JCR *jcr)
399 {
400    MSGS *msgs;
401    DEST *d;
402    BPIPE *bpipe;
403    POOLMEM *cmd, *line;
404    int len, stat;
405
406    Dmsg1(580, "Close_msg jcr=%p\n", jcr);
407
408    if (jcr == NULL) {                /* NULL -> global chain */
409       msgs = daemon_msgs;
410       P(mutex);                       /* only one thread walking the chain */
411    } else {
412       msgs = jcr->jcr_msgs;
413       jcr->jcr_msgs = NULL;
414    }
415    if (msgs == NULL) {
416       return;
417    }
418    Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
419    cmd = get_pool_memory(PM_MESSAGE);
420    for (d=msgs->dest_chain; d; ) {
421       if (d->fd) {
422          switch (d->dest_code) {
423          case MD_FILE:
424          case MD_APPEND:
425             if (d->fd) {
426                fclose(d->fd);            /* close open file descriptor */
427                d->fd = NULL;
428             }
429             break;
430          case MD_MAIL:
431          case MD_MAIL_ON_ERROR:
432          case MD_MAIL_ON_SUCCESS:
433             Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
434             if (!d->fd) {
435                break;
436             }
437             if (
438                 (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
439                  jcr->JobStatus == JS_Terminated) 
440                 ||
441                 (d->dest_code == MD_MAIL_ON_SUCCESS && jcr &&
442                  jcr->JobStatus == JS_ErrorTerminated)
443                 ){
444                goto rem_temp_file;
445             }
446
447             if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
448                Pmsg0(000, _("open mail pipe failed.\n"));
449                goto rem_temp_file;
450             }
451             Dmsg0(850, "Opened mail pipe\n");
452             len = d->max_len+10;
453             line = get_memory(len);
454             rewind(d->fd);
455             while (fgets(line, len, d->fd)) {
456                fputs(line, bpipe->wfd);
457             }
458             if (!close_wpipe(bpipe)) {       /* close write pipe sending mail */
459                berrno be;
460                Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
461             }
462
463             /*
464              * Since we are closing all messages, before "recursing"
465              * make sure we are not closing the daemon messages, otherwise
466              * kaboom.
467              */
468             if (msgs != daemon_msgs) {
469                /* read what mail prog returned -- should be nothing */
470                while (fgets(line, len, bpipe->rfd)) {
471                   Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
472                }
473             }
474
475             stat = close_bpipe(bpipe);
476             if (stat != 0 && msgs != daemon_msgs) {
477                berrno be;
478                be.set_errno(stat);
479                Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
480                Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
481                                         "CMD=%s\n"
482                                         "ERR=%s\n"), cmd, be.strerror());
483             }
484             free_memory(line);
485 rem_temp_file:
486             /* Remove temp file */
487             fclose(d->fd);
488             d->fd = NULL;
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                    bstrutime(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                    d->fd = NULL;
751                    if (open_dest_file(jcr, d, mode)) {
752                       fputs(dt, d->fd);
753                       fputs(msg, d->fd);
754                    }
755                 }
756                 break;
757              case MD_DIRECTOR:
758                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
759                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
760                    bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
761                       jcr->Job, type, mtime, msg);
762                 }
763                 break;
764              case MD_STDOUT:
765                 Dmsg1(850, "STDOUT for following msg: %s", msg);
766                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
767                    fputs(dt, stdout);
768                    fputs(msg, stdout);
769                    fflush(stdout);
770                 }
771                 break;
772              case MD_STDERR:
773                 Dmsg1(850, "STDERR for following msg: %s", msg);
774                 fputs(dt, stderr);
775                 fputs(msg, stderr);
776                 fflush(stdout);
777                 break;
778              default:
779                 break;
780           }
781        }
782     }
783 }
784
785 /*********************************************************************
786  *
787  *  This subroutine returns the filename portion of a Windows 
788  *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
789  *  to the full path.
790  */
791
792 inline const char *
793 get_basename(const char *pathname)
794 {
795 #if defined(_MSC_VER)
796    const char *basename;
797    
798    if ((basename = strrchr(pathname, '\\')) == NULL) {
799       basename = pathname;
800    } else {
801       basename++;
802    }
803
804    return basename;
805 #else
806    return pathname;
807 #endif
808 }
809
810 /*********************************************************************
811  *
812  *  This subroutine prints a debug message if the level number
813  *  is less than or equal the debug_level. File and line numbers
814  *  are included for more detail if desired, but not currently
815  *  printed.
816  *
817  *  If the level is negative, the details of file and line number
818  *  are not printed.
819  */
820 void
821 d_msg(const char *file, int line, int level, const char *fmt,...)
822 {
823     char      buf[5000];
824     int       len;
825     va_list   arg_ptr;
826     bool      details = true;
827
828     if (level < 0) {
829        details = false;
830        level = -level;
831     }
832
833     if (level <= debug_level) {
834 #ifdef FULL_LOCATION
835        if (details) {
836           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
837        } else {
838           len = 0;
839        }
840 #else
841        len = 0;
842 #endif
843        va_start(arg_ptr, fmt);
844        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
845        va_end(arg_ptr);
846
847        /*
848         * Used the "trace on" command in the console to turn on
849         *  output to the trace file.  "trace off" will close the file.
850         */
851        if (trace) {
852           if (!trace_fd) {
853              char fn[200];
854              bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
855              trace_fd = fopen(fn, "a+b");
856           }
857           if (trace_fd) {
858              fputs(buf, trace_fd);
859              fflush(trace_fd);
860           } else {
861              /* Some problem, turn off tracing */
862              trace = false;
863           }
864        } else {   /* not tracing */
865           fputs(buf, stdout);
866           fflush(stdout);
867        }
868     }
869 }
870
871 /*
872  * Set trace flag on/off. If argument is negative, there is no change
873  */
874 void set_trace(int trace_flag)
875 {
876    if (trace_flag < 0) {
877       return;
878    } else if (trace_flag > 0) {
879       trace = true;
880    } else {
881       trace = false;
882    }
883    if (!trace && trace_fd) {
884       FILE *ltrace_fd = trace_fd;
885       trace_fd = NULL;
886       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
887       fclose(ltrace_fd);
888    }
889 }
890
891 bool get_trace(void)
892 {
893    return trace;
894 }
895
896 /*********************************************************************
897  *
898  *  This subroutine prints a message regardless of the debug level
899  *
900  *  If the level is negative, the details of file and line number
901  *  are not printed.
902  */
903 void
904 p_msg(const char *file, int line, int level, const char *fmt,...)
905 {
906     char      buf[5000];
907     int       len;
908     va_list   arg_ptr;
909
910 #ifdef FULL_LOCATION
911     if (level >= 0) {
912        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
913     } else {
914        len = 0;
915     }
916 #else
917     len = 0;
918 #endif
919     va_start(arg_ptr, fmt);
920     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
921     va_end(arg_ptr);
922     fputs(buf, stdout);
923     fflush(stdout);
924 }
925
926
927 /*********************************************************************
928  *
929  *  subroutine writes a debug message to the trace file if the level number
930  *  is less than or equal the debug_level. File and line numbers
931  *  are included for more detail if desired, but not currently
932  *  printed.
933  *
934  *  If the level is negative, the details of file and line number
935  *  are not printed.
936  */
937 void
938 t_msg(const char *file, int line, int level, const char *fmt,...)
939 {
940     char      buf[5000];
941     int       len;
942     va_list   arg_ptr;
943     int       details = TRUE;
944
945     if (level < 0) {
946        details = FALSE;
947        level = -level;
948     }
949
950     if (level <= debug_level) {
951        if (!trace_fd) {
952           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
953           trace_fd = fopen(buf, "a+b");
954        }
955
956 #ifdef FULL_LOCATION
957        if (details) {
958           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
959        } else {
960           len = 0;
961        }
962 #else
963        len = 0;
964 #endif
965        va_start(arg_ptr, fmt);
966        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
967        va_end(arg_ptr);
968        if (trace_fd != NULL) {
969            fputs(buf, trace_fd);
970            fflush(trace_fd);
971        }
972    }
973 }
974
975
976
977 /* *********************************************************
978  *
979  * print an error message
980  *
981  */
982 void
983 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
984 {
985     char     buf[5000];
986     va_list   arg_ptr;
987     int len;
988
989     /*
990      * Check if we have a message destination defined.
991      * We always report M_ABORT and M_ERROR_TERM
992      */
993     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
994                          !bit_is_set(type, daemon_msgs->send_msg))) {
995        return;                        /* no destination */
996     }
997     switch (type) {
998     case M_ABORT:
999        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1000                my_name, get_basename(file), line);
1001        break;
1002     case M_ERROR_TERM:
1003        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1004                my_name, get_basename(file), line);
1005        break;
1006     case M_FATAL:
1007        if (level == -1)            /* skip details */
1008           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1009        else
1010           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1011        break;
1012     case M_ERROR:
1013        if (level == -1)            /* skip details */
1014           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1015        else
1016           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1017        break;
1018     case M_WARNING:
1019        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1020        break;
1021     case M_SECURITY:
1022        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1023        break;
1024     default:
1025        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1026        break;
1027     }
1028
1029     va_start(arg_ptr, fmt);
1030     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1031     va_end(arg_ptr);
1032
1033     dispatch_message(NULL, type, 0, buf);
1034
1035     if (type == M_ABORT) {
1036        char *p = 0;
1037        p[0] = 0;                      /* generate segmentation violation */
1038     }
1039     if (type == M_ERROR_TERM) {
1040        exit(1);
1041     }
1042 }
1043
1044 /* *********************************************************
1045  *
1046  * Generate a Job message
1047  *
1048  */
1049 void
1050 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1051 {
1052     char     rbuf[5000];
1053     va_list   arg_ptr;
1054     int len;
1055     MSGS *msgs;
1056     const char *job;
1057
1058
1059     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1060
1061     /* Special case for the console, which has a dir_bsock and JobId==0,
1062      *  in that case, we send the message directly back to the
1063      *  dir_bsock.
1064      */
1065     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1066        BSOCK *dir = jcr->dir_bsock;
1067        va_start(arg_ptr, fmt);
1068        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1069                                 fmt, arg_ptr);
1070        va_end(arg_ptr);
1071        bnet_send(jcr->dir_bsock);
1072        return;
1073     }
1074
1075     msgs = NULL;
1076     job = NULL;
1077     if (jcr) {
1078        msgs = jcr->jcr_msgs;
1079        job = jcr->Job;
1080     }
1081     if (!msgs) {
1082        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1083     }
1084     if (!job) {
1085        job = "";                      /* Set null job name if none */
1086     }
1087
1088     /*
1089      * Check if we have a message destination defined.
1090      * We always report M_ABORT and M_ERROR_TERM
1091      */
1092     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1093          !bit_is_set(type, msgs->send_msg)) {
1094        return;                        /* no destination */
1095     }
1096     switch (type) {
1097     case M_ABORT:
1098        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1099        break;
1100     case M_ERROR_TERM:
1101        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1102        break;
1103     case M_FATAL:
1104        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1105        if (jcr) {
1106           set_jcr_job_status(jcr, JS_FatalError);
1107        }
1108        break;
1109     case M_ERROR:
1110        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1111        if (jcr) {
1112           jcr->Errors++;
1113        }
1114        break;
1115     case M_WARNING:
1116        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1117        break;
1118     case M_SECURITY:
1119        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1120        break;
1121     default:
1122        len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1123        break;
1124     }
1125
1126     va_start(arg_ptr, fmt);
1127     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1128     va_end(arg_ptr);
1129
1130     dispatch_message(jcr, type, mtime, rbuf);
1131
1132     if (type == M_ABORT){
1133        char *p = 0;
1134        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1135        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1136        p[0] = 0;                      /* generate segmentation violation */
1137     }
1138     if (type == M_ERROR_TERM) {
1139        exit(1);
1140     }
1141 }
1142
1143 /*
1144  * If we come here, prefix the message with the file:line-number,
1145  *  then pass it on to the normal Jmsg routine.
1146  */
1147 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1148 {
1149    va_list   arg_ptr;
1150    int i, len, maxlen;
1151    POOLMEM *pool_buf;
1152
1153    pool_buf = get_pool_memory(PM_EMSG);
1154    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1155
1156    for (;;) {
1157       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1158       va_start(arg_ptr, fmt);
1159       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1160       va_end(arg_ptr);
1161       if (len < 0 || len >= (maxlen-5)) {
1162          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1163          continue;
1164       }
1165       break;
1166    }
1167
1168    Jmsg(jcr, type, mtime, "%s", pool_buf);
1169    free_memory(pool_buf);
1170 }
1171
1172
1173 /*
1174  * Edit a message into a Pool memory buffer, with file:lineno
1175  */
1176 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1177 {
1178    va_list   arg_ptr;
1179    int i, len, maxlen;
1180
1181    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1182
1183    for (;;) {
1184       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1185       va_start(arg_ptr, fmt);
1186       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1187       va_end(arg_ptr);
1188       if (len < 0 || len >= (maxlen-5)) {
1189          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1190          continue;
1191       }
1192       break;
1193    }
1194    return len;
1195 }
1196
1197 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1198 {
1199    va_list   arg_ptr;
1200    int i, len, maxlen;
1201
1202    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1203
1204    for (;;) {
1205       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1206       va_start(arg_ptr, fmt);
1207       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1208       va_end(arg_ptr);
1209       if (len < 0 || len >= (maxlen-5)) {
1210          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1211          continue;
1212       }
1213       break;
1214    }
1215    return len;
1216 }
1217
1218
1219 /*
1220  * Edit a message into a Pool Memory buffer NO file:lineno
1221  *  Returns: string length of what was edited.
1222  */
1223 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1224 {
1225    va_list   arg_ptr;
1226    int len, maxlen;
1227
1228    for (;;) {
1229       maxlen = sizeof_pool_memory(*pool_buf) - 1;
1230       va_start(arg_ptr, fmt);
1231       len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1232       va_end(arg_ptr);
1233       if (len < 0 || len >= (maxlen-5)) {
1234          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1235          continue;
1236       }
1237       break;
1238    }
1239    return len;
1240 }
1241
1242 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1243 {
1244    va_list   arg_ptr;
1245    int len, maxlen;
1246
1247    for (;;) {
1248       maxlen = sizeof_pool_memory(pool_buf) - 1;
1249       va_start(arg_ptr, fmt);
1250       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1251       va_end(arg_ptr);
1252       if (len < 0 || len >= (maxlen-5)) {
1253          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1254          continue;
1255       }
1256       break;
1257    }
1258    return len;
1259 }
1260
1261 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1262 {
1263    va_list   arg_ptr;
1264    int len, maxlen;
1265
1266    for (;;) {
1267       maxlen = pool_buf.max_size() - 1;
1268       va_start(arg_ptr, fmt);
1269       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1270       va_end(arg_ptr);
1271       if (len < 0 || len >= (maxlen-5)) {
1272          pool_buf.realloc_pm(maxlen + maxlen/2);
1273          continue;
1274       }
1275       break;
1276    }
1277    return len;
1278 }
1279
1280
1281 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1282
1283 /*
1284  * We queue messages rather than print them directly. This
1285  *  is generally used in low level routines (msg handler, bnet)
1286  *  to prevent recursion (i.e. if you are in the middle of
1287  *  sending a message, it is a bit messy to recursively call
1288  *  yourself when the bnet packet is not reentrant).
1289  */
1290 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1291 {
1292    va_list   arg_ptr;
1293    int len, maxlen;
1294    POOLMEM *pool_buf;
1295    MQUEUE_ITEM *item;
1296
1297    pool_buf = get_pool_memory(PM_EMSG);
1298
1299    for (;;) {
1300       maxlen = sizeof_pool_memory(pool_buf) - 1;
1301       va_start(arg_ptr, fmt);
1302       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1303       va_end(arg_ptr);
1304       if (len < 0 || len >= (maxlen-5)) {
1305          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1306          continue;
1307       }
1308       break;
1309    }
1310    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1311    item->type = type;
1312    item->mtime = time(NULL);
1313    strcpy(item->msg, pool_buf);
1314    /* If no jcr or dequeuing send to daemon to avoid recursion */
1315    if (!jcr || jcr->dequeuing) {
1316       /* jcr==NULL => daemon message, safe to send now */
1317       Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1318       free(item);
1319    } else {
1320       /* Queue message for later sending */
1321       P(msg_queue_mutex);
1322       jcr->msg_queue->append(item);
1323       V(msg_queue_mutex);
1324    }
1325    free_memory(pool_buf);
1326 }
1327
1328 /*
1329  * Dequeue messages
1330  */
1331 void dequeue_messages(JCR *jcr)
1332 {
1333    MQUEUE_ITEM *item;
1334    P(msg_queue_mutex);
1335    if (!jcr->msg_queue) {
1336       goto bail_out;
1337    }
1338    jcr->dequeuing = true;
1339    foreach_dlist(item, jcr->msg_queue) {
1340       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1341    }
1342    jcr->msg_queue->destroy();
1343    jcr->dequeuing = false;
1344
1345 bail_out:
1346    V(msg_queue_mutex);
1347 }
1348
1349
1350 /*
1351  * If we come here, prefix the message with the file:line-number,
1352  *  then pass it on to the normal Qmsg routine.
1353  */
1354 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1355 {
1356    va_list   arg_ptr;
1357    int i, len, maxlen;
1358    POOLMEM *pool_buf;
1359
1360    pool_buf = get_pool_memory(PM_EMSG);
1361    i = Mmsg(pool_buf, "%s:%d ", file, line);
1362
1363    for (;;) {
1364       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1365       va_start(arg_ptr, fmt);
1366       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1367       va_end(arg_ptr);
1368       if (len < 0 || len >= (maxlen-5)) {
1369          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1370          continue;
1371       }
1372       break;
1373    }
1374
1375    Qmsg(jcr, type, mtime, "%s", pool_buf);
1376    free_memory(pool_buf);
1377 }