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