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