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