2 * Bacula message handling routines
4 * Kern Sibbald, April 2000
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
29 sql_query p_sql_query = NULL;
31 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
34 * This is where we define "Globals" because all the
35 * daemons include this file.
37 const char *working_directory = NULL; /* working directory path stored here */
38 int verbose = 0; /* increase User messages */
39 int debug_level = 0; /* debug level */
40 time_t daemon_start_time = 0; /* Daemon start time */
41 const char *version = VERSION " (" BDATE ")";
42 char my_name[30]; /* daemon name is stored here */
43 char *exepath = (char *)NULL;
44 char *exename = (char *)NULL;
45 int console_msg_pending = 0;
46 char con_fname[500]; /* Console filename */
47 FILE *con_fd = NULL; /* Console file descriptor */
48 brwlock_t con_lock; /* Console lock structure */
51 #if defined(HAVE_POSTGRESQL)
52 char catalog_db[] = "PostgreSQL";
53 #elif defined(HAVE_MYSQL)
54 char catalog_db[] = "MySQL";
55 #elif defined(HAVE_SQLITE)
56 char catalog_db[] = "SQLite";
58 char catalog_db[] = "Internal";
61 const char *host_os = HOST_OS;
62 const char *distname = DISTNAME;
63 const char *distver = DISTVER;
64 static FILE *trace_fd = NULL;
65 #if defined(HAVE_WIN32)
66 static bool trace = true;
68 static bool trace = false;
71 /* Forward referenced functions */
73 /* Imported functions */
78 /* Used to allow only one thread close the daemon messages at a time */
79 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
80 static MSGS *daemon_msgs; /* global messages */
84 * Set daemon name. Also, find canonical execution
85 * path. Note, exepath has spare room for tacking on
86 * the exename so that we can reconstruct the full name.
88 * Note, this routine can get called multiple times
89 * The second time is to put the name as found in the
90 * Resource record. On the second call, generally,
91 * argv is NULL to avoid doing the path code twice.
93 #define BTRACE_EXTRA 20
94 void my_name_is(int argc, char *argv[], const char *name)
100 bstrncpy(my_name, name, sizeof(my_name));
101 if (argc>0 && argv && argv[0]) {
102 /* strip trailing filename and save exepath */
103 for (l=p=argv[0]; *p; p++) {
105 l = p; /* set pos of last slash */
112 #if defined(HAVE_WIN32)
113 /* On Windows allow c: junk */
123 exename = (char *)malloc(len);
129 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
130 for (p=argv[0],q=exepath; p < l; ) {
134 if (strchr(exepath, '.') || exepath[0] != '/') {
135 if (getcwd(cpath, sizeof(cpath))) {
137 exepath = (char *)malloc(strlen(cpath) + 1 + len);
138 strcpy(exepath, cpath);
141 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
146 * Initialize message handler for a daemon or a Job
147 * We make a copy of the MSGS resource passed, so it belows
148 * to the job or daemon and thus can be modified.
150 * NULL for jcr -> initialize global messages for daemon
151 * non-NULL -> initialize jcr using Message resource
154 init_msg(JCR *jcr, MSGS *msg)
156 DEST *d, *dnew, *temp_chain = NULL;
158 if (jcr == NULL && msg == NULL) {
159 init_last_jobs_list();
162 #if !defined(HAVE_WIN32)
164 * Make sure we have fd's 0, 1, 2 open
165 * If we don't do this one of our sockets may open
166 * there and if we then use stdout, it could
167 * send total garbage to our socket.
172 fd = open("/dev/null", O_RDONLY, 0644);
176 for(i=1; fd + i <= 2; i++) {
183 * If msg is NULL, initialize global chain for STDOUT and syslog
186 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
187 memset(daemon_msgs, 0, sizeof(MSGS));
188 #if !defined(HAVE_WIN32)
189 for (i=1; i<=M_MAX; i++) {
190 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
193 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
198 * Walk down the message resource chain duplicating it
199 * for the current Job.
201 for (d=msg->dest_chain; d; d=d->next) {
202 dnew = (DEST *)malloc(sizeof(DEST));
203 memcpy(dnew, d, sizeof(DEST));
204 dnew->next = temp_chain;
206 dnew->mail_filename = NULL;
208 dnew->mail_cmd = bstrdup(d->mail_cmd);
211 dnew->where = bstrdup(d->where);
217 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
218 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
219 jcr->jcr_msgs->dest_chain = temp_chain;
220 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
222 /* If we have default values, release them now */
224 free_msgs_res(daemon_msgs);
226 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
227 memset(daemon_msgs, 0, sizeof(MSGS));
228 daemon_msgs->dest_chain = temp_chain;
229 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
231 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
235 /* Initialize so that the console (User Agent) can
236 * receive messages -- stored in a file.
238 void init_console_msg(const char *wd)
242 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
243 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
246 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
247 con_fname, be.strerror());
249 if (lseek(fd, 0, SEEK_END) > 0) {
250 console_msg_pending = 1;
253 con_fd = fopen(con_fname, "a+b");
256 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
257 con_fname, be.strerror());
259 if (rwl_init(&con_lock) != 0) {
261 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
267 * Called only during parsing of the config file.
269 * Add a message destination. I.e. associate a message type with
270 * a destination (code).
271 * Note, where in the case of dest_code FILE is a filename,
272 * but in the case of MAIL is a space separated list of
273 * email addresses, ...
275 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
279 * First search the existing chain and see if we
280 * can simply add this msg_type to an existing entry.
282 for (d=msg->dest_chain; d; d=d->next) {
283 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
284 (strcmp(where, d->where) == 0))) {
285 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
286 d, msg_type, dest_code, NPRT(where));
287 set_bit(msg_type, d->msg_types);
288 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
292 /* Not found, create a new entry */
293 d = (DEST *)malloc(sizeof(DEST));
294 memset(d, 0, sizeof(DEST));
295 d->next = msg->dest_chain;
296 d->dest_code = dest_code;
297 set_bit(msg_type, d->msg_types); /* set type bit in structure */
298 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
300 d->where = bstrdup(where);
303 d->mail_cmd = bstrdup(mail_cmd);
305 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
306 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
311 * Called only during parsing of the config file.
313 * Remove a message destination
315 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
319 for (d=msg->dest_chain; d; d=d->next) {
320 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
321 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
322 ((where == NULL && d->where == NULL) ||
323 (strcmp(where, d->where) == 0))) {
324 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
325 d, msg_type, dest_code);
326 clear_bit(msg_type, d->msg_types);
327 Dmsg0(850, "Return rem_msg_dest\n");
335 * Create a unique filename for the mail command
337 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
340 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
341 jcr->Job, (int)(long)d);
343 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
344 my_name, (int)(long)d);
346 Dmsg1(850, "mailname=%s\n", name);
352 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
357 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
359 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
363 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
365 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
369 /* If we had to use sendmail, add subject */
371 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
378 * Close the messages for this Messages resource, which means to close
379 * any open files, and dispatch any pending email messages.
381 void close_msg(JCR *jcr)
389 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
391 if (jcr == NULL) { /* NULL -> global chain */
393 P(mutex); /* only one thread walking the chain */
395 msgs = jcr->jcr_msgs;
396 jcr->jcr_msgs = NULL;
401 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
402 cmd = get_pool_memory(PM_MESSAGE);
403 for (d=msgs->dest_chain; d; ) {
405 switch (d->dest_code) {
409 fclose(d->fd); /* close open file descriptor */
413 case MD_MAIL_ON_ERROR:
414 Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
418 if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
419 jcr->JobStatus == JS_Terminated) {
423 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
424 Pmsg0(000, _("open mail pipe failed.\n"));
427 Dmsg0(850, "Opened mail pipe\n");
429 line = get_memory(len);
431 while (fgets(line, len, d->fd)) {
432 fputs(line, bpipe->wfd);
434 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
436 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
440 * Since we are closing all messages, before "recursing"
441 * make sure we are not closing the daemon messages, otherwise
444 if (msgs != daemon_msgs) {
445 /* read what mail prog returned -- should be nothing */
446 while (fgets(line, len, bpipe->rfd)) {
447 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
451 stat = close_bpipe(bpipe);
452 if (stat != 0 && msgs != daemon_msgs) {
455 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
456 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
458 "ERR=%s\n"), cmd, be.strerror());
462 /* Remove temp file */
464 unlink(d->mail_filename);
465 free_pool_memory(d->mail_filename);
466 d->mail_filename = NULL;
467 Dmsg0(850, "end mail or mail on error\n");
474 d = d->next; /* point to next buffer */
476 free_pool_memory(cmd);
477 Dmsg0(850, "Done walking message chain.\n");
484 Dmsg0(850, "===End close msg resource\n");
488 * Free memory associated with Messages resource
490 void free_msgs_res(MSGS *msgs)
494 /* Walk down the message chain releasing allocated buffers */
495 for (d=msgs->dest_chain; d; ) {
502 old = d; /* save pointer to release */
503 d = d->next; /* point to next buffer */
504 free(old); /* free the destination item */
506 msgs->dest_chain = NULL;
507 free(msgs); /* free the head */
512 * Terminate the message handler for good.
513 * Release the global destination chain.
515 * Also, clean up a few other items (cons, exepath). Note,
516 * these really should be done elsewhere.
520 Dmsg0(850, "Enter term_msg\n");
521 close_msg(NULL); /* close global chain */
522 free_msgs_res(daemon_msgs); /* free the resources */
541 term_last_jobs_list();
547 * Handle sending the message to the appropriate place
549 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
552 char dt[MAX_TIME_LENGTH];
558 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
561 * Most messages are prefixed by a date and time. If mtime is
562 * zero, then we use the current time. If mtime is 1 (special
563 * kludge), we do not prefix the date and time. Otherwise,
564 * we assume mtime is a time_t and use it.
573 bstrftime_ny(dt, sizeof(dt), mtime);
579 if (type == M_ABORT || type == M_ERROR_TERM) {
580 #if !defined(HAVE_WIN32)
582 fputs(msg, stdout); /* print this here to INSURE that it is printed */
587 /* Now figure out where to send the message */
590 msgs = jcr->jcr_msgs;
595 for (d=msgs->dest_chain; d; d=d->next) {
596 if (bit_is_set(type, d->msg_types)) {
597 switch (d->dest_code) {
600 if (!jcr || !jcr->db) {
604 POOL_MEM cmd(PM_MESSAGE);
605 bstrftimes(dt, sizeof(dt), mtime);
606 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
607 edit_int64(jcr->JobId, ed1), dt, msg);
608 p_sql_query(jcr, cmd.c_str());
612 Dmsg1(850, "CONSOLE for following msg: %s", msg);
614 con_fd = fopen(con_fname, "a+b");
615 Dmsg0(850, "Console file not open.\n");
618 Pw(con_lock); /* get write lock on console message file */
621 (void)fwrite(dt, dtlen, 1, con_fd);
625 (void)fwrite(msg, len, 1, con_fd);
626 if (msg[len-1] != '\n') {
627 (void)fwrite("\n", 2, 1, con_fd);
630 (void)fwrite("\n", 2, 1, con_fd);
633 console_msg_pending = TRUE;
638 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
640 * We really should do an openlog() here.
642 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
645 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
646 mcmd = get_pool_memory(PM_MESSAGE);
647 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
649 fputs(dt, bpipe->wfd);
650 fputs(msg, bpipe->wfd);
651 /* Messages to the operator go one at a time */
652 stat = close_bpipe(bpipe);
656 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
658 "ERR=%s\n"), mcmd, be.strerror());
661 free_pool_memory(mcmd);
664 case MD_MAIL_ON_ERROR:
665 Dmsg1(850, "MAIL for following msg: %s", msg);
667 POOLMEM *name = get_pool_memory(PM_MESSAGE);
668 make_unique_mail_filename(jcr, name, d);
669 d->fd = fopen(name, "w+b");
673 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
676 free_pool_memory(name);
679 d->mail_filename = name;
682 len = strlen(msg) + dtlen;;
683 if (len > d->max_len) {
684 d->max_len = len; /* keep max line length */
689 Dmsg1(850, "FILE for following msg: %s", msg);
691 d->fd = fopen(d->where, "w+b");
695 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
705 Dmsg1(850, "APPEND for following msg: %s", msg);
707 d->fd = fopen(d->where, "ab");
711 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
721 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
722 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
723 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
724 jcr->Job, type, mtime, msg);
728 Dmsg1(850, "STDOUT for following msg: %s", msg);
729 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
735 Dmsg1(850, "STDERR for following msg: %s", msg);
747 /*********************************************************************
749 * This subroutine prints a debug message if the level number
750 * is less than or equal the debug_level. File and line numbers
751 * are included for more detail if desired, but not currently
754 * If the level is negative, the details of file and line number
758 d_msg(const char *file, int line, int level, const char *fmt,...)
770 if (level <= debug_level) {
773 /* visual studio passes the whole path to the file as well
774 * which makes for very long lines
776 const char *basename;
778 if ((basename = strrchr(file, '\\')) == NULL) {
783 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, basename, line);
790 va_start(arg_ptr, fmt);
791 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
795 * Used the "trace on" command in the console to turn on
796 * output to the trace file. "trace off" will close the file.
801 bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
802 trace_fd = fopen(fn, "a+b");
805 fputs(buf, trace_fd);
808 /* Some problem, turn off tracing */
811 } else { /* not tracing */
818 * Set trace flag on/off. If argument is negative, there is no change
820 void set_trace(int trace_flag)
822 if (trace_flag < 0) {
824 } else if (trace_flag > 0) {
829 if (!trace && trace_fd) {
830 FILE *ltrace_fd = trace_fd;
832 bmicrosleep(0, 100000); /* yield to prevent seg faults */
842 /*********************************************************************
844 * This subroutine prints a message regardless of the debug level
846 * If the level is negative, the details of file and line number
850 p_msg(const char *file, int line, int level, const char *fmt,...)
858 const char *basename;
860 if ((basename = strrchr(file, '\\')) == NULL) {
865 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, basename, line);
872 va_start(arg_ptr, fmt);
873 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
879 /*********************************************************************
881 * subroutine writes a debug message to the trace file if the level number
882 * is less than or equal the debug_level. File and line numbers
883 * are included for more detail if desired, but not currently
886 * If the level is negative, the details of file and line number
890 t_msg(const char *file, int line, int level, const char *fmt,...)
902 if (level <= debug_level) {
904 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
905 trace_fd = fopen(buf, "a+b");
910 const char *basename;
912 if ((basename = strrchr(file, '\\')) == NULL) {
917 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, basename, line);
924 va_start(arg_ptr, fmt);
925 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
927 if (trace_fd != NULL) {
928 fputs(buf, trace_fd);
936 /* *********************************************************
938 * print an error message
942 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
948 const char *basename;
950 if ((basename = strrchr(file, '\\')) == NULL) {
957 * Check if we have a message destination defined.
958 * We always report M_ABORT and M_ERROR_TERM
960 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
961 !bit_is_set(type, daemon_msgs->send_msg))) {
962 return; /* no destination */
966 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
967 my_name, basename, line);
970 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
971 my_name, basename, line);
974 if (level == -1) /* skip details */
975 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
977 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, basename, line);
980 if (level == -1) /* skip details */
981 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
983 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, basename, line);
986 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
989 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
992 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
996 va_start(arg_ptr, fmt);
997 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1000 dispatch_message(NULL, type, 0, buf);
1002 if (type == M_ABORT) {
1004 p[0] = 0; /* generate segmentation violation */
1006 if (type == M_ERROR_TERM) {
1011 /* *********************************************************
1013 * Generate a Job message
1017 Jmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1026 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1028 /* Special case for the console, which has a dir_bsock and JobId==0,
1029 * in that case, we send the message directly back to the
1032 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1033 BSOCK *dir = jcr->dir_bsock;
1034 va_start(arg_ptr, fmt);
1035 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1038 bnet_send(jcr->dir_bsock);
1045 msgs = jcr->jcr_msgs;
1049 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1052 job = ""; /* Set null job name if none */
1056 * Check if we have a message destination defined.
1057 * We always report M_ABORT and M_ERROR_TERM
1059 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1060 !bit_is_set(type, msgs->send_msg)) {
1061 return; /* no destination */
1065 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1068 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1071 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Fatal error: "), my_name, job);
1073 set_jcr_job_status(jcr, JS_FatalError);
1077 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Error: "), my_name, job);
1083 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Warning: "), my_name, job);
1086 len = bsnprintf(rbuf, sizeof(rbuf), _("%s: %s Security violation: "), my_name, job);
1089 len = bsnprintf(rbuf, sizeof(rbuf), "%s: ", my_name);
1093 va_start(arg_ptr, fmt);
1094 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1097 dispatch_message(jcr, type, mtime, rbuf);
1099 if (type == M_ABORT){
1101 p[0] = 0; /* generate segmentation violation */
1103 if (type == M_ERROR_TERM) {
1109 * If we come here, prefix the message with the file:line-number,
1110 * then pass it on to the normal Jmsg routine.
1112 void j_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1117 const char *basename;
1119 if ((basename = strrchr(file, '\\')) == NULL) {
1125 pool_buf = get_pool_memory(PM_EMSG);
1126 i = Mmsg(pool_buf, "%s:%d ", basename, line);
1129 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1130 va_start(arg_ptr, fmt);
1131 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1133 if (len < 0 || len >= (maxlen-5)) {
1134 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1140 Jmsg(jcr, type, mtime, "%s", pool_buf);
1141 free_memory(pool_buf);
1146 * Edit a message into a Pool memory buffer, with file:lineno
1148 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1153 const char *basename;
1155 if ((basename = strrchr(file, '\\')) == NULL) {
1161 i = sprintf(*pool_buf, "%s:%d ", basename, line);
1164 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1165 va_start(arg_ptr, fmt);
1166 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1168 if (len < 0 || len >= (maxlen-5)) {
1169 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1177 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1182 const char *basename;
1184 if ((basename = strrchr(file, '\\')) == NULL) {
1190 i = sprintf(pool_buf, "%s:%d ", basename, line);
1193 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1194 va_start(arg_ptr, fmt);
1195 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1197 if (len < 0 || len >= (maxlen-5)) {
1198 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1208 * Edit a message into a Pool Memory buffer NO file:lineno
1209 * Returns: string length of what was edited.
1211 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1217 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1218 va_start(arg_ptr, fmt);
1219 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1221 if (len < 0 || len >= (maxlen-5)) {
1222 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1230 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1236 maxlen = sizeof_pool_memory(pool_buf) - 1;
1237 va_start(arg_ptr, fmt);
1238 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1240 if (len < 0 || len >= (maxlen-5)) {
1241 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1249 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1255 maxlen = pool_buf.max_size() - 1;
1256 va_start(arg_ptr, fmt);
1257 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1259 if (len < 0 || len >= (maxlen-5)) {
1260 pool_buf.realloc_pm(maxlen + maxlen/2);
1269 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1272 * We queue messages rather than print them directly. This
1273 * is generally used in low level routines (msg handler, bnet)
1274 * to prevent recursion (i.e. if you are in the middle of
1275 * sending a message, it is a bit messy to recursively call
1276 * yourself when the bnet packet is not reentrant).
1278 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1285 pool_buf = get_pool_memory(PM_EMSG);
1288 maxlen = sizeof_pool_memory(pool_buf) - 1;
1289 va_start(arg_ptr, fmt);
1290 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1292 if (len < 0 || len >= (maxlen-5)) {
1293 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1298 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1300 item->mtime = time(NULL);
1301 strcpy(item->msg, pool_buf);
1302 /* If no jcr or dequeuing send to daemon to avoid recursion */
1303 if (!jcr || jcr->dequeuing) {
1304 /* jcr==NULL => daemon message, safe to send now */
1305 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1308 /* Queue message for later sending */
1310 jcr->msg_queue->append(item);
1313 free_memory(pool_buf);
1319 void dequeue_messages(JCR *jcr)
1323 jcr->dequeuing = true;
1324 foreach_dlist(item, jcr->msg_queue) {
1325 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1327 jcr->msg_queue->destroy();
1328 jcr->dequeuing = false;
1334 * If we come here, prefix the message with the file:line-number,
1335 * then pass it on to the normal Qmsg routine.
1337 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1343 pool_buf = get_pool_memory(PM_EMSG);
1344 i = Mmsg(pool_buf, "%s:%d ", file, line);
1347 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1348 va_start(arg_ptr, fmt);
1349 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1351 if (len < 0 || len >= (maxlen-5)) {
1352 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1358 Qmsg(jcr, type, mtime, "%s", pool_buf);
1359 free_memory(pool_buf);