]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/message.c
c51056348831d16f9282a1aeba9ace0cc340b181
[bacula/bacula] / bacula / src / lib / message.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Bacula message handling routines
30  *
31  * NOTE: don't use any Jmsg or Qmsg calls within this file,
32  *   except in q_msg or j_msg (setup routines), 
33  *   otherwise you may get into recursive calls if there are
34  *   errors, and that can lead to looping or deadlocks.
35  *
36  *   Kern Sibbald, April 2000
37  *
38  */
39
40 #include "bacula.h"
41 #include "jcr.h"
42
43 sql_query_func p_sql_query = NULL;
44 sql_escape_func p_sql_escape = NULL;
45
46 #define FULL_LOCATION 1               /* set for file:line in Debug messages */
47
48 /*
49  *  This is where we define "Globals" because all the
50  *    daemons include this file.
51  */
52 const char *working_directory = NULL;       /* working directory path stored here */
53 int verbose = 0;                      /* increase User messages */
54 int debug_level = 0;                  /* debug level */
55 bool dbg_timestamp = false;           /* print timestamp in debug output */
56 bool prt_kaboom = false;              /* Print kaboom output */
57 utime_t daemon_start_time = 0;        /* Daemon start time */
58 const char *version = VERSION " (" BDATE ")";
59 const char *dist_name = DISTNAME " " DISTVER;
60 int beef = BEEF;
61 char my_name[30] = {0};               /* daemon name is stored here */
62 char host_name[50] = {0};             /* host machine name */
63 char *exepath = (char *)NULL;
64 char *exename = (char *)NULL;
65 int console_msg_pending = false;
66 char con_fname[500];                  /* Console filename */
67 FILE *con_fd = NULL;                  /* Console file descriptor */
68 brwlock_t con_lock;                   /* Console lock structure */
69
70 /* Forward referenced functions */
71
72 /* Imported functions */
73 void create_jcr_key();
74
75 /* Static storage */
76
77 /* Exclude spaces but require .mail at end */
78 #define MAIL_REGEX "^[^ ]+\\.mail$"
79
80 /* Allow only one thread to tweak d->fd at a time */
81 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
82 static MSGS *daemon_msgs;              /* global messages */
83 static char *catalog_db = NULL;       /* database type */
84 static void (*message_callback)(int type, char *msg) = NULL;
85 static FILE *trace_fd = NULL;
86 #if defined(HAVE_WIN32)
87 static bool trace = true;
88 #else
89 static bool trace = false;
90 #endif
91 static int hangup = 0;
92
93 /* Constants */
94 const char *host_os = HOST_OS;
95 const char *distname = DISTNAME;
96 const char *distver = DISTVER;
97
98 /*
99  * Walk back in a string from end looking for a
100  *  path separator.  
101  *  This routine is passed the start of the string and
102  *  the end of the string, it returns either the beginning
103  *  of the string or where it found a path separator.
104  */
105 static const char *bstrrpath(const char *start, const char *end)
106 {
107    while ( end > start ) {
108       end--;   
109       if (IsPathSeparator(*end)) {
110          break;
111       }
112    }
113    return end;
114 }
115
116 /* Some message class methods */
117 void MSGS::lock()
118 {
119    P(fides_mutex);
120 }
121
122 void MSGS::unlock()
123 {
124    V(fides_mutex);
125 }
126
127 /*
128  * Wait for not in use variable to be clear
129  */
130 void MSGS::wait_not_in_use()     /* leaves fides_mutex set */
131 {
132    lock();
133    while (m_in_use || m_closing) {
134       unlock();
135       bmicrosleep(0, 200);         /* wait */
136       lock();
137    }
138 }
139
140 /*
141  * Handle message delivery errors
142  */
143 static void delivery_error(const char *fmt,...)
144 {
145    va_list   arg_ptr;
146    int i, len, maxlen;
147    POOLMEM *pool_buf;
148    char dt[MAX_TIME_LENGTH];
149    int dtlen;
150
151    pool_buf = get_pool_memory(PM_EMSG);
152
153    bstrftime_ny(dt, sizeof(dt), time(NULL));
154    dtlen = strlen(dt);
155    dt[dtlen++] = ' ';
156    dt[dtlen] = 0;
157
158    i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
159
160    for (;;) {
161       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
162       va_start(arg_ptr, fmt);
163       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
164       va_end(arg_ptr);
165       if (len < 0 || len >= (maxlen-5)) {
166          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
167          continue;
168       }
169       break;
170    }
171
172    fputs(pool_buf, stdout);  /* print this here to INSURE that it is printed */
173    fflush(stdout);
174    syslog(LOG_DAEMON|LOG_ERR, "%s", pool_buf);
175    free_memory(pool_buf);
176 }                 
177
178 void register_message_callback(void msg_callback(int type, char *msg))
179 {
180    message_callback = msg_callback;
181 }
182
183
184 /*
185  * Set daemon name. Also, find canonical execution
186  *  path.  Note, exepath has spare room for tacking on
187  *  the exename so that we can reconstruct the full name.
188  *
189  * Note, this routine can get called multiple times
190  *  The second time is to put the name as found in the
191  *  Resource record. On the second call, generally,
192  *  argv is NULL to avoid doing the path code twice.
193  */
194 void my_name_is(int argc, char *argv[], const char *name)
195 {
196    char *l, *p, *q;
197    char cpath[1024];
198    int len;
199
200    if (gethostname(host_name, sizeof(host_name)) != 0) {
201       bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
202    }
203    bstrncpy(my_name, name, sizeof(my_name));
204    if (argc>0 && argv && argv[0]) {
205       /* strip trailing filename and save exepath */
206       for (l=p=argv[0]; *p; p++) {
207          if (IsPathSeparator(*p)) {
208             l = p;                       /* set pos of last slash */
209          }
210       }
211       if (IsPathSeparator(*l)) {
212          l++;
213       } else {
214          l = argv[0];
215 #if defined(HAVE_WIN32)
216          /* On Windows allow c: drive specification */
217          if (l[1] == ':') {
218             l += 2;
219          }
220 #endif
221       }
222       len = strlen(l) + 1;
223       if (exename) {
224          free(exename);
225       }
226       exename = (char *)malloc(len);
227       strcpy(exename, l);
228
229       if (exepath) {
230          free(exepath);
231       }
232       exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
233       for (p=argv[0],q=exepath; p < l; ) {
234          *q++ = *p++;
235       }
236       *q = 0;
237       if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
238          if (getcwd(cpath, sizeof(cpath))) {
239             free(exepath);
240             exepath = (char *)malloc(strlen(cpath) + 1 + len);
241             strcpy(exepath, cpath);
242          }
243       }
244       Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
245    }
246 }
247
248 void
249 set_db_type(const char *name)
250 {
251    if (catalog_db != NULL) {
252       free(catalog_db);
253    }
254    catalog_db = bstrdup(name);
255 }
256
257 /*
258  * Initialize message handler for a daemon or a Job
259  *   We make a copy of the MSGS resource passed, so it belows
260  *   to the job or daemon and thus can be modified.
261  *
262  *   NULL for jcr -> initialize global messages for daemon
263  *   non-NULL     -> initialize jcr using Message resource
264  */
265 void
266 init_msg(JCR *jcr, MSGS *msg)
267 {
268    DEST *d, *dnew, *temp_chain = NULL;
269    int i;
270
271    if (jcr == NULL && msg == NULL) {
272       init_last_jobs_list();
273       /* Create a daemon key then set invalid jcr */
274       /* Maybe we should give the daemon a jcr??? */
275       create_jcr_key();
276       set_jcr_in_tsd(INVALID_JCR);
277    }
278
279 #if !defined(HAVE_WIN32)
280    /*
281     * Make sure we have fd's 0, 1, 2 open
282     *  If we don't do this one of our sockets may open
283     *  there and if we then use stdout, it could
284     *  send total garbage to our socket.
285     *
286     */
287    int fd;
288    fd = open("/dev/null", O_RDONLY, 0644);
289    if (fd > 2) {
290       close(fd);
291    } else {
292       for(i=1; fd + i <= 2; i++) {
293          dup2(fd, fd+i);
294       }
295    }
296
297 #endif
298    /*
299     * If msg is NULL, initialize global chain for STDOUT and syslog
300     */
301    if (msg == NULL) {
302       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
303       memset(daemon_msgs, 0, sizeof(MSGS));
304       for (i=1; i<=M_MAX; i++) {
305          add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
306       }
307       Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
308       return;
309    }
310
311    /*
312     * Walk down the message resource chain duplicating it
313     * for the current Job.
314     */
315    for (d=msg->dest_chain; d; d=d->next) {
316       dnew = (DEST *)malloc(sizeof(DEST));
317       memcpy(dnew, d, sizeof(DEST));
318       dnew->next = temp_chain;
319       dnew->fd = NULL;
320       dnew->mail_filename = NULL;
321       if (d->mail_cmd) {
322          dnew->mail_cmd = bstrdup(d->mail_cmd);
323       }
324       if (d->where) {
325          dnew->where = bstrdup(d->where);
326       }
327       temp_chain = dnew;
328    }
329
330    if (jcr) {
331       jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
332       memset(jcr->jcr_msgs, 0, sizeof(MSGS));
333       jcr->jcr_msgs->dest_chain = temp_chain;
334       memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
335    } else {
336       /* If we have default values, release them now */
337       if (daemon_msgs) {
338          free_msgs_res(daemon_msgs);
339       }
340       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
341       memset(daemon_msgs, 0, sizeof(MSGS));
342       daemon_msgs->dest_chain = temp_chain;
343       memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
344    }
345
346    Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
347
348 }
349
350 /* Initialize so that the console (User Agent) can
351  * receive messages -- stored in a file.
352  */
353 void init_console_msg(const char *wd)
354 {
355    int fd;
356
357    bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
358    fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
359    if (fd == -1) {
360       berrno be;
361       Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
362           con_fname, be.bstrerror());
363    }
364    if (lseek(fd, 0, SEEK_END) > 0) {
365       console_msg_pending = 1;
366    }
367    close(fd);
368    con_fd = fopen(con_fname, "a+b");
369    if (!con_fd) {
370       berrno be;
371       Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
372           con_fname, be.bstrerror());
373    }
374    if (rwl_init(&con_lock) != 0) {
375       berrno be;
376       Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
377          be.bstrerror());
378    }
379 }
380
381 /*
382  * Called only during parsing of the config file.
383  *
384  * Add a message destination. I.e. associate a message type with
385  *  a destination (code).
386  * Note, where in the case of dest_code FILE is a filename,
387  *  but in the case of MAIL is a space separated list of
388  *  email addresses, ...
389  */
390 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
391 {
392    DEST *d;
393    /*
394     * First search the existing chain and see if we
395     * can simply add this msg_type to an existing entry.
396     */
397    for (d=msg->dest_chain; d; d=d->next) {
398       if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
399                      (strcmp(where, d->where) == 0))) {
400          Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
401              d, msg_type, dest_code, NPRT(where));
402          set_bit(msg_type, d->msg_types);
403          set_bit(msg_type, msg->send_msg);  /* set msg_type bit in our local */
404          return;
405       }
406    }
407    /* Not found, create a new entry */
408    d = (DEST *)malloc(sizeof(DEST));
409    memset(d, 0, sizeof(DEST));
410    d->next = msg->dest_chain;
411    d->dest_code = dest_code;
412    set_bit(msg_type, d->msg_types);      /* set type bit in structure */
413    set_bit(msg_type, msg->send_msg);     /* set type bit in our local */
414    if (where) {
415       d->where = bstrdup(where);
416    }
417    if (mail_cmd) {
418       d->mail_cmd = bstrdup(mail_cmd);
419    }
420    Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
421           d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
422    msg->dest_chain = d;
423 }
424
425 /*
426  * Called only during parsing of the config file.
427  *
428  * Remove a message destination
429  */
430 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
431 {
432    DEST *d;
433
434    for (d=msg->dest_chain; d; d=d->next) {
435       Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
436       if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
437           ((where == NULL && d->where == NULL) ||
438                      (strcmp(where, d->where) == 0))) {
439          Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
440                d, msg_type, dest_code);
441          clear_bit(msg_type, d->msg_types);
442          Dmsg0(850, "Return rem_msg_dest\n");
443          return;
444       }
445    }
446 }
447
448
449 /*
450  * Create a unique filename for the mail command
451  */
452 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
453 {
454    if (jcr) {
455       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
456                  jcr->Job, (int)(intptr_t)d);
457    } else {
458       Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
459                  my_name, (int)(intptr_t)d);
460    }
461    Dmsg1(850, "mailname=%s\n", name);
462 }
463
464 /*
465  * Open a mail pipe
466  */
467 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
468 {
469    BPIPE *bpipe;
470
471    if (d->mail_cmd) {
472       cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
473    } else {
474       Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
475    }
476    fflush(stdout);
477
478    if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
479       /* If we had to use sendmail, add subject */
480       if (!d->mail_cmd) {
481          fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
482       }
483    } else {
484       berrno be;
485       delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
486          cmd, be.bstrerror());
487    }
488    return bpipe;
489 }
490
491 /*
492  * Close the messages for this Messages resource, which means to close
493  *  any open files, and dispatch any pending email messages.
494  */
495 void close_msg(JCR *jcr)
496 {
497    MSGS *msgs;
498    DEST *d;
499    BPIPE *bpipe;
500    POOLMEM *cmd, *line;
501    int len, stat;
502
503    Dmsg1(580, "Close_msg jcr=%p\n", jcr);
504
505    if (jcr == NULL) {                /* NULL -> global chain */
506       msgs = daemon_msgs;
507    } else {
508       msgs = jcr->jcr_msgs;
509       jcr->jcr_msgs = NULL;
510    }
511    if (msgs == NULL) {
512       return;
513    }
514
515    /* Wait for item to be not in use, then mark closing */
516    if (msgs->is_closing()) {
517       return;
518    }
519    msgs->wait_not_in_use();          /* leaves fides_mutex set */
520    /* Note get_closing() does not lock because we are already locked */
521    if (msgs->get_closing()) {
522       msgs->unlock();
523       return;
524    }
525    msgs->set_closing();
526    msgs->unlock();
527
528    Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
529    cmd = get_pool_memory(PM_MESSAGE);
530    for (d=msgs->dest_chain; d; ) {
531       if (d->fd) {
532          switch (d->dest_code) {
533          case MD_FILE:
534          case MD_APPEND:
535             if (d->fd) {
536                fclose(d->fd);            /* close open file descriptor */
537                d->fd = NULL;
538             }
539             break;
540          case MD_MAIL:
541          case MD_MAIL_ON_ERROR:
542          case MD_MAIL_ON_SUCCESS:
543             Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
544             if (!d->fd) {
545                break;
546             }
547
548             switch (d->dest_code) {
549             case MD_MAIL_ON_ERROR:
550                if (jcr) {
551                   switch (jcr->JobStatus) {
552                   case JS_Terminated:
553                   case JS_Warnings:
554                      goto rem_temp_file;
555                   default:
556                      break;
557                   }
558                }
559                break;
560             case MD_MAIL_ON_SUCCESS:
561                if (jcr) {
562                   switch (jcr->JobStatus) {
563                   case JS_Terminated:
564                   case JS_Warnings:
565                      break;
566                   default:
567                      goto rem_temp_file;
568                   }
569                }
570                break;
571             default:
572                break;
573             }
574
575             if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
576                Pmsg0(000, _("open mail pipe failed.\n"));
577                goto rem_temp_file;
578             }
579
580             Dmsg0(850, "Opened mail pipe\n");
581             len = d->max_len+10;
582             line = get_memory(len);
583             rewind(d->fd);
584             while (fgets(line, len, d->fd)) {
585                fputs(line, bpipe->wfd);
586             }
587             if (!close_wpipe(bpipe)) {       /* close write pipe sending mail */
588                berrno be;
589                Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
590             }
591
592             /*
593              * Since we are closing all messages, before "recursing"
594              * make sure we are not closing the daemon messages, otherwise
595              * kaboom.
596              */
597             if (msgs != daemon_msgs) {
598                /* read what mail prog returned -- should be nothing */
599                while (fgets(line, len, bpipe->rfd)) {
600                   delivery_error(_("Mail prog: %s"), line);
601                }
602             }
603
604             stat = close_bpipe(bpipe);
605             if (stat != 0 && msgs != daemon_msgs) {
606                berrno be;
607                be.set_errno(stat);
608                Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
609                delivery_error(_("Mail program terminated in error.\n"
610                                  "CMD=%s\n"
611                                  "ERR=%s\n"), cmd, be.bstrerror());
612             }
613             free_memory(line);
614 rem_temp_file:
615             /* Remove temp file */
616             if (d->fd) {
617                fclose(d->fd);
618                d->fd = NULL;
619             }
620             if (d->mail_filename) {
621                /* Exclude spaces in mail_filename */
622                safer_unlink(d->mail_filename, MAIL_REGEX);
623                free_pool_memory(d->mail_filename);
624                d->mail_filename = NULL;
625             }
626             Dmsg0(850, "end mail or mail on error\n");
627             break;
628          default:
629             break;
630          }
631          d->fd = NULL;
632       }
633       d = d->next;                    /* point to next buffer */
634    }
635    free_pool_memory(cmd);
636    Dmsg0(850, "Done walking message chain.\n");
637    if (jcr) {
638       free_msgs_res(msgs);
639       msgs = NULL;
640    } else {
641       msgs->clear_closing();
642    }
643    Dmsg0(850, "===End close msg resource\n");
644 }
645
646 /*
647  * Free memory associated with Messages resource
648  */
649 void free_msgs_res(MSGS *msgs)
650 {
651    DEST *d, *old;
652
653    /* Walk down the message chain releasing allocated buffers */
654    for (d=msgs->dest_chain; d; ) {
655       if (d->where) {
656          free(d->where);
657       }
658       if (d->mail_cmd) {
659          free(d->mail_cmd);
660       }
661       old = d;                        /* save pointer to release */
662       d = d->next;                    /* point to next buffer */
663       free(old);                      /* free the destination item */
664    }
665    msgs->dest_chain = NULL;
666    free(msgs);                        /* free the head */
667 }
668
669
670 /*
671  * Terminate the message handler for good.
672  * Release the global destination chain.
673  *
674  * Also, clean up a few other items (cons, exepath). Note,
675  *   these really should be done elsewhere.
676  */
677 void term_msg()
678 {
679    Dmsg0(850, "Enter term_msg\n");
680    close_msg(NULL);                   /* close global chain */
681    free_msgs_res(daemon_msgs);        /* free the resources */
682    daemon_msgs = NULL;
683    if (con_fd) {
684       fflush(con_fd);
685       fclose(con_fd);
686       con_fd = NULL;
687    }
688    if (exepath) {
689       free(exepath);
690       exepath = NULL;
691    }
692    if (exename) {
693       free(exename);
694       exename = NULL;
695    }
696    if (trace_fd) {
697       fclose(trace_fd);
698       trace_fd = NULL;
699    }
700    if (catalog_db) {
701       free(catalog_db);
702       catalog_db = NULL;
703    }
704    term_last_jobs_list();
705 }
706
707 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode) 
708 {
709    d->fd = fopen(d->where, mode);
710    if (!d->fd) {
711       berrno be;
712       delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
713       return false;
714    }
715    return true;
716 }
717
718 /* Split the output for syslog (it converts \n to ' ' and is
719  *   limited to 1024 characters per syslog message
720  */
721 static void send_to_syslog(int mode, const char *msg)
722 {
723    int len;
724    char buf[1024];
725    const char *p2;
726    const char *p = msg;
727
728    while (*p && ((p2 = strchr(p, '\n')) != NULL)) {
729       len = MIN((int)sizeof(buf) - 1, p2 - p + 1); /* Add 1 to keep \n */
730       strncpy(buf, p, len);
731       buf[len] = 0;
732       syslog(mode, "%s", buf);
733       p = p2+1;                 /* skip \n */
734    }
735    if (*p != 0) {               /* no \n at the end ? */
736       syslog(mode, "%s", p);
737    }
738 }
739
740 /*
741  * Handle sending the message to the appropriate place
742  */
743 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
744 {
745     DEST *d;
746     char dt[MAX_TIME_LENGTH];
747     POOLMEM *mcmd;
748     int len, dtlen;
749     MSGS *msgs;
750     BPIPE *bpipe;
751     const char *mode;
752
753     Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
754
755     /*
756      * Most messages are prefixed by a date and time. If mtime is
757      *  zero, then we use the current time.  If mtime is 1 (special
758      *  kludge), we do not prefix the date and time. Otherwise,
759      *  we assume mtime is a utime_t and use it.
760      */
761     if (mtime == 0) {
762        mtime = time(NULL);
763     }
764     if (mtime == 1) {
765        *dt = 0;
766        dtlen = 0;
767        mtime = time(NULL);      /* get time for SQL log */
768     } else {
769        bstrftime_ny(dt, sizeof(dt), mtime);
770        dtlen = strlen(dt);
771        dt[dtlen++] = ' ';
772        dt[dtlen] = 0;
773     }
774
775     /* If the program registered a callback, send it there */
776     if (message_callback) {
777        message_callback(type, msg);
778        return;
779     }
780
781     /* For serious errors make sure message is printed or logged */
782     if (type == M_ABORT || type == M_ERROR_TERM) {
783        fputs(dt, stdout);
784        fputs(msg, stdout);
785        fflush(stdout);
786        if (type == M_ABORT) {
787           syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
788        }
789     }
790
791
792     /* Now figure out where to send the message */
793     msgs = NULL;
794     if (!jcr) {
795        jcr = get_jcr_from_tsd();
796     }
797     if (jcr) {
798        msgs = jcr->jcr_msgs;
799     }
800     if (msgs == NULL) {
801        msgs = daemon_msgs;
802     }
803     /*
804      * If closing this message resource, print and send to syslog,
805      *   then get out.
806      */
807     if (msgs->is_closing()) {
808        fputs(dt, stdout);
809        fputs(msg, stdout);
810        fflush(stdout);
811        syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
812        return;
813     }
814
815     for (d=msgs->dest_chain; d; d=d->next) {
816        if (bit_is_set(type, d->msg_types)) {
817           switch (d->dest_code) {
818              case MD_CATALOG:
819                 char ed1[50];
820                 if (!jcr || !jcr->db || !jcr->db->is_connected()) {
821                    break;
822                 }
823                 if (p_sql_query && p_sql_escape) {
824                    POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
825                    POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
826                    
827                    int len = strlen(msg) + 1;
828                    esc_msg = check_pool_memory_size(esc_msg, len * 2 + 1);
829                    p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
830
831                    bstrutime(dt, sizeof(dt), mtime);
832                    Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
833                          edit_int64(jcr->JobId, ed1), dt, esc_msg);
834                    p_sql_query(jcr, cmd);
835                    
836                    free_pool_memory(cmd);
837                    free_pool_memory(esc_msg);
838                 }
839                 break;
840              case MD_CONSOLE:
841                 Dmsg1(850, "CONSOLE for following msg: %s", msg);
842                 if (!con_fd) {
843                    con_fd = fopen(con_fname, "a+b");
844                    Dmsg0(850, "Console file not open.\n");
845                 }
846                 if (con_fd) {
847                    Pw(con_lock);      /* get write lock on console message file */
848                    errno = 0;
849                    if (dtlen) {
850                       (void)fwrite(dt, dtlen, 1, con_fd);
851                    }
852                    len = strlen(msg);
853                    if (len > 0) {
854                       (void)fwrite(msg, len, 1, con_fd);
855                       if (msg[len-1] != '\n') {
856                          (void)fwrite("\n", 2, 1, con_fd);
857                       }
858                    } else {
859                       (void)fwrite("\n", 2, 1, con_fd);
860                    }
861                    fflush(con_fd);
862                    console_msg_pending = true;
863                    Vw(con_lock);
864                 }
865                 break;
866              case MD_SYSLOG:
867                 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
868                 /*
869                  * We really should do an openlog() here.
870                  */
871                 send_to_syslog(LOG_DAEMON|LOG_ERR, msg);
872                 break;
873              case MD_OPERATOR:
874                 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
875                 mcmd = get_pool_memory(PM_MESSAGE);
876                 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
877                    int stat;
878                    fputs(dt, bpipe->wfd);
879                    fputs(msg, bpipe->wfd);
880                    /* Messages to the operator go one at a time */
881                    stat = close_bpipe(bpipe);
882                    if (stat != 0) {
883                       berrno be;
884                       be.set_errno(stat);
885                       delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
886                             "CMD=%s\n"
887                             "ERR=%s\n"), mcmd, be.bstrerror());
888                    }
889                 }
890                 free_pool_memory(mcmd);
891                 break;
892              case MD_MAIL:
893              case MD_MAIL_ON_ERROR:
894              case MD_MAIL_ON_SUCCESS:
895                 Dmsg1(850, "MAIL for following msg: %s", msg);
896                 if (msgs->is_closing()) {
897                    break;
898                 }
899                 msgs->set_in_use();
900                 if (!d->fd) {
901                    POOLMEM *name = get_pool_memory(PM_MESSAGE);
902                    make_unique_mail_filename(jcr, name, d);
903                    d->fd = fopen(name, "w+b");
904                    if (!d->fd) {
905                       berrno be;
906                       delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
907                             be.bstrerror());
908                       free_pool_memory(name);
909                       msgs->clear_in_use();
910                       break;
911                    }
912                    d->mail_filename = name;
913                 }
914                 fputs(dt, d->fd);
915                 len = strlen(msg) + dtlen;;
916                 if (len > d->max_len) {
917                    d->max_len = len;      /* keep max line length */
918                 }
919                 fputs(msg, d->fd);
920                 msgs->clear_in_use();
921                 break;
922              case MD_APPEND:
923                 Dmsg1(850, "APPEND for following msg: %s", msg);
924                 mode = "ab";
925                 goto send_to_file;
926              case MD_FILE:
927                 Dmsg1(850, "FILE for following msg: %s", msg);
928                 mode = "w+b";
929 send_to_file:
930                 if (msgs->is_closing()) {
931                    break;
932                 }
933                 msgs->set_in_use();
934                 if (!d->fd && !open_dest_file(jcr, d, mode)) {
935                    msgs->clear_in_use();
936                    break;
937                 }
938                 fputs(dt, d->fd);
939                 fputs(msg, d->fd);
940                 /* On error, we close and reopen to handle log rotation */
941                 if (ferror(d->fd)) {
942                    fclose(d->fd);
943                    d->fd = NULL;
944                    if (open_dest_file(jcr, d, mode)) {
945                       fputs(dt, d->fd);
946                       fputs(msg, d->fd);
947                    }
948                 }
949                 msgs->clear_in_use();
950                 break;
951              case MD_DIRECTOR:
952                 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
953                 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
954                    jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
955                       jcr->Job, type, mtime, msg);
956                 } else {
957                    Dmsg1(800, "no jcr for following msg: %s", msg);
958                 }
959                 break;
960              case MD_STDOUT:
961                 Dmsg1(850, "STDOUT for following msg: %s", msg);
962                 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
963                    fputs(dt, stdout);
964                    fputs(msg, stdout);
965                    fflush(stdout);
966                 }
967                 break;
968              case MD_STDERR:
969                 Dmsg1(850, "STDERR for following msg: %s", msg);
970                 fputs(dt, stderr);
971                 fputs(msg, stderr);
972                 fflush(stdout);
973                 break;
974              default:
975                 break;
976           }
977        }
978     }
979 }
980
981 /*********************************************************************
982  *
983  *  This subroutine returns the filename portion of a path.  
984  *  It is used because some compilers set __FILE__ 
985  *  to the full path.  Try to return base + next higher path.
986  */
987
988 const char *get_basename(const char *pathname)
989 {
990    const char *basename;
991    
992    if ((basename = bstrrpath(pathname, pathname+strlen(pathname))) == pathname) {
993       /* empty */
994    } else if ((basename = bstrrpath(pathname, basename-1)) == pathname) {
995       /* empty */
996    } else {
997       basename++;
998    }
999    return basename;
1000 }
1001
1002 /*
1003  * print or write output to trace file 
1004  */
1005 static void pt_out(char *buf)
1006 {
1007     /*
1008      * Used the "trace on" command in the console to turn on
1009      *  output to the trace file.  "trace off" will close the file.
1010      */
1011     if (trace) {
1012        if (!trace_fd) {
1013           char fn[200];
1014           bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
1015           trace_fd = fopen(fn, "a+b");
1016        }
1017        if (trace_fd) {
1018           fputs(buf, trace_fd);
1019           fflush(trace_fd);
1020           return;
1021        } else {
1022           /* Some problem, turn off tracing */
1023           trace = false;
1024        }
1025     }
1026     /* not tracing */
1027     fputs(buf, stdout);
1028     fflush(stdout);
1029 }
1030
1031 /*********************************************************************
1032  *
1033  *  This subroutine prints a debug message if the level number
1034  *  is less than or equal the debug_level. File and line numbers
1035  *  are included for more detail if desired, but not currently
1036  *  printed.
1037  *
1038  *  If the level is negative, the details of file and line number
1039  *  are not printed.
1040  */
1041 void
1042 d_msg(const char *file, int line, int level, const char *fmt,...)
1043 {
1044     char      buf[5000];
1045     int       len;
1046     va_list   arg_ptr;
1047     bool      details = true;
1048     utime_t   mtime;
1049
1050     if (level < 0) {
1051        details = false;
1052        level = -level;
1053     }
1054
1055     if (level <= debug_level) {
1056        if (dbg_timestamp) {
1057           mtime = time(NULL);
1058           bstrftimes(buf, sizeof(buf), mtime);
1059           len = strlen(buf);
1060           buf[len++] = ' ';
1061           buf[len] = 0;
1062           pt_out(buf);
1063        }
1064     
1065 #ifdef FULL_LOCATION
1066        if (details) {
1067           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d-%u ", 
1068                 my_name, get_basename(file), line, get_jobid_from_tsd());
1069        } else {
1070           len = 0;
1071        }
1072 #else
1073        len = 0;
1074 #endif
1075        va_start(arg_ptr, fmt);
1076        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1077        va_end(arg_ptr);
1078
1079        pt_out(buf);
1080     }
1081 }
1082
1083 /*
1084  * Set trace flag on/off. If argument is negative, there is no change
1085  */
1086 void set_trace(int trace_flag)
1087 {
1088    if (trace_flag < 0) {
1089       return;
1090    } else if (trace_flag > 0) {
1091       trace = true;
1092    } else {
1093       trace = false;
1094    }
1095    if (!trace && trace_fd) {
1096       FILE *ltrace_fd = trace_fd;
1097       trace_fd = NULL;
1098       bmicrosleep(0, 100000);         /* yield to prevent seg faults */
1099       fclose(ltrace_fd);
1100    }
1101 }
1102
1103 void set_hangup(int hangup_value)
1104 {
1105    if (hangup_value < 0) {
1106       return;
1107    } else {
1108       hangup = hangup_value;
1109    }
1110 }
1111
1112 int get_hangup(void)
1113 {
1114    return hangup;
1115 }
1116
1117 bool get_trace(void)
1118 {
1119    return trace;
1120 }
1121
1122 /*********************************************************************
1123  *
1124  *  This subroutine prints a message regardless of the debug level
1125  *
1126  *  If the level is negative, the details of file and line number
1127  *  are not printed.
1128  */
1129 void
1130 p_msg(const char *file, int line, int level, const char *fmt,...)
1131 {
1132     char      buf[5000];
1133     int       len;
1134     va_list   arg_ptr;
1135
1136 #ifdef FULL_LOCATION
1137     if (level >= 0) {
1138        len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1139     } else {
1140        len = 0;
1141     }
1142 #else
1143     len = 0;
1144 #endif
1145     va_start(arg_ptr, fmt);
1146     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1147     va_end(arg_ptr);
1148
1149     pt_out(buf);     
1150 }
1151
1152
1153 /*********************************************************************
1154  *
1155  *  subroutine writes a debug message to the trace file if the level number
1156  *  is less than or equal the debug_level. File and line numbers
1157  *  are included for more detail if desired, but not currently
1158  *  printed.
1159  *
1160  *  If the level is negative, the details of file and line number
1161  *  are not printed.
1162  */
1163 void
1164 t_msg(const char *file, int line, int level, const char *fmt,...)
1165 {
1166     char      buf[5000];
1167     int       len;
1168     va_list   arg_ptr;
1169     int       details = TRUE;
1170
1171     if (level < 0) {
1172        details = FALSE;
1173        level = -level;
1174     }
1175
1176     if (level <= debug_level) {
1177        if (!trace_fd) {
1178           bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1179           trace_fd = fopen(buf, "a+b");
1180        }
1181
1182 #ifdef FULL_LOCATION
1183        if (details) {
1184           len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1185        } else {
1186           len = 0;
1187        }
1188 #else
1189        len = 0;
1190 #endif
1191        va_start(arg_ptr, fmt);
1192        bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1193        va_end(arg_ptr);
1194        if (trace_fd != NULL) {
1195            fputs(buf, trace_fd);
1196            fflush(trace_fd);
1197        }
1198    }
1199 }
1200
1201 /* *********************************************************
1202  *
1203  * print an error message
1204  *
1205  */
1206 void
1207 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1208 {
1209     char     buf[5000];
1210     va_list   arg_ptr;
1211     int len;
1212
1213     /*
1214      * Check if we have a message destination defined.
1215      * We always report M_ABORT and M_ERROR_TERM
1216      */
1217     if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1218                          !bit_is_set(type, daemon_msgs->send_msg))) {
1219        return;                        /* no destination */
1220     }
1221     switch (type) {
1222     case M_ABORT:
1223        len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1224                my_name, get_basename(file), line);
1225        break;
1226     case M_ERROR_TERM:
1227        len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1228                my_name, get_basename(file), line);
1229        break;
1230     case M_FATAL:
1231        if (level == -1)            /* skip details */
1232           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1233        else
1234           len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1235        break;
1236     case M_ERROR:
1237        if (level == -1)            /* skip details */
1238           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1239        else
1240           len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1241        break;
1242     case M_WARNING:
1243        len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1244        break;
1245     case M_SECURITY:
1246        len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1247        break;
1248     default:
1249        len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1250        break;
1251     }
1252
1253     va_start(arg_ptr, fmt);
1254     bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1255     va_end(arg_ptr);
1256
1257     dispatch_message(NULL, type, 0, buf);
1258
1259     if (type == M_ABORT) {
1260        char *p = 0;
1261        p[0] = 0;                      /* generate segmentation violation */
1262     }
1263     if (type == M_ERROR_TERM) {
1264        exit(1);
1265     }
1266 }
1267
1268 /* *********************************************************
1269  *
1270  * Generate a Job message
1271  *
1272  */
1273 void
1274 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1275 {
1276     char     rbuf[5000];
1277     va_list   arg_ptr;
1278     int len;
1279     MSGS *msgs;
1280     uint32_t JobId = 0;
1281
1282
1283     Dmsg1(850, "Enter Jmsg type=%d\n", type);
1284
1285     /* Special case for the console, which has a dir_bsock and JobId==0,
1286      *  in that case, we send the message directly back to the
1287      *  dir_bsock.
1288      */
1289     if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1290        BSOCK *dir = jcr->dir_bsock;
1291        va_start(arg_ptr, fmt);
1292        dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1293                                 fmt, arg_ptr);
1294        va_end(arg_ptr);
1295        jcr->dir_bsock->send();
1296        return;
1297     }
1298
1299     /* The watchdog thread can't use Jmsg directly, we always queued it */
1300     if (is_watchdog()) {
1301        va_start(arg_ptr, fmt);
1302        bvsnprintf(rbuf,  sizeof(rbuf), fmt, arg_ptr);
1303        va_end(arg_ptr);
1304        Qmsg(jcr, type, mtime, "%s", rbuf);
1305        return;
1306     }
1307
1308     msgs = NULL;
1309     if (!jcr) {
1310        jcr = get_jcr_from_tsd();
1311     }
1312     if (jcr) {
1313        if (!jcr->dequeuing_msgs) { /* Avoid recursion */
1314           /* Dequeue messages to keep the original order  */
1315           dequeue_messages(jcr); 
1316        }
1317        msgs = jcr->jcr_msgs;
1318        JobId = jcr->JobId;
1319     }
1320     if (!msgs) {
1321        msgs = daemon_msgs;            /* if no jcr, we use daemon handler */
1322     }
1323
1324     /*
1325      * Check if we have a message destination defined.
1326      * We always report M_ABORT and M_ERROR_TERM
1327      */
1328     if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1329          !bit_is_set(type, msgs->send_msg)) {
1330        return;                        /* no destination */
1331     }
1332     switch (type) {
1333     case M_ABORT:
1334        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1335        break;
1336     case M_ERROR_TERM:
1337        len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1338        break;
1339     case M_FATAL:
1340        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1341        if (jcr) {
1342           jcr->setJobStatus(JS_FatalError);
1343        }
1344        if (jcr && jcr->JobErrors == 0) {
1345           jcr->JobErrors = 1;
1346        }
1347        break;
1348     case M_ERROR:
1349        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1350        if (jcr) {
1351           jcr->JobErrors++;
1352        }
1353        break;
1354     case M_WARNING:
1355        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1356        if (jcr) {
1357           jcr->JobWarnings++;
1358        }
1359        break;
1360     case M_SECURITY:
1361        len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "), 
1362                my_name, JobId);
1363        break;
1364     default:
1365        len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1366        break;
1367     }
1368
1369     va_start(arg_ptr, fmt);
1370     bvsnprintf(rbuf+len,  sizeof(rbuf)-len, fmt, arg_ptr);
1371     va_end(arg_ptr);
1372
1373     dispatch_message(jcr, type, mtime, rbuf);
1374
1375     if (type == M_ABORT){
1376        char *p = 0;
1377        printf("Bacula forced SEG FAULT to obtain traceback.\n");
1378        syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1379        p[0] = 0;                      /* generate segmentation violation */
1380     }
1381     if (type == M_ERROR_TERM) {
1382        exit(1);
1383     }
1384 }
1385
1386 /*
1387  * If we come here, prefix the message with the file:line-number,
1388  *  then pass it on to the normal Jmsg routine.
1389  */
1390 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1391 {
1392    va_list   arg_ptr;
1393    int i, len, maxlen;
1394    POOLMEM *pool_buf;
1395
1396    pool_buf = get_pool_memory(PM_EMSG);
1397    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1398
1399    for (;;) {
1400       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1401       va_start(arg_ptr, fmt);
1402       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1403       va_end(arg_ptr);
1404       if (len < 0 || len >= (maxlen-5)) {
1405          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1406          continue;
1407       }
1408       break;
1409    }
1410
1411    Jmsg(jcr, type, mtime, "%s", pool_buf);
1412    free_memory(pool_buf);
1413 }
1414
1415
1416 /*
1417  * Edit a message into a Pool memory buffer, with file:lineno
1418  */
1419 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1420 {
1421    va_list   arg_ptr;
1422    int i, len, maxlen;
1423
1424    i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1425
1426    for (;;) {
1427       maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1428       va_start(arg_ptr, fmt);
1429       len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1430       va_end(arg_ptr);
1431       if (len < 0 || len >= (maxlen-5)) {
1432          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1433          continue;
1434       }
1435       break;
1436    }
1437    return len;
1438 }
1439
1440 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1441 {
1442    va_list   arg_ptr;
1443    int i, len, maxlen;
1444
1445    i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1446
1447    for (;;) {
1448       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1449       va_start(arg_ptr, fmt);
1450       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1451       va_end(arg_ptr);
1452       if (len < 0 || len >= (maxlen-5)) {
1453          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1454          continue;
1455       }
1456       break;
1457    }
1458    return len;
1459 }
1460
1461
1462 /*
1463  * Edit a message into a Pool Memory buffer NO file:lineno
1464  *  Returns: string length of what was edited.
1465  */
1466 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1467 {
1468    va_list   arg_ptr;
1469    int len, maxlen;
1470
1471    for (;;) {
1472       maxlen = sizeof_pool_memory(*pool_buf) - 1;
1473       va_start(arg_ptr, fmt);
1474       len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1475       va_end(arg_ptr);
1476       if (len < 0 || len >= (maxlen-5)) {
1477          *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1478          continue;
1479       }
1480       break;
1481    }
1482    return len;
1483 }
1484
1485 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1486 {
1487    va_list   arg_ptr;
1488    int len, maxlen;
1489
1490    for (;;) {
1491       maxlen = sizeof_pool_memory(pool_buf) - 1;
1492       va_start(arg_ptr, fmt);
1493       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1494       va_end(arg_ptr);
1495       if (len < 0 || len >= (maxlen-5)) {
1496          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1497          continue;
1498       }
1499       break;
1500    }
1501    return len;
1502 }
1503
1504 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1505 {
1506    va_list   arg_ptr;
1507    int len, maxlen;
1508
1509    for (;;) {
1510       maxlen = pool_buf.max_size() - 1;
1511       va_start(arg_ptr, fmt);
1512       len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1513       va_end(arg_ptr);
1514       if (len < 0 || len >= (maxlen-5)) {
1515          pool_buf.realloc_pm(maxlen + maxlen/2);
1516          continue;
1517       }
1518       break;
1519    }
1520    return len;
1521 }
1522
1523
1524 /*
1525  * We queue messages rather than print them directly. This
1526  *  is generally used in low level routines (msg handler, bnet)
1527  *  to prevent recursion (i.e. if you are in the middle of
1528  *  sending a message, it is a bit messy to recursively call
1529  *  yourself when the bnet packet is not reentrant).
1530  */
1531 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1532 {
1533    va_list   arg_ptr;
1534    int len, maxlen;
1535    POOLMEM *pool_buf;
1536    MQUEUE_ITEM *item;
1537
1538    pool_buf = get_pool_memory(PM_EMSG);
1539
1540    for (;;) {
1541       maxlen = sizeof_pool_memory(pool_buf) - 1;
1542       va_start(arg_ptr, fmt);
1543       len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1544       va_end(arg_ptr);
1545       if (len < 0 || len >= (maxlen-5)) {
1546          pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1547          continue;
1548       }
1549       break;
1550    }
1551    item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1552    item->type = type;
1553    item->mtime = time(NULL);
1554    strcpy(item->msg, pool_buf);
1555    if (!jcr) {
1556       jcr = get_jcr_from_tsd();
1557    }
1558    /* If no jcr or no queue or dequeuing send to syslog */
1559    if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1560       syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1561       free(item);
1562    } else {
1563       /* Queue message for later sending */
1564       P(jcr->msg_queue_mutex);
1565       jcr->msg_queue->append(item);
1566       V(jcr->msg_queue_mutex);
1567    }
1568    free_memory(pool_buf);
1569 }
1570
1571 /*
1572  * Dequeue messages
1573  */
1574 void dequeue_messages(JCR *jcr)
1575 {
1576    MQUEUE_ITEM *item;
1577    if (!jcr->msg_queue) {
1578       return;
1579    }
1580    P(jcr->msg_queue_mutex);
1581    jcr->dequeuing_msgs = true;
1582    foreach_dlist(item, jcr->msg_queue) {
1583       Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1584    }
1585    /* Remove messages just sent */
1586    jcr->msg_queue->destroy();
1587    jcr->dequeuing_msgs = false;
1588    V(jcr->msg_queue_mutex);
1589 }
1590
1591
1592 /*
1593  * If we come here, prefix the message with the file:line-number,
1594  *  then pass it on to the normal Qmsg routine.
1595  */
1596 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1597 {
1598    va_list   arg_ptr;
1599    int i, len, maxlen;
1600    POOLMEM *pool_buf;
1601
1602    pool_buf = get_pool_memory(PM_EMSG);
1603    i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1604
1605    for (;;) {
1606       maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1607       va_start(arg_ptr, fmt);
1608       len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1609       va_end(arg_ptr);
1610       if (len < 0 || len >= (maxlen-5)) {
1611          pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1612          continue;
1613       }
1614       break;
1615    }
1616
1617    Qmsg(jcr, type, mtime, "%s", pool_buf);
1618    free_memory(pool_buf);
1619 }