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