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