]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
kes Begin work on new GUI console.
[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
166    if (jcr == NULL && msg == NULL) {
167       init_last_jobs_list();
168    }
169
170 #if !defined(HAVE_WIN32)
171    /*
172     * Make sure we have fd's 0, 1, 2 open
173     *  If we don't do this one of our sockets may open
174     *  there and if we then use stdout, it could
175     *  send total garbage to our socket.
176     *
177     */
178    int fd;
179    int i;
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 #if !defined(HAVE_WIN32)
197       for (i=1; i<=M_MAX; i++) {
198          add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
199       }
200 #endif
201       Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
202       return;
203    }
204
205    /*
206     * Walk down the message resource chain duplicating it
207     * for the current Job.
208     */
209    for (d=msg->dest_chain; d; d=d->next) {
210       dnew = (DEST *)malloc(sizeof(DEST));
211       memcpy(dnew, d, sizeof(DEST));
212       dnew->next = temp_chain;
213       dnew->fd = NULL;
214       dnew->mail_filename = NULL;
215       if (d->mail_cmd) {
216          dnew->mail_cmd = bstrdup(d->mail_cmd);
217       }
218       if (d->where) {
219          dnew->where = bstrdup(d->where);
220       }
221       temp_chain = dnew;
222    }
223
224    if (jcr) {
225       jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
226       memset(jcr->jcr_msgs, 0, sizeof(MSGS));
227       jcr->jcr_msgs->dest_chain = temp_chain;
228       memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
229    } else {
230       /* If we have default values, release them now */
231       if (daemon_msgs) {
232          free_msgs_res(daemon_msgs);
233       }
234       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
235       memset(daemon_msgs, 0, sizeof(MSGS));
236       daemon_msgs->dest_chain = temp_chain;
237       memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
238    }
239    Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
240
241 }
242
243 /* Initialize so that the console (User Agent) can
244  * receive messages -- stored in a file.
245  */
246 void init_console_msg(const char *wd)
247 {
248    int fd;
249
250    bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
251    fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
252    if (fd == -1) {
253       berrno be;
254       Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
255           con_fname, be.strerror());
256    }
257    if (lseek(fd, 0, SEEK_END) > 0) {
258       console_msg_pending = 1;
259    }
260    close(fd);
261    con_fd = fopen(con_fname, "a+b");
262    if (!con_fd) {
263       berrno be;
264       Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
265           con_fname, be.strerror());
266    }
267    if (rwl_init(&con_lock) != 0) {
268       berrno be;
269       Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
270          be.strerror());
271    }
272 }
273
274 /*
275  * Called only during parsing of the config file.
276  *
277  * Add a message destination. I.e. associate a message type with
278  *  a destination (code).
279  * Note, where in the case of dest_code FILE is a filename,
280  *  but in the case of MAIL is a space separated list of
281  *  email addresses, ...
282  */
283 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
284 {
285    DEST *d;
286    /*
287     * First search the existing chain and see if we
288     * can simply add this msg_type to an existing entry.
289     */
290    for (d=msg->dest_chain; d; d=d->next) {
291       if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
292                      (strcmp(where, d->where) == 0))) {
293          Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
294              d, msg_type, dest_code, NPRT(where));
295          set_bit(msg_type, d->msg_types);
296          set_bit(msg_type, msg->send_msg);  /* set msg_type bit in our local */
297          return;
298       }
299    }
300    /* Not found, create a new entry */
301    d = (DEST *)malloc(sizeof(DEST));
302    memset(d, 0, sizeof(DEST));
303    d->next = msg->dest_chain;
304    d->dest_code = dest_code;
305    set_bit(msg_type, d->msg_types);      /* set type bit in structure */
306    set_bit(msg_type, msg->send_msg);     /* set type bit in our local */
307    if (where) {
308       d->where = bstrdup(where);
309    }
310    if (mail_cmd) {
311       d->mail_cmd = bstrdup(mail_cmd);
312    }
313    Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
314           d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
315    msg->dest_chain = d;
316 }
317
318 /*
319  * Called only during parsing of the config file.
320  *
321  * Remove a message destination
322  */
323 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
324 {
325    DEST *d;
326
327    for (d=msg->dest_chain; d; d=d->next) {
328       Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
329       if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
330           ((where == NULL && d->where == NULL) ||
331                      (strcmp(where, d->where) == 0))) {
332          Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
333                d, msg_type, dest_code);
334          clear_bit(msg_type, d->msg_types);
335          Dmsg0(850, "Return rem_msg_dest\n");
336          return;
337       }
338    }
339 }
340
341
342 /*
343  * Create a unique filename for the mail command
344  */
345 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
346 {
347    if (jcr) {
348       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
349                  jcr->Job, (int)(long)d);
350    } else {
351       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
352                  my_name, (int)(long)d);
353    }
354    Dmsg1(850, "mailname=%s\n", name);
355 }
356
357 /*
358  * Open a mail pipe
359  */
360 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
361 {
362    BPIPE *bpipe;
363
364    if (d->mail_cmd) {
365       cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
366    } else {
367       Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
368    }
369    fflush(stdout);
370
371    if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
372       berrno be;
373       Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
374          cmd, be.strerror());
375    }
376
377    /* If we had to use sendmail, add subject */
378    if (!d->mail_cmd) {
379        fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
380    }
381
382    return bpipe;
383 }
384
385 /*
386  * Close the messages for this Messages resource, which means to close
387  *  any open files, and dispatch any pending email messages.
388  */
389 void close_msg(JCR *jcr)
390 {
391    MSGS *msgs;
392    DEST *d;
393    BPIPE *bpipe;
394    POOLMEM *cmd, *line;
395    int len, stat;
396
397    Dmsg1(580, "Close_msg jcr=%p\n", jcr);
398
399    if (jcr == NULL) {                /* NULL -> global chain */
400       msgs = daemon_msgs;
401       P(mutex);                       /* only one thread walking the chain */
402    } else {
403       msgs = jcr->jcr_msgs;
404       jcr->jcr_msgs = NULL;
405    }
406    if (msgs == NULL) {
407       return;
408    }
409    Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
410    cmd = get_pool_memory(PM_MESSAGE);
411    for (d=msgs->dest_chain; d; ) {
412       if (d->fd) {
413          switch (d->dest_code) {
414          case MD_FILE:
415          case MD_APPEND:
416             if (d->fd) {
417                fclose(d->fd);            /* close open file descriptor */
418             }
419             break;
420          case MD_MAIL:
421          case MD_MAIL_ON_ERROR:
422             Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
423             if (!d->fd) {
424                break;
425             }
426             if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
427                 jcr->JobStatus == JS_Terminated) {
428                goto rem_temp_file;
429             }
430
431             if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
432                Pmsg0(000, _("open mail pipe failed.\n"));
433                goto rem_temp_file;
434             }
435             Dmsg0(850, "Opened mail pipe\n");
436             len = d->max_len+10;
437             line = get_memory(len);
438             rewind(d->fd);
439             while (fgets(line, len, d->fd)) {
440                fputs(line, bpipe->wfd);
441             }
442             if (!close_wpipe(bpipe)) {       /* close write pipe sending mail */
443                berrno be;
444                Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
445             }
446
447             /*
448              * Since we are closing all messages, before "recursing"
449              * make sure we are not closing the daemon messages, otherwise
450              * kaboom.
451              */
452             if (msgs != daemon_msgs) {
453                /* read what mail prog returned -- should be nothing */
454                while (fgets(line, len, bpipe->rfd)) {
455                   Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
456                }
457             }
458
459             stat = close_bpipe(bpipe);
460             if (stat != 0 && msgs != daemon_msgs) {
461                berrno be;
462                be.set_errno(stat);
463                Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
464                Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
465                                         "CMD=%s\n"
466                                         "ERR=%s\n"), cmd, be.strerror());
467             }
468             free_memory(line);
469 rem_temp_file:
470             /* Remove temp file */
471             fclose(d->fd);
472             unlink(d->mail_filename);
473             free_pool_memory(d->mail_filename);
474             d->mail_filename = NULL;
475             Dmsg0(850, "end mail or mail on error\n");
476             break;
477          default:
478             break;
479          }
480          d->fd = NULL;
481       }
482       d = d->next;                    /* point to next buffer */
483    }
484    free_pool_memory(cmd);
485    Dmsg0(850, "Done walking message chain.\n");
486    if (jcr) {
487       free_msgs_res(msgs);
488       msgs = NULL;
489    } else {
490       V(mutex);
491    }
492    Dmsg0(850, "===End close msg resource\n");
493 }
494
495 /*
496  * Free memory associated with Messages resource
497  */
498 void free_msgs_res(MSGS *msgs)
499 {
500    DEST *d, *old;
501
502    /* Walk down the message chain releasing allocated buffers */
503    for (d=msgs->dest_chain; d; ) {
504       if (d->where) {
505          free(d->where);
506       }
507       if (d->mail_cmd) {
508          free(d->mail_cmd);
509       }
510       old = d;                        /* save pointer to release */
511       d = d->next;                    /* point to next buffer */
512       free(old);                      /* free the destination item */
513    }
514    msgs->dest_chain = NULL;
515    free(msgs);                        /* free the head */
516 }
517
518
519 /*
520  * Terminate the message handler for good.
521  * Release the global destination chain.
522  *
523  * Also, clean up a few other items (cons, exepath). Note,
524  *   these really should be done elsewhere.
525  */
526 void term_msg()
527 {
528    Dmsg0(850, "Enter term_msg\n");
529    close_msg(NULL);                   /* close global chain */
530    free_msgs_res(daemon_msgs);        /* free the resources */
531    daemon_msgs = NULL;
532    if (con_fd) {
533       fflush(con_fd);
534       fclose(con_fd);
535       con_fd = NULL;
536    }
537    if (exepath) {
538       free(exepath);
539       exepath = NULL;
540    }
541    if (exename) {
542       free(exename);
543       exename = NULL;
544    }
545    if (trace_fd) {
546       fclose(trace_fd);
547       trace_fd = NULL;
548    }
549    term_last_jobs_list();
550 }
551
552 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode) 
553 {
554    d->fd = fopen(d->where, mode);
555    if (!d->fd) {
556       berrno be;
557       d->fd = stdout;
558       Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
559             be.strerror());
560       d->fd = NULL;
561       return false;
562    }
563    return true;
564 }
565
566 /*
567  * Handle sending the message to the appropriate place
568  */
569 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
570 {
571     DEST *d;
572     char dt[MAX_TIME_LENGTH];
573     POOLMEM *mcmd;
574     int len, dtlen;
575     MSGS *msgs;
576     BPIPE *bpipe;
577     char *mode;
578
579     Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
580
581     /*
582      * Most messages are prefixed by a date and time. If mtime is
583      *  zero, then we use the current time.  If mtime is 1 (special
584      *  kludge), we do not prefix the date and time. Otherwise,
585      *  we assume mtime is a time_t and use it.
586      */
587     if (mtime == 0) {
588        mtime = time(NULL);
589     }
590     if (mtime == 1) {
591        *dt = 0;
592        dtlen = 0;
593     } else {
594        bstrftime_ny(dt, sizeof(dt), mtime);
595        dtlen = strlen(dt);
596        dt[dtlen++] = ' ';
597        dt[dtlen] = 0;
598     }
599
600     if (type == M_ABORT || type == M_ERROR_TERM) {
601 #if !defined(HAVE_WIN32)
602        fputs(dt, stdout);
603        fputs(msg, stdout);         /* print this here to INSURE that it is printed */
604        fflush(stdout);
605 #endif
606     }
607
608     /* Now figure out where to send the message */
609     msgs = NULL;
610     if (jcr) {
611        msgs = jcr->jcr_msgs;
612     }
613     if (msgs == NULL) {
614        msgs = daemon_msgs;
615     }
616     for (d=msgs->dest_chain; d; d=d->next) {
617        if (bit_is_set(type, d->msg_types)) {
618           switch (d->dest_code) {
619              case MD_CATALOG:
620                 char ed1[50];
621                 if (!jcr || !jcr->db) {
622                    break;
623                 }
624                 if (p_sql_query) {
625                    POOL_MEM cmd(PM_MESSAGE);
626                    bstrftimes(dt, sizeof(dt), mtime);
627                    Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
628                          edit_int64(jcr->JobId, ed1), dt, msg);
629                    p_sql_query(jcr, cmd.c_str());
630                 }
631                 break;
632              case MD_CONSOLE:
633                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
634                 if (!con_fd) {
635                    con_fd = fopen(con_fname, "a+b");
636                    Dmsg0(850, "Console file not open.\n");
637                 }
638                 if (con_fd) {
639                    Pw(con_lock);      /* get write lock on console message file */
640                    errno = 0;
641                    if (dtlen) {
642                       (void)fwrite(dt, dtlen, 1, con_fd);
643                    }
644                    len = strlen(msg);
645                    if (len > 0) {
646                       (void)fwrite(msg, len, 1, con_fd);
647                       if (msg[len-1] != '\n') {
648                          (void)fwrite("\n", 2, 1, con_fd);
649                       }
650                    } else {
651                       (void)fwrite("\n", 2, 1, con_fd);
652                    }
653                    fflush(con_fd);
654                    console_msg_pending = TRUE;
655                    Vw(con_lock);
656                 }
657                 break;
658              case MD_SYSLOG:
659                 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
660                 /*
661                  * We really should do an openlog() here.
662                  */
663                 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
664                 break;
665              case MD_OPERATOR:
666                 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
667                 mcmd = get_pool_memory(PM_MESSAGE);
668                 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
669                    int stat;
670                    fputs(dt, bpipe->wfd);
671                    fputs(msg, bpipe->wfd);
672                    /* Messages to the operator go one at a time */
673                    stat = close_bpipe(bpipe);
674                    if (stat != 0) {
675                       berrno be;
676                       be.set_errno(stat);
677                       Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
678                             "CMD=%s\n"
679                             "ERR=%s\n"), mcmd, be.strerror());
680                    }
681                 }
682                 free_pool_memory(mcmd);
683                 break;
684              case MD_MAIL:
685              case MD_MAIL_ON_ERROR:
686                 Dmsg1(850, "MAIL for following msg: %s", msg);
687                 if (!d->fd) {
688                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
689                    make_unique_mail_filename(jcr, name, d);
690                    d->fd = fopen(name, "w+b");
691                    if (!d->fd) {
692                       berrno be;
693                       d->fd = stdout;
694                       Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
695                             be.strerror());
696                       d->fd = NULL;
697                       free_pool_memory(name);
698                       break;
699                    }
700                    d->mail_filename = name;
701                 }
702                 fputs(dt, d->fd);
703                 len = strlen(msg) + dtlen;;
704                 if (len > d->max_len) {
705                    d->max_len = len;      /* keep max line length */
706                 }
707                 fputs(msg, d->fd);
708                 break;
709              case MD_APPEND:
710                 Dmsg1(850, "APPEND for following msg: %s", msg);
711                 mode = "ab";
712                 goto send_to_file;
713              case MD_FILE:
714                 Dmsg1(850, "FILE for following msg: %s", msg);
715                 mode = "w+b";
716 send_to_file:
717                 if (!d->fd && !open_dest_file(jcr, d, mode)) {
718                    break;
719                 }
720                 fputs(dt, d->fd);
721                 fputs(msg, d->fd);
722                 /* On error, we close and reopen to handle log rotation */
723                 if (ferror(d->fd)) {
724                    fclose(d->fd);
725                    if (open_dest_file(jcr, d, mode)) {
726                       fputs(dt, d->fd);
727                       fputs(msg, d->fd);
728                    }
729                 }
730                 break;
731              case MD_DIRECTOR:
732                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
733                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
734                    bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
735                       jcr->Job, type, mtime, msg);
736                 }
737                 break;
738              case MD_STDOUT:
739                 Dmsg1(850, "STDOUT for following msg: %s", msg);
740                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
741                    fputs(dt, stdout);
742                    fputs(msg, stdout);
743                 }
744                 break;
745              case MD_STDERR:
746                 Dmsg1(850, "STDERR for following msg: %s", msg);
747                 fputs(dt, stderr);
748                 fputs(msg, stderr);
749                 break;
750              default:
751                 break;
752           }
753        }
754     }
755 }
756
757 /*********************************************************************
758  *
759  *  This subroutine returns the filename portion of a Windows 
760  *  path.  It is used because Microsoft Visual Studio sets __FILE__ 
761  *  to the full path.
762  */
763
764 inline const char *
765 get_basename(const char *pathname)
766 {
767 #if defined(_MSC_VER)
768    const char *basename;
769    
770    if ((basename = strrchr(pathname, '\\')) == NULL) {
771       basename = pathname;
772    } else {
773       basename++;
774    }
775
776    return basename;
777 #else
778    return pathname;
779 #endif
780 }
781
782 /*********************************************************************
783  *
784  *  This subroutine prints a debug message if the level number
785  *  is less than or equal the debug_level. File and line numbers
786  *  are included for more detail if desired, but not currently
787  *  printed.
788  *
789  *  If the level is negative, the details of file and line number
790  *  are not printed.
791  */
792 void
793 d_msg(const char *file, int line, int level, const char *fmt,...)
794 {
795     char      buf[5000];
796     int       len;
797     va_list   arg_ptr;
798     bool      details = true;
799
800     if (level < 0) {
801        details = false;
802        level = -level;
803     }
804
805     if (level <= debug_level) {
806 #ifdef FULL_LOCATION
807        if (details) {
808           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
809        } else {
810           len = 0;
811        }
812 #else
813        len = 0;
814 #endif
815        va_start(arg_ptr, fmt);
816        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
817        va_end(arg_ptr);
818
819        /*
820         * Used the "trace on" command in the console to turn on
821         *  output to the trace file.  "trace off" will close the file.
822         */
823        if (trace) {
824           if (!trace_fd) {
825              char fn[200];
826              bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
827              trace_fd = fopen(fn, "a+b");
828           }
829           if (trace_fd) {
830              fputs(buf, trace_fd);
831              fflush(trace_fd);
832           } else {
833              /* Some problem, turn off tracing */
834              trace = false;
835           }
836        } else {   /* not tracing */
837           fputs(buf, stdout);
838        }
839     }
840 }
841
842 /*
843  * Set trace flag on/off. If argument is negative, there is no change
844  */
845 void set_trace(int trace_flag)
846 {
847    if (trace_flag < 0) {
848       return;
849    } else if (trace_flag > 0) {
850       trace = true;
851    } else {
852       trace = false;
853    }
854    if (!trace && trace_fd) {
855       FILE *ltrace_fd = trace_fd;
856       trace_fd = NULL;
857       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
858       fclose(ltrace_fd);
859    }
860 }
861
862 bool get_trace(void)
863 {
864    return trace;
865 }
866
867 /*********************************************************************
868  *
869  *  This subroutine prints a message regardless of the debug level
870  *
871  *  If the level is negative, the details of file and line number
872  *  are not printed.
873  */
874 void
875 p_msg(const char *file, int line, int level, const char *fmt,...)
876 {
877     char      buf[5000];
878     int       len;
879     va_list   arg_ptr;
880
881 #ifdef FULL_LOCATION
882     if (level >= 0) {
883        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
884     } else {
885        len = 0;
886     }
887 #else
888     len = 0;
889 #endif
890     va_start(arg_ptr, fmt);
891     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
892     va_end(arg_ptr);
893     fputs(buf, stdout);
894 }
895
896
897 /*********************************************************************
898  *
899  *  subroutine writes a debug message to the trace file if the level number
900  *  is less than or equal the debug_level. File and line numbers
901  *  are included for more detail if desired, but not currently
902  *  printed.
903  *
904  *  If the level is negative, the details of file and line number
905  *  are not printed.
906  */
907 void
908 t_msg(const char *file, int line, int level, const char *fmt,...)
909 {
910     char      buf[5000];
911     int       len;
912     va_list   arg_ptr;
913     int       details = TRUE;
914
915     if (level < 0) {
916        details = FALSE;
917        level = -level;
918     }
919
920     if (level <= debug_level) {
921        if (!trace_fd) {
922           bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
923           trace_fd = fopen(buf, "a+b");
924        }
925
926 #ifdef FULL_LOCATION
927        if (details) {
928           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
929        } else {
930           len = 0;
931        }
932 #else
933        len = 0;
934 #endif
935        va_start(arg_ptr, fmt);
936        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
937        va_end(arg_ptr);
938        if (trace_fd != NULL) {
939            fputs(buf, trace_fd);
940            fflush(trace_fd);
941        }
942    }
943 }
944
945
946
947 /* *********************************************************
948  *
949  * print an error message
950  *
951  */
952 void
953 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
954 {
955     char     buf[5000];
956     va_list   arg_ptr;
957     int len;
958
959     /*
960      * Check if we have a message destination defined.
961      * We always report M_ABORT and M_ERROR_TERM
962      */
963     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
964                          !bit_is_set(type, daemon_msgs->send_msg))) {
965        return;                        /* no destination */
966     }
967     switch (type) {
968     case M_ABORT:
969        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
970                my_name, get_basename(file), line);
971        break;
972     case M_ERROR_TERM:
973        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
974                my_name, get_basename(file), line);
975        break;
976     case M_FATAL:
977        if (level == -1)            /* skip details */
978           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
979        else
980           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
981        break;
982     case M_ERROR:
983        if (level == -1)            /* skip details */
984           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
985        else
986           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
987        break;
988     case M_WARNING:
989        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
990        break;
991     case M_SECURITY:
992        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
993        break;
994     default:
995        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
996        break;
997     }
998
999     va_start(arg_ptr, fmt);
1000     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1001     va_end(arg_ptr);
1002
1003     dispatch_message(NULL, type, 0, buf);
1004
1005     if (type == M_ABORT) {
1006        char *p = 0;
1007        p[0] = 0;                      /* generate segmentation violation */
1008     }
1009     if (type == M_ERROR_TERM) {
1010        exit(1);
1011     }
1012 }
1013
1014 /* *********************************************************
1015  *
1016  * Generate a Job message
1017  *
1018  */
1019 void
1020 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1021 {
1022     char     rbuf[5000];
1023     va_list   arg_ptr;
1024     int len;
1025     MSGS *msgs;
1026     const char *job;
1027
1028
1029     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1030
1031     /* Special case for the console, which has a dir_bsock and JobId==0,
1032      *  in that case, we send the message directly back to the
1033      *  dir_bsock.
1034      */
1035     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1036        BSOCK *dir = jcr->dir_bsock;
1037        va_start(arg_ptr, fmt);
1038        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1039                                 fmt, arg_ptr);
1040        va_end(arg_ptr);
1041        bnet_send(jcr->dir_bsock);
1042        return;
1043     }
1044
1045     msgs = NULL;
1046     job = NULL;
1047     if (jcr) {
1048        msgs = jcr->jcr_msgs;
1049        job = jcr->Job;
1050     }
1051     if (!msgs) {
1052        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1053     }
1054     if (!job) {
1055        job = "";                      /* Set null job name if none */
1056     }
1057
1058     /*
1059      * Check if we have a message destination defined.
1060      * We always report M_ABORT and M_ERROR_TERM
1061      */
1062     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1063          !bit_is_set(type, msgs->send_msg)) {
1064        return;                        /* no destination */
1065     }
1066     switch (type) {
1067     case M_ABORT:
1068        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1069        break;
1070     case M_ERROR_TERM:
1071        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1072        break;
1073     case M_FATAL:
1074        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1075        if (jcr) {
1076           set_jcr_job_status(jcr, JS_FatalError);
1077        }
1078        break;
1079     case M_ERROR:
1080        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1081        if (jcr) {
1082           jcr->Errors++;
1083        }
1084        break;
1085     case M_WARNING:
1086        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1087        break;
1088     case M_SECURITY:
1089        len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1090        break;
1091     default:
1092        len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1093        break;
1094     }
1095
1096     va_start(arg_ptr, fmt);
1097     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1098     va_end(arg_ptr);
1099
1100     dispatch_message(jcr, type, mtime, rbuf);
1101
1102     if (type == M_ABORT){
1103        char *p = 0;
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 }