]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
Ignore UTF-8 marker at the start of .conf files.
[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        fputs(dt, stdout);
600        fputs(msg, stdout);         /* print this here to INSURE that it is printed */
601        fflush(stdout);
602     }
603
604     /* Now figure out where to send the message */
605     msgs = NULL;
606     if (jcr) {
607        msgs = jcr->jcr_msgs;
608     }
609     if (msgs == NULL) {
610        msgs = daemon_msgs;
611     }
612     for (d=msgs->dest_chain; d; d=d->next) {
613        if (bit_is_set(type, d->msg_types)) {
614           switch (d->dest_code) {
615              case MD_CATALOG:
616                 char ed1[50];
617                 if (!jcr || !jcr->db) {
618                    break;
619                 }
620                 if (p_sql_query) {
621                    POOL_MEM cmd(PM_MESSAGE);
622                    bstrftimes(dt, sizeof(dt), mtime);
623                    Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
624                          edit_int64(jcr->JobId, ed1), dt, msg);
625                    p_sql_query(jcr, cmd.c_str());
626                 }
627                 break;
628              case MD_CONSOLE:
629                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
630                 if (!con_fd) {
631                    con_fd = fopen(con_fname, "a+b");
632                    Dmsg0(850, "Console file not open.\n");
633                 }
634                 if (con_fd) {
635                    Pw(con_lock);      /* get write lock on console message file */
636                    errno = 0;
637                    if (dtlen) {
638                       (void)fwrite(dt, dtlen, 1, con_fd);
639                    }
640                    len = strlen(msg);
641                    if (len > 0) {
642                       (void)fwrite(msg, len, 1, con_fd);
643                       if (msg[len-1] != '\n') {
644                          (void)fwrite("\n", 2, 1, con_fd);
645                       }
646                    } else {
647                       (void)fwrite("\n", 2, 1, con_fd);
648                    }
649                    fflush(con_fd);
650                    console_msg_pending = TRUE;
651                    Vw(con_lock);
652                 }
653                 break;
654              case MD_SYSLOG:
655                 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
656                 /*
657                  * We really should do an openlog() here.
658                  */
659                 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
660                 break;
661              case MD_OPERATOR:
662                 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
663                 mcmd = get_pool_memory(PM_MESSAGE);
664                 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
665                    int stat;
666                    fputs(dt, bpipe->wfd);
667                    fputs(msg, bpipe->wfd);
668                    /* Messages to the operator go one at a time */
669                    stat = close_bpipe(bpipe);
670                    if (stat != 0) {
671                       berrno be;
672                       be.set_errno(stat);
673                       Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
674                             "CMD=%s\n"
675                             "ERR=%s\n"), mcmd, be.strerror());
676                    }
677                 }
678                 free_pool_memory(mcmd);
679                 break;
680              case MD_MAIL:
681              case MD_MAIL_ON_ERROR:
682                 Dmsg1(850, "MAIL for following msg: %s", msg);
683                 if (!d->fd) {
684                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
685                    make_unique_mail_filename(jcr, name, d);
686                    d->fd = fopen(name, "w+b");
687                    if (!d->fd) {
688                       berrno be;
689                       d->fd = stdout;
690                       Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
691                             be.strerror());
692                       d->fd = NULL;
693                       free_pool_memory(name);
694                       break;
695                    }
696                    d->mail_filename = name;
697                 }
698                 fputs(dt, d->fd);
699                 len = strlen(msg) + dtlen;;
700                 if (len > d->max_len) {
701                    d->max_len = len;      /* keep max line length */
702                 }
703                 fputs(msg, d->fd);
704                 break;
705              case MD_APPEND:
706                 Dmsg1(850, "APPEND for following msg: %s", msg);
707                 mode = "ab";
708                 goto send_to_file;
709              case MD_FILE:
710                 Dmsg1(850, "FILE for following msg: %s", msg);
711                 mode = "w+b";
712 send_to_file:
713                 if (!d->fd && !open_dest_file(jcr, d, mode)) {
714                    break;
715                 }
716                 fputs(dt, d->fd);
717                 fputs(msg, d->fd);
718                 /* On error, we close and reopen to handle log rotation */
719                 if (ferror(d->fd)) {
720                    fclose(d->fd);
721                    if (open_dest_file(jcr, d, mode)) {
722                       fputs(dt, d->fd);
723                       fputs(msg, d->fd);
724                    }
725                 }
726                 break;
727              case MD_DIRECTOR:
728                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
729                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
730                    bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
731                       jcr->Job, type, mtime, msg);
732                 }
733                 break;
734              case MD_STDOUT:
735                 Dmsg1(850, "STDOUT for following msg: %s", msg);
736                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
737                    fputs(dt, stdout);
738                    fputs(msg, stdout);
739                 }
740                 break;
741              case MD_STDERR:
742                 Dmsg1(850, "STDERR for following msg: %s", msg);
743                 fputs(dt, stderr);
744                 fputs(msg, stderr);
745                 break;
746              default:
747                 break;
748           }
749        }
750     }
751 }
752
753 /*********************************************************************
754  *
755  *  This subroutine returns the filename portion of a Windows 
756  *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
757  *  to the full path.
758  */
759
760 inline const char *
761 get_basename(const char *pathname)
762 {
763 #if defined(_MSC_VER)
764    const char *basename;
765    
766    if ((basename = strrchr(pathname, '\\')) == NULL) {
767       basename = pathname;
768    } else {
769       basename++;
770    }
771
772    return basename;
773 #else
774    return pathname;
775 #endif
776 }
777
778 /*********************************************************************
779  *
780  *  This subroutine prints a debug message if the level number
781  *  is less than or equal the debug_level. File and line numbers
782  *  are included for more detail if desired, but not currently
783  *  printed.
784  *
785  *  If the level is negative, the details of file and line number
786  *  are not printed.
787  */
788 void
789 d_msg(const char *file, int line, int level, const char *fmt,...)
790 {
791     char      buf[5000];
792     int       len;
793     va_list   arg_ptr;
794     bool      details = true;
795
796     if (level < 0) {
797        details = false;
798        level = -level;
799     }
800
801     if (level <= debug_level) {
802 #ifdef FULL_LOCATION
803        if (details) {
804           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
805        } else {
806           len = 0;
807        }
808 #else
809        len = 0;
810 #endif
811        va_start(arg_ptr, fmt);
812        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
813        va_end(arg_ptr);
814
815        /*
816         * Used the "trace on" command in the console to turn on
817         *  output to the trace file.  "trace off" will close the file.
818         */
819        if (trace) {
820           if (!trace_fd) {
821              char fn[200];
822              bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
823              trace_fd = fopen(fn, "a+b");
824           }
825           if (trace_fd) {
826              fputs(buf, trace_fd);
827              fflush(trace_fd);
828           } else {
829              /* Some problem, turn off tracing */
830              trace = false;
831           }
832        } else {   /* not tracing */
833           fputs(buf, stdout);
834        }
835     }
836 }
837
838 /*
839  * Set trace flag on/off. If argument is negative, there is no change
840  */
841 void set_trace(int trace_flag)
842 {
843    if (trace_flag < 0) {
844       return;
845    } else if (trace_flag > 0) {
846       trace = true;
847    } else {
848       trace = false;
849    }
850    if (!trace && trace_fd) {
851       FILE *ltrace_fd = trace_fd;
852       trace_fd = NULL;
853       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
854       fclose(ltrace_fd);
855    }
856 }
857
858 bool get_trace(void)
859 {
860    return trace;
861 }
862
863 /*********************************************************************
864  *
865  *  This subroutine prints a message regardless of the debug level
866  *
867  *  If the level is negative, the details of file and line number
868  *  are not printed.
869  */
870 void
871 p_msg(const char *file, int line, int level, const char *fmt,...)
872 {
873     char      buf[5000];
874     int       len;
875     va_list   arg_ptr;
876
877 #ifdef FULL_LOCATION
878     if (level >= 0) {
879        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
880     } else {
881        len = 0;
882     }
883 #else
884     len = 0;
885 #endif
886     va_start(arg_ptr, fmt);
887     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
888     va_end(arg_ptr);
889     fputs(buf, stdout);
890 }
891
892
893 /*********************************************************************
894  *
895  *  subroutine writes a debug message to the trace file if the level number
896  *  is less than or equal the debug_level. File and line numbers
897  *  are included for more detail if desired, but not currently
898  *  printed.
899  *
900  *  If the level is negative, the details of file and line number
901  *  are not printed.
902  */
903 void
904 t_msg(const char *file, int line, int level, const char *fmt,...)
905 {
906     char      buf[5000];
907     int       len;
908     va_list   arg_ptr;
909     int       details = TRUE;
910
911     if (level < 0) {
912        details = FALSE;
913        level = -level;
914     }
915
916     if (level <= debug_level) {
917        if (!trace_fd) {
918           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
919           trace_fd = fopen(buf, "a+b");
920        }
921
922 #ifdef FULL_LOCATION
923        if (details) {
924           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
925        } else {
926           len = 0;
927        }
928 #else
929        len = 0;
930 #endif
931        va_start(arg_ptr, fmt);
932        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
933        va_end(arg_ptr);
934        if (trace_fd != NULL) {
935            fputs(buf, trace_fd);
936            fflush(trace_fd);
937        }
938    }
939 }
940
941
942
943 /* *********************************************************
944  *
945  * print an error message
946  *
947  */
948 void
949 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
950 {
951     char     buf[5000];
952     va_list   arg_ptr;
953     int len;
954
955     /*
956      * Check if we have a message destination defined.
957      * We always report M_ABORT and M_ERROR_TERM
958      */
959     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
960                          !bit_is_set(type, daemon_msgs->send_msg))) {
961        return;                        /* no destination */
962     }
963     switch (type) {
964     case M_ABORT:
965        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
966                my_name, get_basename(file), line);
967        break;
968     case M_ERROR_TERM:
969        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
970                my_name, get_basename(file), line);
971        break;
972     case M_FATAL:
973        if (level == -1)            /* skip details */
974           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
975        else
976           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
977        break;
978     case M_ERROR:
979        if (level == -1)            /* skip details */
980           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
981        else
982           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
983        break;
984     case M_WARNING:
985        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
986        break;
987     case M_SECURITY:
988        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
989        break;
990     default:
991        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
992        break;
993     }
994
995     va_start(arg_ptr, fmt);
996     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
997     va_end(arg_ptr);
998
999     dispatch_message(NULL, type, 0, buf);
1000
1001     if (type == M_ABORT) {
1002        char *p = 0;
1003        p[0] = 0;                      /* generate segmentation violation */
1004     }
1005     if (type == M_ERROR_TERM) {
1006        exit(1);
1007     }
1008 }
1009
1010 /* *********************************************************
1011  *
1012  * Generate a Job message
1013  *
1014  */
1015 void
1016 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1017 {
1018     char     rbuf[5000];
1019     va_list   arg_ptr;
1020     int len;
1021     MSGS *msgs;
1022     const char *job;
1023
1024
1025     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1026
1027     /* Special case for the console, which has a dir_bsock and JobId==0,
1028      *  in that case, we send the message directly back to the
1029      *  dir_bsock.
1030      */
1031     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1032        BSOCK *dir = jcr->dir_bsock;
1033        va_start(arg_ptr, fmt);
1034        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1035                                 fmt, arg_ptr);
1036        va_end(arg_ptr);
1037        bnet_send(jcr->dir_bsock);
1038        return;
1039     }
1040
1041     msgs = NULL;
1042     job = NULL;
1043     if (jcr) {
1044        msgs = jcr->jcr_msgs;
1045        job = jcr->Job;
1046     }
1047     if (!msgs) {
1048        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1049     }
1050     if (!job) {
1051        job = "";                      /* Set null job name if none */
1052     }
1053
1054     /*
1055      * Check if we have a message destination defined.
1056      * We always report M_ABORT and M_ERROR_TERM
1057      */
1058     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1059          !bit_is_set(type, msgs->send_msg)) {
1060        return;                        /* no destination */
1061     }
1062     switch (type) {
1063     case M_ABORT:
1064        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1065        break;
1066     case M_ERROR_TERM:
1067        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1068        break;
1069     case M_FATAL:
1070        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1071        if (jcr) {
1072           set_jcr_job_status(jcr, JS_FatalError);
1073        }
1074        break;
1075     case M_ERROR:
1076        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1077        if (jcr) {
1078           jcr->Errors++;
1079        }
1080        break;
1081     case M_WARNING:
1082        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1083        break;
1084     case M_SECURITY:
1085        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1086        break;
1087     default:
1088        len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1089        break;
1090     }
1091
1092     va_start(arg_ptr, fmt);
1093     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1094     va_end(arg_ptr);
1095
1096     dispatch_message(jcr, type, mtime, rbuf);
1097
1098     if (type == M_ABORT){
1099        char *p = 0;
1100        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1101        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1102        p[0] = 0;                      /* generate segmentation violation */
1103     }
1104     if (type == M_ERROR_TERM) {
1105        exit(1);
1106     }
1107 }
1108
1109 /*
1110  * If we come here, prefix the message with the file:line-number,
1111  *  then pass it on to the normal Jmsg routine.
1112  */
1113 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1114 {
1115    va_list   arg_ptr;
1116    int i, len, maxlen;
1117    POOLMEM *pool_buf;
1118
1119    pool_buf = get_pool_memory(PM_EMSG);
1120    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1121
1122    for (;;) {
1123       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1124       va_start(arg_ptr, fmt);
1125       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1126       va_end(arg_ptr);
1127       if (len < 0 || len >= (maxlen-5)) {
1128          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1129          continue;
1130       }
1131       break;
1132    }
1133
1134    Jmsg(jcr, type, mtime, "%s", pool_buf);
1135    free_memory(pool_buf);
1136 }
1137
1138
1139 /*
1140  * Edit a message into a Pool memory buffer, with file:lineno
1141  */
1142 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1143 {
1144    va_list   arg_ptr;
1145    int i, len, maxlen;
1146
1147    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1148
1149    for (;;) {
1150       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1151       va_start(arg_ptr, fmt);
1152       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1153       va_end(arg_ptr);
1154       if (len < 0 || len >= (maxlen-5)) {
1155          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1156          continue;
1157       }
1158       break;
1159    }
1160    return len;
1161 }
1162
1163 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1164 {
1165    va_list   arg_ptr;
1166    int i, len, maxlen;
1167
1168    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1169
1170    for (;;) {
1171       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1172       va_start(arg_ptr, fmt);
1173       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1174       va_end(arg_ptr);
1175       if (len < 0 || len >= (maxlen-5)) {
1176          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1177          continue;
1178       }
1179       break;
1180    }
1181    return len;
1182 }
1183
1184
1185 /*
1186  * Edit a message into a Pool Memory buffer NO file:lineno
1187  *  Returns: string length of what was edited.
1188  */
1189 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1190 {
1191    va_list   arg_ptr;
1192    int len, maxlen;
1193
1194    for (;;) {
1195       maxlen = sizeof_pool_memory(*pool_buf) - 1;
1196       va_start(arg_ptr, fmt);
1197       len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1198       va_end(arg_ptr);
1199       if (len < 0 || len >= (maxlen-5)) {
1200          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1201          continue;
1202       }
1203       break;
1204    }
1205    return len;
1206 }
1207
1208 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1209 {
1210    va_list   arg_ptr;
1211    int len, maxlen;
1212
1213    for (;;) {
1214       maxlen = sizeof_pool_memory(pool_buf) - 1;
1215       va_start(arg_ptr, fmt);
1216       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1217       va_end(arg_ptr);
1218       if (len < 0 || len >= (maxlen-5)) {
1219          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1220          continue;
1221       }
1222       break;
1223    }
1224    return len;
1225 }
1226
1227 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1228 {
1229    va_list   arg_ptr;
1230    int len, maxlen;
1231
1232    for (;;) {
1233       maxlen = pool_buf.max_size() - 1;
1234       va_start(arg_ptr, fmt);
1235       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1236       va_end(arg_ptr);
1237       if (len < 0 || len >= (maxlen-5)) {
1238          pool_buf.realloc_pm(maxlen + maxlen/2);
1239          continue;
1240       }
1241       break;
1242    }
1243    return len;
1244 }
1245
1246
1247 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1248
1249 /*
1250  * We queue messages rather than print them directly. This
1251  *  is generally used in low level routines (msg handler, bnet)
1252  *  to prevent recursion (i.e. if you are in the middle of
1253  *  sending a message, it is a bit messy to recursively call
1254  *  yourself when the bnet packet is not reentrant).
1255  */
1256 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1257 {
1258    va_list   arg_ptr;
1259    int len, maxlen;
1260    POOLMEM *pool_buf;
1261    MQUEUE_ITEM *item;
1262
1263    pool_buf = get_pool_memory(PM_EMSG);
1264
1265    for (;;) {
1266       maxlen = sizeof_pool_memory(pool_buf) - 1;
1267       va_start(arg_ptr, fmt);
1268       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1269       va_end(arg_ptr);
1270       if (len < 0 || len >= (maxlen-5)) {
1271          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1272          continue;
1273       }
1274       break;
1275    }
1276    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1277    item->type = type;
1278    item->mtime = time(NULL);
1279    strcpy(item->msg, pool_buf);
1280    /* If no jcr or dequeuing send to daemon to avoid recursion */
1281    if (!jcr || jcr->dequeuing) {
1282       /* jcr==NULL => daemon message, safe to send now */
1283       Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1284       free(item);
1285    } else {
1286       /* Queue message for later sending */
1287       P(msg_queue_mutex);
1288       jcr->msg_queue->append(item);
1289       V(msg_queue_mutex);
1290    }
1291    free_memory(pool_buf);
1292 }
1293
1294 /*
1295  * Dequeue messages
1296  */
1297 void dequeue_messages(JCR *jcr)
1298 {
1299    MQUEUE_ITEM *item;
1300    P(msg_queue_mutex);
1301    if (!jcr->msg_queue) {
1302       goto bail_out;
1303    }
1304    jcr->dequeuing = true;
1305    foreach_dlist(item, jcr->msg_queue) {
1306       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1307    }
1308    jcr->msg_queue->destroy();
1309    jcr->dequeuing = false;
1310
1311 bail_out:
1312    V(msg_queue_mutex);
1313 }
1314
1315
1316 /*
1317  * If we come here, prefix the message with the file:line-number,
1318  *  then pass it on to the normal Qmsg routine.
1319  */
1320 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1321 {
1322    va_list   arg_ptr;
1323    int i, len, maxlen;
1324    POOLMEM *pool_buf;
1325
1326    pool_buf = get_pool_memory(PM_EMSG);
1327    i = Mmsg(pool_buf, "%s:%d ", file, line);
1328
1329    for (;;) {
1330       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1331       va_start(arg_ptr, fmt);
1332       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1333       va_end(arg_ptr);
1334       if (len < 0 || len >= (maxlen-5)) {
1335          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1336          continue;
1337       }
1338       break;
1339    }
1340
1341    Qmsg(jcr, type, mtime, "%s", pool_buf);
1342    free_memory(pool_buf);
1343 }