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 */
50 static char *catalog_db = NULL; /* database type */
52 const char *host_os = HOST_OS;
53 const char *distname = DISTNAME;
54 const char *distver = DISTVER;
55 static FILE *trace_fd = NULL;
56 #if defined(HAVE_WIN32)
57 static bool trace = true;
59 static bool trace = false;
62 /* Forward referenced functions */
64 /* Imported functions */
69 /* Used to allow only one thread close the daemon messages at a time */
70 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
71 static MSGS *daemon_msgs; /* global messages */
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.
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.
84 #define BTRACE_EXTRA 20
85 void my_name_is(int argc, char *argv[], const char *name)
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++) {
96 l = p; /* set pos of last slash */
103 #if defined(HAVE_WIN32)
104 /* On Windows allow c: junk */
114 exename = (char *)malloc(len);
120 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
121 for (p=argv[0],q=exepath; p < l; ) {
125 if (strchr(exepath, '.') || exepath[0] != '/') {
126 if (getcwd(cpath, sizeof(cpath))) {
128 exepath = (char *)malloc(strlen(cpath) + 1 + len);
129 strcpy(exepath, cpath);
132 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
139 return catalog_db != NULL ? catalog_db : "unknown";
143 set_db_type(const char *name)
145 if (catalog_db != NULL)
150 catalog_db = bstrdup(name);
154 * Initialize message handler for a daemon or a Job
155 * We make a copy of the MSGS resource passed, so it belows
156 * to the job or daemon and thus can be modified.
158 * NULL for jcr -> initialize global messages for daemon
159 * non-NULL -> initialize jcr using Message resource
162 init_msg(JCR *jcr, MSGS *msg)
164 DEST *d, *dnew, *temp_chain = NULL;
166 if (jcr == NULL && msg == NULL) {
167 init_last_jobs_list();
170 #if !defined(HAVE_WIN32)
172 * Make sure we have fd's 0, 1, 2 open
173 * If we don't do this one of our sockets may open
174 * there and if we then use stdout, it could
175 * send total garbage to our socket.
180 fd = open("/dev/null", O_RDONLY, 0644);
184 for(i=1; fd + i <= 2; i++) {
191 * If msg is NULL, initialize global chain for STDOUT and syslog
194 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
195 memset(daemon_msgs, 0, sizeof(MSGS));
196 #if !defined(HAVE_WIN32)
197 for (i=1; i<=M_MAX; i++) {
198 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
201 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
206 * Walk down the message resource chain duplicating it
207 * for the current Job.
209 for (d=msg->dest_chain; d; d=d->next) {
210 dnew = (DEST *)malloc(sizeof(DEST));
211 memcpy(dnew, d, sizeof(DEST));
212 dnew->next = temp_chain;
214 dnew->mail_filename = NULL;
216 dnew->mail_cmd = bstrdup(d->mail_cmd);
219 dnew->where = bstrdup(d->where);
225 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
226 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
227 jcr->jcr_msgs->dest_chain = temp_chain;
228 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
230 /* If we have default values, release them now */
232 free_msgs_res(daemon_msgs);
234 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
235 memset(daemon_msgs, 0, sizeof(MSGS));
236 daemon_msgs->dest_chain = temp_chain;
237 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
239 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
243 /* Initialize so that the console (User Agent) can
244 * receive messages -- stored in a file.
246 void init_console_msg(const char *wd)
250 bsnprintf(con_fname, sizeof(con_fname), "%s/%s.conmsg", wd, my_name);
251 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
254 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
255 con_fname, be.strerror());
257 if (lseek(fd, 0, SEEK_END) > 0) {
258 console_msg_pending = 1;
261 con_fd = fopen(con_fname, "a+b");
264 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
265 con_fname, be.strerror());
267 if (rwl_init(&con_lock) != 0) {
269 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
275 * Called only during parsing of the config file.
277 * Add a message destination. I.e. associate a message type with
278 * a destination (code).
279 * Note, where in the case of dest_code FILE is a filename,
280 * but in the case of MAIL is a space separated list of
281 * email addresses, ...
283 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
287 * First search the existing chain and see if we
288 * can simply add this msg_type to an existing entry.
290 for (d=msg->dest_chain; d; d=d->next) {
291 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
292 (strcmp(where, d->where) == 0))) {
293 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
294 d, msg_type, dest_code, NPRT(where));
295 set_bit(msg_type, d->msg_types);
296 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
300 /* Not found, create a new entry */
301 d = (DEST *)malloc(sizeof(DEST));
302 memset(d, 0, sizeof(DEST));
303 d->next = msg->dest_chain;
304 d->dest_code = dest_code;
305 set_bit(msg_type, d->msg_types); /* set type bit in structure */
306 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
308 d->where = bstrdup(where);
311 d->mail_cmd = bstrdup(mail_cmd);
313 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
314 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
319 * Called only during parsing of the config file.
321 * Remove a message destination
323 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
327 for (d=msg->dest_chain; d; d=d->next) {
328 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
329 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
330 ((where == NULL && d->where == NULL) ||
331 (strcmp(where, d->where) == 0))) {
332 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
333 d, msg_type, dest_code);
334 clear_bit(msg_type, d->msg_types);
335 Dmsg0(850, "Return rem_msg_dest\n");
343 * Create a unique filename for the mail command
345 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
348 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
349 jcr->Job, (int)(long)d);
351 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
352 my_name, (int)(long)d);
354 Dmsg1(850, "mailname=%s\n", name);
360 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
365 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where);
367 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
371 if (!(bpipe = open_bpipe(cmd, 120, "rw"))) {
373 Jmsg(jcr, M_ERROR, 0, _("open mail pipe %s failed: ERR=%s\n"),
377 /* If we had to use sendmail, add subject */
379 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
386 * Close the messages for this Messages resource, which means to close
387 * any open files, and dispatch any pending email messages.
389 void close_msg(JCR *jcr)
397 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
399 if (jcr == NULL) { /* NULL -> global chain */
401 P(mutex); /* only one thread walking the chain */
403 msgs = jcr->jcr_msgs;
404 jcr->jcr_msgs = NULL;
409 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
410 cmd = get_pool_memory(PM_MESSAGE);
411 for (d=msgs->dest_chain; d; ) {
413 switch (d->dest_code) {
417 fclose(d->fd); /* close open file descriptor */
421 case MD_MAIL_ON_ERROR:
422 Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n");
426 if (d->dest_code == MD_MAIL_ON_ERROR && jcr &&
427 jcr->JobStatus == JS_Terminated) {
431 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
432 Pmsg0(000, _("open mail pipe failed.\n"));
435 Dmsg0(850, "Opened mail pipe\n");
437 line = get_memory(len);
439 while (fgets(line, len, d->fd)) {
440 fputs(line, bpipe->wfd);
442 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
444 Pmsg1(000, _("close error: ERR=%s\n"), be.strerror());
448 * Since we are closing all messages, before "recursing"
449 * make sure we are not closing the daemon messages, otherwise
452 if (msgs != daemon_msgs) {
453 /* read what mail prog returned -- should be nothing */
454 while (fgets(line, len, bpipe->rfd)) {
455 Jmsg1(jcr, M_INFO, 0, _("Mail prog: %s"), line);
459 stat = close_bpipe(bpipe);
460 if (stat != 0 && msgs != daemon_msgs) {
463 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
464 Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
466 "ERR=%s\n"), cmd, be.strerror());
470 /* Remove temp file */
472 unlink(d->mail_filename);
473 free_pool_memory(d->mail_filename);
474 d->mail_filename = NULL;
475 Dmsg0(850, "end mail or mail on error\n");
482 d = d->next; /* point to next buffer */
484 free_pool_memory(cmd);
485 Dmsg0(850, "Done walking message chain.\n");
492 Dmsg0(850, "===End close msg resource\n");
496 * Free memory associated with Messages resource
498 void free_msgs_res(MSGS *msgs)
502 /* Walk down the message chain releasing allocated buffers */
503 for (d=msgs->dest_chain; d; ) {
510 old = d; /* save pointer to release */
511 d = d->next; /* point to next buffer */
512 free(old); /* free the destination item */
514 msgs->dest_chain = NULL;
515 free(msgs); /* free the head */
520 * Terminate the message handler for good.
521 * Release the global destination chain.
523 * Also, clean up a few other items (cons, exepath). Note,
524 * these really should be done elsewhere.
528 Dmsg0(850, "Enter term_msg\n");
529 close_msg(NULL); /* close global chain */
530 free_msgs_res(daemon_msgs); /* free the resources */
549 term_last_jobs_list();
555 * Handle sending the message to the appropriate place
557 void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg)
560 char dt[MAX_TIME_LENGTH];
566 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
569 * Most messages are prefixed by a date and time. If mtime is
570 * zero, then we use the current time. If mtime is 1 (special
571 * kludge), we do not prefix the date and time. Otherwise,
572 * we assume mtime is a time_t and use it.
581 bstrftime_ny(dt, sizeof(dt), mtime);
587 if (type == M_ABORT || type == M_ERROR_TERM) {
588 #if !defined(HAVE_WIN32)
590 fputs(msg, stdout); /* print this here to INSURE that it is printed */
595 /* Now figure out where to send the message */
598 msgs = jcr->jcr_msgs;
603 for (d=msgs->dest_chain; d; d=d->next) {
604 if (bit_is_set(type, d->msg_types)) {
605 switch (d->dest_code) {
608 if (!jcr || !jcr->db) {
612 POOL_MEM cmd(PM_MESSAGE);
613 bstrftimes(dt, sizeof(dt), mtime);
614 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
615 edit_int64(jcr->JobId, ed1), dt, msg);
616 p_sql_query(jcr, cmd.c_str());
620 Dmsg1(850, "CONSOLE for following msg: %s", msg);
622 con_fd = fopen(con_fname, "a+b");
623 Dmsg0(850, "Console file not open.\n");
626 Pw(con_lock); /* get write lock on console message file */
629 (void)fwrite(dt, dtlen, 1, con_fd);
633 (void)fwrite(msg, len, 1, con_fd);
634 if (msg[len-1] != '\n') {
635 (void)fwrite("\n", 2, 1, con_fd);
638 (void)fwrite("\n", 2, 1, con_fd);
641 console_msg_pending = TRUE;
646 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
648 * We really should do an openlog() here.
650 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
653 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
654 mcmd = get_pool_memory(PM_MESSAGE);
655 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
657 fputs(dt, bpipe->wfd);
658 fputs(msg, bpipe->wfd);
659 /* Messages to the operator go one at a time */
660 stat = close_bpipe(bpipe);
664 Qmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
666 "ERR=%s\n"), mcmd, be.strerror());
669 free_pool_memory(mcmd);
672 case MD_MAIL_ON_ERROR:
673 Dmsg1(850, "MAIL for following msg: %s", msg);
675 POOLMEM *name = get_pool_memory(PM_MESSAGE);
676 make_unique_mail_filename(jcr, name, d);
677 d->fd = fopen(name, "w+b");
681 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), name,
684 free_pool_memory(name);
687 d->mail_filename = name;
690 len = strlen(msg) + dtlen;;
691 if (len > d->max_len) {
692 d->max_len = len; /* keep max line length */
697 Dmsg1(850, "FILE for following msg: %s", msg);
699 d->fd = fopen(d->where, "w+b");
703 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
713 Dmsg1(850, "APPEND for following msg: %s", msg);
715 d->fd = fopen(d->where, "ab");
719 Qmsg2(jcr, M_ERROR, 0, _("fopen %s failed: ERR=%s\n"), d->where,
729 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
730 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
731 bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s",
732 jcr->Job, type, mtime, msg);
736 Dmsg1(850, "STDOUT for following msg: %s", msg);
737 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
743 Dmsg1(850, "STDERR for following msg: %s", msg);
754 /*********************************************************************
756 * This subroutine returns the filename portion of a Windows
757 * path. It is used because Microsoft Visual Studio sets __FILE__
762 get_basename(const char *pathname)
764 #if defined(_MSC_VER)
765 const char *basename;
767 if ((basename = strrchr(pathname, '\\')) == NULL) {
779 /*********************************************************************
781 * This subroutine prints a debug message 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
786 * If the level is negative, the details of file and line number
790 d_msg(const char *file, int line, int level, const char *fmt,...)
802 if (level <= debug_level) {
805 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
812 va_start(arg_ptr, fmt);
813 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
817 * Used the "trace on" command in the console to turn on
818 * output to the trace file. "trace off" will close the file.
823 bsnprintf(fn, sizeof(fn), "%s/bacula.trace", working_directory ? working_directory : ".");
824 trace_fd = fopen(fn, "a+b");
827 fputs(buf, trace_fd);
830 /* Some problem, turn off tracing */
833 } else { /* not tracing */
840 * Set trace flag on/off. If argument is negative, there is no change
842 void set_trace(int trace_flag)
844 if (trace_flag < 0) {
846 } else if (trace_flag > 0) {
851 if (!trace && trace_fd) {
852 FILE *ltrace_fd = trace_fd;
854 bmicrosleep(0, 100000); /* yield to prevent seg faults */
864 /*********************************************************************
866 * This subroutine prints a message regardless of the debug level
868 * If the level is negative, the details of file and line number
872 p_msg(const char *file, int line, int level, const char *fmt,...)
880 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
887 va_start(arg_ptr, fmt);
888 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
894 /*********************************************************************
896 * subroutine writes a debug message to the trace file if the level number
897 * is less than or equal the debug_level. File and line numbers
898 * are included for more detail if desired, but not currently
901 * If the level is negative, the details of file and line number
905 t_msg(const char *file, int line, int level, const char *fmt,...)
917 if (level <= debug_level) {
919 bsnprintf(buf, sizeof(buf), "%s/bacula.trace", working_directory);
920 trace_fd = fopen(buf, "a+b");
925 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
932 va_start(arg_ptr, fmt);
933 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
935 if (trace_fd != NULL) {
936 fputs(buf, trace_fd);
944 /* *********************************************************
946 * print an error message
950 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
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, get_basename(file), line);
970 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
971 my_name, get_basename(file), 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, get_basename(file), 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, get_basename(file), 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,...)
1118 pool_buf = get_pool_memory(PM_EMSG);
1119 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1122 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1123 va_start(arg_ptr, fmt);
1124 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1126 if (len < 0 || len >= (maxlen-5)) {
1127 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1133 Jmsg(jcr, type, mtime, "%s", pool_buf);
1134 free_memory(pool_buf);
1139 * Edit a message into a Pool memory buffer, with file:lineno
1141 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1146 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1149 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1150 va_start(arg_ptr, fmt);
1151 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1153 if (len < 0 || len >= (maxlen-5)) {
1154 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1162 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1167 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1170 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1171 va_start(arg_ptr, fmt);
1172 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1174 if (len < 0 || len >= (maxlen-5)) {
1175 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1185 * Edit a message into a Pool Memory buffer NO file:lineno
1186 * Returns: string length of what was edited.
1188 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1194 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1195 va_start(arg_ptr, fmt);
1196 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1198 if (len < 0 || len >= (maxlen-5)) {
1199 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1207 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1213 maxlen = sizeof_pool_memory(pool_buf) - 1;
1214 va_start(arg_ptr, fmt);
1215 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1217 if (len < 0 || len >= (maxlen-5)) {
1218 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1226 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1232 maxlen = pool_buf.max_size() - 1;
1233 va_start(arg_ptr, fmt);
1234 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1236 if (len < 0 || len >= (maxlen-5)) {
1237 pool_buf.realloc_pm(maxlen + maxlen/2);
1246 static pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
1249 * We queue messages rather than print them directly. This
1250 * is generally used in low level routines (msg handler, bnet)
1251 * to prevent recursion (i.e. if you are in the middle of
1252 * sending a message, it is a bit messy to recursively call
1253 * yourself when the bnet packet is not reentrant).
1255 void Qmsg(JCR *jcr, int type, time_t mtime, const char *fmt,...)
1262 pool_buf = get_pool_memory(PM_EMSG);
1265 maxlen = sizeof_pool_memory(pool_buf) - 1;
1266 va_start(arg_ptr, fmt);
1267 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1269 if (len < 0 || len >= (maxlen-5)) {
1270 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1275 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1277 item->mtime = time(NULL);
1278 strcpy(item->msg, pool_buf);
1279 /* If no jcr or dequeuing send to daemon to avoid recursion */
1280 if (!jcr || jcr->dequeuing) {
1281 /* jcr==NULL => daemon message, safe to send now */
1282 Jmsg(NULL, item->type, item->mtime, "%s", item->msg);
1285 /* Queue message for later sending */
1287 jcr->msg_queue->append(item);
1290 free_memory(pool_buf);
1296 void dequeue_messages(JCR *jcr)
1300 if (!jcr->msg_queue) {
1303 jcr->dequeuing = true;
1304 foreach_dlist(item, jcr->msg_queue) {
1305 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1307 jcr->msg_queue->destroy();
1308 jcr->dequeuing = false;
1316 * If we come here, prefix the message with the file:line-number,
1317 * then pass it on to the normal Qmsg routine.
1319 void q_msg(const char *file, int line, JCR *jcr, int type, time_t mtime, const char *fmt,...)
1325 pool_buf = get_pool_memory(PM_EMSG);
1326 i = Mmsg(pool_buf, "%s:%d ", file, line);
1329 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1330 va_start(arg_ptr, fmt);
1331 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1333 if (len < 0 || len >= (maxlen-5)) {
1334 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1340 Qmsg(jcr, type, mtime, "%s", pool_buf);
1341 free_memory(pool_buf);