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