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