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