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