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