2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula message handling routines
22 * NOTE: don't use any Jmsg or Qmsg calls within this file,
23 * except in q_msg or j_msg (setup routines),
24 * otherwise you may get into recursive calls if there are
25 * errors, and that can lead to looping or deadlocks.
27 * Kern Sibbald, April 2000
34 sql_query_call p_sql_query = NULL;
35 sql_escape_call p_sql_escape = NULL;
37 #define FULL_LOCATION 1 /* set for file:line in Debug messages */
40 * This is where we define "Globals" because all the
41 * daemons include this file.
43 dlist *daemon_msg_queue = NULL;
44 pthread_mutex_t daemon_msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
45 static bool dequeuing_daemon_msgs = false;
46 const char *working_directory = NULL; /* working directory path stored here */
47 const char *assert_msg = NULL; /* ASSERT2 error message */
48 const char *version = VERSION " (" BDATE ")";
49 const char *dist_name = DISTNAME " " DISTVER;
50 char *exepath = (char *)NULL;
51 char *exename = (char *)NULL;
52 char db_engine_name[50] = {0}; /* Database engine name or type */
53 char con_fname[500]; /* Console filename */
54 char my_name[MAX_NAME_LENGTH] = {0}; /* daemon name is stored here */
55 char host_name[50] = {0}; /* host machine name */
56 char fail_time[30] = {0}; /* Time of failure */
57 int verbose = 0; /* increase User messages */
58 int64_t debug_level = 0; /* debug level */
59 int64_t debug_level_tags = 0; /* debug tags */
60 int32_t debug_flags = 0; /* debug flags */
61 bool console_msg_pending = false;
62 utime_t daemon_start_time = 0; /* Daemon start time */
63 FILE *con_fd = NULL; /* Console file descriptor */
64 brwlock_t con_lock; /* Console lock structure */
65 bool dbg_timestamp = false; /* print timestamp in debug output */
66 bool dbg_thread = false; /* add thread_id to details */
67 bool prt_kaboom = false; /* Print kaboom output */
68 job_code_callback_t message_job_code_callback = NULL; /* Job code callback. Only used by director. */
70 /* Forward referenced functions */
72 /* Imported functions */
73 void create_jcr_key();
77 /* Exclude spaces but require .mail at end */
78 #define MAIL_REGEX "^[^ ]+\\.mail$"
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 void (*message_callback)(int type, char *msg) = NULL;
84 static FILE *trace_fd = NULL;
85 #if defined(HAVE_WIN32)
86 static bool trace = true;
88 static bool trace = false;
90 static int hangup = 0;
91 static int blowup = 0;
94 const char *host_os = HOST_OS;
95 const char *distname = DISTNAME;
96 const char *distver = DISTVER;
99 * Walk back in a string from end looking for a
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.
105 static const char *bstrrpath(const char *start, const char *end)
107 while ( end > start ) {
109 if (IsPathSeparator(*end)) {
116 /* Some message class methods */
128 * Wait for not in use variable to be clear
130 void MSGS::wait_not_in_use() /* leaves fides_mutex set */
133 while (m_in_use || m_closing) {
135 bmicrosleep(0, 200); /* wait */
141 * Handle message delivery errors
143 static void delivery_error(const char *fmt,...)
148 char dt[MAX_TIME_LENGTH];
151 pool_buf = get_pool_memory(PM_EMSG);
153 bstrftime_ny(dt, sizeof(dt), time(NULL));
158 i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
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);
165 if (len < 0 || len >= (maxlen-5)) {
166 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
172 fputs(pool_buf, stdout); /* print this here to INSURE that it is printed */
174 syslog(LOG_DAEMON|LOG_ERR, "%s", pool_buf);
175 free_memory(pool_buf);
178 void set_debug_flags(char *options)
180 for (char *p = options; *p ; p++) {
182 case '0': /* clear flags */
186 case 'i': /* used by FD */
187 case 'd': /* used by FD */
191 dbg_timestamp = true;
195 dbg_timestamp = false;
207 /* truncate the trace file */
208 if (trace && trace_fd) {
209 ftruncate(fileno(trace_fd), 0);
214 /* Turn on/off add_events for P()/V() */
215 debug_flags |= DEBUG_MUTEX_EVENT;
219 /* Display event stack during lockdump */
220 debug_flags |= DEBUG_PRINT_EVENT;
224 Dmsg1(000, "Unknown debug flag %c\n", *p);
229 void register_message_callback(void msg_callback(int type, char *msg))
231 message_callback = msg_callback;
236 * Set daemon name. Also, find canonical execution
237 * path. Note, exepath has spare room for tacking on
238 * the exename so that we can reconstruct the full name.
240 * Note, this routine can get called multiple times
241 * The second time is to put the name as found in the
242 * Resource record. On the second call, generally,
243 * argv is NULL to avoid doing the path code twice.
245 void my_name_is(int argc, char *argv[], const char *name)
251 if (gethostname(host_name, sizeof(host_name)) != 0) {
252 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
254 bstrncpy(my_name, name, sizeof(my_name));
255 if (argc>0 && argv && argv[0]) {
256 /* strip trailing filename and save exepath */
257 for (l=p=argv[0]; *p; p++) {
258 if (IsPathSeparator(*p)) {
259 l = p; /* set pos of last slash */
262 if (IsPathSeparator(*l)) {
266 #if defined(HAVE_WIN32)
267 /* On Windows allow c: drive specification */
277 exename = (char *)malloc(len);
283 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
284 for (p=argv[0],q=exepath; p < l; ) {
288 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
289 if (getcwd(cpath, sizeof(cpath))) {
291 exepath = (char *)malloc(strlen(cpath) + 1 + len);
292 strcpy(exepath, cpath);
295 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
299 /* Set special ASSERT2 message where debugger can find it */
301 set_assert_msg(const char *file, int line, const char *msg)
304 bsnprintf(buf, sizeof(buf), "ASSERT at %s:%d-%u ERR=%s",
305 get_basename(file), line, get_jobid_from_tsd(), msg);
306 assert_msg = bstrdup(buf);
309 void set_db_engine_name(const char *name)
311 bstrncpy(db_engine_name, name, sizeof(db_engine_name)-1);
315 * Initialize message handler for a daemon or a Job
316 * We make a copy of the MSGS resource passed, so it belows
317 * to the job or daemon and thus can be modified.
319 * NULL for jcr -> initialize global messages for daemon
320 * non-NULL -> initialize jcr using Message resource
323 init_msg(JCR *jcr, MSGS *msg, job_code_callback_t job_code_callback)
325 DEST *d, *dnew, *temp_chain = NULL;
328 if (jcr == NULL && msg == NULL) {
329 init_last_jobs_list();
330 /* Create a daemon key then set invalid jcr */
331 /* Maybe we should give the daemon a jcr??? */
333 set_jcr_in_tsd(INVALID_JCR);
336 message_job_code_callback = job_code_callback;
338 #if !defined(HAVE_WIN32)
340 * Make sure we have fd's 0, 1, 2 open
341 * If we don't do this one of our sockets may open
342 * there and if we then use stdout, it could
343 * send total garbage to our socket.
347 fd = open("/dev/null", O_RDONLY, 0644);
351 for(i=1; fd + i <= 2; i++) {
358 * If msg is NULL, initialize global chain for STDOUT and syslog
361 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
362 memset(daemon_msgs, 0, sizeof(MSGS));
363 for (i=1; i<=M_MAX; i++) {
364 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
366 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
371 * Walk down the message resource chain duplicating it
372 * for the current Job.
374 for (d=msg->dest_chain; d; d=d->next) {
375 dnew = (DEST *)malloc(sizeof(DEST));
376 memcpy(dnew, d, sizeof(DEST));
377 dnew->next = temp_chain;
379 dnew->mail_filename = NULL;
381 dnew->mail_cmd = bstrdup(d->mail_cmd);
384 dnew->where = bstrdup(d->where);
390 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
391 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
392 jcr->jcr_msgs->dest_chain = temp_chain;
393 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
395 /* If we have default values, release them now */
397 free_msgs_res(daemon_msgs);
399 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
400 memset(daemon_msgs, 0, sizeof(MSGS));
401 daemon_msgs->dest_chain = temp_chain;
402 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
405 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
408 /* Initialize so that the console (User Agent) can
409 * receive messages -- stored in a file.
411 void init_console_msg(const char *wd)
415 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
416 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
419 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
420 con_fname, be.bstrerror());
422 if (lseek(fd, 0, SEEK_END) > 0) {
423 console_msg_pending = true;
426 con_fd = bfopen(con_fname, "a+b");
429 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
430 con_fname, be.bstrerror());
432 if (rwl_init(&con_lock) != 0) {
434 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
440 * Called only during parsing of the config file.
442 * Add a message destination. I.e. associate a message type with
443 * a destination (code).
444 * Note, where in the case of dest_code FILE is a filename,
445 * but in the case of MAIL is a space separated list of
446 * email addresses, ...
448 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
452 * First search the existing chain and see if we
453 * can simply add this msg_type to an existing entry.
455 for (d=msg->dest_chain; d; d=d->next) {
456 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
457 (strcmp(where, d->where) == 0))) {
458 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
459 d, msg_type, dest_code, NPRT(where));
460 set_bit(msg_type, d->msg_types);
461 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
465 /* Not found, create a new entry */
466 d = (DEST *)malloc(sizeof(DEST));
467 memset(d, 0, sizeof(DEST));
468 d->next = msg->dest_chain;
469 d->dest_code = dest_code;
470 set_bit(msg_type, d->msg_types); /* set type bit in structure */
471 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
473 d->where = bstrdup(where);
476 d->mail_cmd = bstrdup(mail_cmd);
478 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
479 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
484 * Called only during parsing of the config file.
486 * Remove a message destination
488 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
492 for (d=msg->dest_chain; d; d=d->next) {
493 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
494 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
495 ((where == NULL && d->where == NULL) ||
496 (strcmp(where, d->where) == 0))) {
497 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
498 d, msg_type, dest_code);
499 clear_bit(msg_type, d->msg_types);
500 Dmsg0(850, "Return rem_msg_dest\n");
508 * Create a unique filename for the mail command
510 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
513 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
514 jcr->Job, (int)(intptr_t)d);
516 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
517 my_name, (int)(intptr_t)d);
519 Dmsg1(850, "mailname=%s\n", name);
525 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
530 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where, message_job_code_callback);
532 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
536 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
537 /* If we had to use sendmail, add subject */
539 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
543 delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
544 cmd, be.bstrerror());
550 * Close the messages for this Messages resource, which means to close
551 * any open files, and dispatch any pending email messages.
553 void close_msg(JCR *jcr)
561 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
563 if (jcr == NULL) { /* NULL -> global chain */
566 msgs = jcr->jcr_msgs;
567 jcr->jcr_msgs = NULL;
573 /* Wait for item to be not in use, then mark closing */
574 if (msgs->is_closing()) {
577 msgs->wait_not_in_use(); /* leaves fides_mutex set */
578 /* Note get_closing() does not lock because we are already locked */
579 if (msgs->get_closing()) {
586 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
587 cmd = get_pool_memory(PM_MESSAGE);
588 for (d=msgs->dest_chain; d; ) {
591 switch (d->dest_code) {
595 fclose(d->fd); /* close open file descriptor */
600 case MD_MAIL_ON_ERROR:
601 case MD_MAIL_ON_SUCCESS:
602 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
606 success = jcr && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings);
608 if (d->dest_code == MD_MAIL_ON_ERROR && success) {
609 goto rem_temp_file; /* no mail */
610 } else if (d->dest_code == MD_MAIL_ON_SUCCESS && !success) {
611 goto rem_temp_file; /* no mail */
614 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
615 Pmsg0(000, _("open mail pipe failed.\n"));
616 goto rem_temp_file; /* error get out */
618 Dmsg0(850, "Opened mail pipe\n");
620 line = get_memory(len);
622 while (fgets(line, len, d->fd)) {
623 fputs(line, bpipe->wfd);
625 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
627 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
631 * Since we are closing all messages, before "recursing"
632 * make sure we are not closing the daemon messages, otherwise
635 if (msgs != daemon_msgs) {
636 /* read what mail prog returned -- should be nothing */
637 while (fgets(line, len, bpipe->rfd)) {
638 delivery_error(_("Mail prog: %s"), line);
642 stat = close_bpipe(bpipe);
643 if (stat != 0 && msgs != daemon_msgs) {
646 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
647 delivery_error(_("Mail program terminated in error.\n"
649 "ERR=%s\n"), cmd, be.bstrerror());
654 /* Remove temp mail file */
659 /* Exclude spaces in mail_filename */
660 if (d->mail_filename) {
661 safer_unlink(d->mail_filename, MAIL_REGEX);
662 free_pool_memory(d->mail_filename);
663 d->mail_filename = NULL;
665 Dmsg0(850, "end mail or mail on error\n");
672 d = d->next; /* point to next buffer */
674 free_pool_memory(cmd);
675 Dmsg0(850, "Done walking message chain.\n");
680 msgs->clear_closing();
682 Dmsg0(850, "===End close msg resource\n");
686 * Free memory associated with Messages resource
688 void free_msgs_res(MSGS *msgs)
692 /* Walk down the message chain releasing allocated buffers */
693 for (d=msgs->dest_chain; d; ) {
702 old = d; /* save pointer to release */
703 d = d->next; /* point to next buffer */
704 free(old); /* free the destination item */
706 msgs->dest_chain = NULL;
707 free(msgs); /* free the head */
712 * Terminate the message handler for good.
713 * Release the global destination chain.
715 * Also, clean up a few other items (cons, exepath). Note,
716 * these really should be done elsewhere.
720 Dmsg0(850, "Enter term_msg\n");
721 close_msg(NULL); /* close global chain */
722 free_msgs_res(daemon_msgs); /* free the resources */
742 working_directory = NULL;
743 term_last_jobs_list();
746 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
748 d->fd = bfopen(d->where, mode);
751 delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
757 /* Split the output for syslog (it converts \n to ' ' and is
758 * limited to 1024 characters per syslog message
760 static void send_to_syslog(int mode, const char *msg)
767 while (*p && ((p2 = strchr(p, '\n')) != NULL)) {
768 len = MIN((int)sizeof(buf) - 1, p2 - p + 1); /* Add 1 to keep \n */
769 strncpy(buf, p, len);
771 syslog(mode, "%s", buf);
772 p = p2+1; /* skip \n */
774 if (*p != 0) { /* no \n at the end ? */
775 syslog(mode, "%s", p);
780 * Handle sending the message to the appropriate place
782 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
785 char dt[MAX_TIME_LENGTH];
791 bool created_jcr = false;
793 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
796 * Most messages are prefixed by a date and time. If mtime is
797 * zero, then we use the current time. If mtime is 1 (special
798 * kludge), we do not prefix the date and time. Otherwise,
799 * we assume mtime is a utime_t and use it.
807 mtime = time(NULL); /* get time for SQL log */
809 bstrftime_ny(dt, sizeof(dt), mtime);
815 /* If the program registered a callback, send it there */
816 if (message_callback) {
817 message_callback(type, msg);
821 /* For serious errors make sure message is printed or logged */
822 if (type == M_ABORT || type == M_ERROR_TERM) {
826 if (type == M_ABORT) {
827 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
832 /* Now figure out where to send the message */
835 jcr = get_jcr_from_tsd();
838 /* Temporary fix for a deadlock in the reload command when
839 * the configuration has a problem. The JCR chain is locked
840 * during the reload, we cannot create a new JCR.
844 jcr = new_jcr(sizeof(JCR), NULL);
850 msgs = jcr->jcr_msgs;
856 * If closing this message resource, print and send to syslog,
859 if (msgs->is_closing()) {
863 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
868 for (d=msgs->dest_chain; d; d=d->next) {
869 if (bit_is_set(type, d->msg_types)) {
871 switch (d->dest_code) {
874 if (!jcr || !jcr->db) {
877 if (p_sql_query && p_sql_escape) {
878 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
879 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
881 int len = strlen(msg) + 1;
882 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
883 ok = p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
885 bstrutime(dt, sizeof(dt), mtime);
886 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
887 edit_int64(jcr->JobId, ed1), dt, esc_msg);
888 ok = p_sql_query(jcr, cmd);
891 delivery_error(_("Message delivery error: Unable to store data in database.\n"));
893 free_pool_memory(cmd);
894 free_pool_memory(esc_msg);
898 Dmsg1(850, "CONSOLE for following msg: %s", msg);
900 con_fd = bfopen(con_fname, "a+b");
901 Dmsg0(850, "Console file not open.\n");
904 Pw(con_lock); /* get write lock on console message file */
907 (void)fwrite(dt, dtlen, 1, con_fd);
911 (void)fwrite(msg, len, 1, con_fd);
912 if (msg[len-1] != '\n') {
913 (void)fwrite("\n", 2, 1, con_fd);
916 (void)fwrite("\n", 2, 1, con_fd);
919 console_msg_pending = true;
924 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
926 * We really should do an openlog() here.
928 send_to_syslog(LOG_DAEMON|LOG_ERR, msg);
931 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
932 mcmd = get_pool_memory(PM_MESSAGE);
933 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
935 fputs(dt, bpipe->wfd);
936 fputs(msg, bpipe->wfd);
937 /* Messages to the operator go one at a time */
938 stat = close_bpipe(bpipe);
942 delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
944 "ERR=%s\n"), mcmd, be.bstrerror());
947 free_pool_memory(mcmd);
950 case MD_MAIL_ON_ERROR:
951 case MD_MAIL_ON_SUCCESS:
952 Dmsg1(850, "MAIL for following msg: %s", msg);
953 if (msgs->is_closing()) {
958 POOLMEM *name = get_pool_memory(PM_MESSAGE);
959 make_unique_mail_filename(jcr, name, d);
960 d->fd = bfopen(name, "w+b");
963 delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
965 free_pool_memory(name);
966 msgs->clear_in_use();
969 d->mail_filename = name;
972 len = strlen(msg) + dtlen;;
973 if (len > d->max_len) {
974 d->max_len = len; /* keep max line length */
977 msgs->clear_in_use();
980 Dmsg1(850, "APPEND for following msg: %s", msg);
984 Dmsg1(850, "FILE for following msg: %s", msg);
987 if (msgs->is_closing()) {
991 if (!d->fd && !open_dest_file(jcr, d, mode)) {
992 msgs->clear_in_use();
997 /* On error, we close and reopen to handle log rotation */
1001 if (open_dest_file(jcr, d, mode)) {
1006 msgs->clear_in_use();
1009 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
1010 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
1011 jcr->dir_bsock->fsend("Jmsg JobId=%ld type=%d level=%lld %s",
1012 jcr->JobId, type, mtime, msg);
1014 Dmsg1(800, "no jcr for following msg: %s", msg);
1018 Dmsg1(850, "STDOUT for following msg: %s", msg);
1019 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
1026 Dmsg1(850, "STDERR for following msg: %s", msg);
1041 /*********************************************************************
1043 * This subroutine returns the filename portion of a path.
1044 * It is used because some compilers set __FILE__
1045 * to the full path. Try to return base + next higher path.
1048 const char *get_basename(const char *pathname)
1050 const char *basename;
1052 if ((basename = bstrrpath(pathname, pathname+strlen(pathname))) == pathname) {
1054 } else if ((basename = bstrrpath(pathname, basename-1)) == pathname) {
1063 * print or write output to trace file
1065 static void pt_out(char *buf)
1068 * Used the "trace on" command in the console to turn on
1069 * output to the trace file. "trace off" will close the file.
1074 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
1075 trace_fd = bfopen(fn, "a+b");
1078 fputs(buf, trace_fd);
1082 /* Some problem, turn off tracing */
1091 /*********************************************************************
1093 * This subroutine prints a debug message if the level number
1094 * is less than or equal the debug_level. File and line numbers
1095 * are included for more detail if desired, but not currently
1098 * If the level is negative, the details of file and line number
1103 vd_msg(const char *file, int line, int64_t level, const char *fmt, va_list arg_ptr)
1106 int len = 0; /* space used in buf */
1107 bool details = true;
1115 if (chk_dbglvl(level)) {
1116 if (dbg_timestamp) {
1118 bstrftimes(buf+len, sizeof(buf)-len, mtime);
1123 #ifdef FULL_LOCATION
1126 len += bsnprintf(buf+len, sizeof(buf)-len, "%s[%lld]: %s:%d-%u ",
1127 my_name, bthread_get_thread_id(),
1128 get_basename(file), line, get_jobid_from_tsd());
1130 len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
1131 my_name, get_basename(file), line, get_jobid_from_tsd());
1135 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1142 d_msg(const char *file, int line, int64_t level, const char *fmt,...)
1145 va_start(arg_ptr, fmt);
1146 vd_msg(file, line, level, fmt, arg_ptr); /* without tags */
1152 * Set trace flag on/off. If argument is negative, there is no change
1154 void set_trace(int trace_flag)
1156 if (trace_flag < 0) {
1158 } else if (trace_flag > 0) {
1163 if (!trace && trace_fd) {
1164 FILE *ltrace_fd = trace_fd;
1166 bmicrosleep(0, 100000); /* yield to prevent seg faults */
1171 void set_hangup(int hangup_value)
1173 if (hangup_value != -1) {
1174 hangup = hangup_value;
1178 int get_hangup(void)
1183 void set_blowup(int blowup_value)
1185 if (blowup_value != -1) {
1186 blowup = blowup_value;
1190 int get_blowup(void)
1195 bool handle_hangup_blowup(JCR *jcr, uint32_t file_count, uint64_t byte_count)
1197 if (hangup == 0 && blowup == 0) {
1201 /* Debug code: check if we must hangup or blowup */
1202 if ((hangup > 0 && (file_count > (uint32_t)hangup)) ||
1203 (hangup < 0 && (byte_count/1024 > (uint32_t)-hangup))) {
1204 jcr->setJobStatus(JS_Incomplete);
1206 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
1208 Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d Kbytes.\n", -hangup);
1213 if ((blowup > 0 && (file_count > (uint32_t)blowup)) ||
1214 (blowup < 0 && (byte_count/1024 > (uint32_t)-blowup))) {
1216 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d files.\n", blowup);
1218 Jmsg1(jcr, M_ABORT, 0, "Debug blowup requested after %d Kbytes.\n", -blowup);
1220 /* will never reach this line */
1226 bool get_trace(void)
1231 /*********************************************************************
1233 * This subroutine prints a message regardless of the debug level
1235 * If the level is negative, the details of file and line number
1239 p_msg(const char *file, int line, int level, const char *fmt,...)
1242 int len = 0; /* space used in buf */
1245 if (dbg_timestamp) {
1246 utime_t mtime = time(NULL);
1247 bstrftimes(buf+len, sizeof(buf)-len, mtime);
1252 #ifdef FULL_LOCATION
1254 len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
1255 my_name, get_basename(file), line, get_jobid_from_tsd());
1259 va_start(arg_ptr, fmt);
1260 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1267 /*********************************************************************
1269 * subroutine writes a debug message to the trace file if the level number
1270 * is less than or equal the debug_level. File and line numbers
1271 * are included for more detail if desired, but not currently
1274 * If the level is negative, the details of file and line number
1278 t_msg(const char *file, int line, int64_t level, const char *fmt,...)
1285 level = level & ~DT_ALL; /* level should be tag free */
1292 if (level <= debug_level) {
1294 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1295 trace_fd = bfopen(buf, "a+b");
1298 #ifdef FULL_LOCATION
1300 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1307 va_start(arg_ptr, fmt);
1308 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1310 if (trace_fd != NULL) {
1311 fputs(buf, trace_fd);
1317 /* *********************************************************
1319 * print an error message
1323 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1330 * Check if we have a message destination defined.
1331 * We always report M_ABORT and M_ERROR_TERM
1333 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1334 !bit_is_set(type, daemon_msgs->send_msg))) {
1335 return; /* no destination */
1339 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1340 my_name, get_basename(file), line);
1343 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1344 my_name, get_basename(file), line);
1347 if (level == -1) /* skip details */
1348 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1350 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1353 if (level == -1) /* skip details */
1354 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1356 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1359 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1362 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1365 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1369 va_start(arg_ptr, fmt);
1370 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1374 dispatch_message(NULL, type, 0, buf);
1376 if (type == M_ABORT) {
1378 p[0] = 0; /* generate segmentation violation */
1380 if (type == M_ERROR_TERM) {
1385 /* Check in the msgs resource if a given type is defined */
1386 bool is_message_type_set(JCR *jcr, int type)
1390 msgs = jcr->jcr_msgs;
1393 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1395 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1396 !bit_is_set(type, msgs->send_msg)) {
1397 return false; /* no destination */
1402 /* *********************************************************
1404 * Generate a Job message
1408 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1417 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1419 /* Special case for the console, which has a dir_bsock and JobId==0,
1420 * in that case, we send the message directly back to the
1423 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1424 BSOCK *dir = jcr->dir_bsock;
1425 va_start(arg_ptr, fmt);
1426 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1429 jcr->dir_bsock->send();
1433 /* The watchdog thread can't use Jmsg directly, we always queued it */
1434 if (is_watchdog()) {
1435 va_start(arg_ptr, fmt);
1436 bvsnprintf(rbuf, sizeof(rbuf), fmt, arg_ptr);
1438 Qmsg(jcr, type, mtime, "%s", rbuf);
1444 jcr = get_jcr_from_tsd();
1447 if (!jcr->dequeuing_msgs) { /* Avoid recursion */
1448 /* Dequeue messages to keep the original order */
1449 dequeue_messages(jcr);
1451 msgs = jcr->jcr_msgs;
1455 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1459 * Check if we have a message destination defined.
1460 * We always report M_ABORT and M_ERROR_TERM
1462 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1463 !bit_is_set(type, msgs->send_msg)) {
1464 return; /* no destination */
1468 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1471 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1474 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1476 jcr->setJobStatus(JS_FatalError);
1478 if (jcr && jcr->JobErrors == 0) {
1483 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1489 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1495 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1499 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1503 va_start(arg_ptr, fmt);
1504 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1507 dispatch_message(jcr, type, mtime, rbuf);
1509 if (type == M_ABORT){
1511 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1512 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1513 p[0] = 0; /* generate segmentation violation */
1515 if (type == M_ERROR_TERM) {
1521 * If we come here, prefix the message with the file:line-number,
1522 * then pass it on to the normal Jmsg routine.
1524 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1530 va_start(arg_ptr, fmt);
1531 vd_msg(file, line, 0, fmt, arg_ptr);
1534 pool_buf = get_pool_memory(PM_EMSG);
1535 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1538 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1539 va_start(arg_ptr, fmt);
1540 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1542 if (len < 0 || len >= (maxlen-5)) {
1543 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1549 Jmsg(jcr, type, mtime, "%s", pool_buf);
1550 free_memory(pool_buf);
1555 * Edit a message into a Pool memory buffer, with file:lineno
1557 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1562 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1565 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1566 va_start(arg_ptr, fmt);
1567 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1569 if (len < 0 || len >= (maxlen-5)) {
1570 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1578 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1583 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1586 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1587 va_start(arg_ptr, fmt);
1588 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1590 if (len < 0 || len >= (maxlen-5)) {
1591 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1601 * Edit a message into a Pool Memory buffer NO file:lineno
1602 * Returns: string length of what was edited.
1604 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1610 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1611 va_start(arg_ptr, fmt);
1612 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1614 if (len < 0 || len >= (maxlen-5)) {
1615 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1623 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1629 maxlen = sizeof_pool_memory(pool_buf) - 1;
1630 va_start(arg_ptr, fmt);
1631 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1633 if (len < 0 || len >= (maxlen-5)) {
1634 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1642 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1648 maxlen = pool_buf.max_size() - 1;
1649 va_start(arg_ptr, fmt);
1650 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1652 if (len < 0 || len >= (maxlen-5)) {
1653 pool_buf.realloc_pm(maxlen + maxlen/2);
1663 * We queue messages rather than print them directly. This
1664 * is generally used in low level routines (msg handler, bnet)
1665 * to prevent recursion (i.e. if you are in the middle of
1666 * sending a message, it is a bit messy to recursively call
1667 * yourself when the bnet packet is not reentrant).
1669 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1676 pool_buf = get_pool_memory(PM_EMSG);
1679 maxlen = sizeof_pool_memory(pool_buf) - 1;
1680 va_start(arg_ptr, fmt);
1681 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1683 if (len < 0 || len >= (maxlen-5)) {
1684 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1689 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1691 item->mtime = time(NULL);
1692 strcpy(item->msg, pool_buf);
1694 jcr = get_jcr_from_tsd();
1697 if (jcr && type==M_FATAL) {
1698 jcr->setJobStatus(JS_FatalError);
1701 /* If no jcr or no queue or dequeuing send to syslog */
1702 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1703 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1704 P(daemon_msg_queue_mutex);
1705 if (daemon_msg_queue) {
1706 daemon_msg_queue->append(item);
1708 V(daemon_msg_queue_mutex);
1710 /* Queue message for later sending */
1711 P(jcr->msg_queue_mutex);
1712 jcr->msg_queue->append(item);
1713 V(jcr->msg_queue_mutex);
1715 free_memory(pool_buf);
1721 void dequeue_messages(JCR *jcr)
1726 /* Avoid bad calls and recursion */
1727 if (!jcr || jcr->dequeuing_msgs) {
1731 /* Dequeue daemon messages */
1732 if (daemon_msg_queue && !dequeuing_daemon_msgs) {
1733 P(daemon_msg_queue_mutex);
1734 dequeuing_daemon_msgs = true;
1735 jcr->dequeuing_msgs = true;
1737 jcr->JobId = 0; /* set daemon JobId == 0 */
1738 if (jcr->dir_bsock) jcr->dir_bsock->suppress_error_messages(true);
1739 foreach_dlist(item, daemon_msg_queue) {
1740 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1742 if (jcr->dir_bsock) jcr->dir_bsock->suppress_error_messages(false);
1743 /* Remove messages just sent */
1744 daemon_msg_queue->destroy();
1745 jcr->JobId = JobId; /* restore JobId */
1746 jcr->dequeuing_msgs = false;
1747 dequeuing_daemon_msgs = false;
1748 V(daemon_msg_queue_mutex);
1751 /* Dequeue Job specific messages */
1752 if (!jcr->msg_queue || jcr->dequeuing_msgs) {
1755 P(jcr->msg_queue_mutex);
1756 jcr->dequeuing_msgs = true;
1757 if (jcr->dir_bsock) jcr->dir_bsock->suppress_error_messages(true);
1758 foreach_dlist(item, jcr->msg_queue) {
1759 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1761 if (jcr->dir_bsock) jcr->dir_bsock->suppress_error_messages(false);
1762 /* Remove messages just sent */
1763 jcr->msg_queue->destroy();
1764 jcr->dequeuing_msgs = false;
1765 V(jcr->msg_queue_mutex);
1770 * If we come here, prefix the message with the file:line-number,
1771 * then pass it on to the normal Qmsg routine.
1773 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1779 pool_buf = get_pool_memory(PM_EMSG);
1780 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1783 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1784 va_start(arg_ptr, fmt);
1785 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1787 if (len < 0 || len >= (maxlen-5)) {
1788 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1794 Qmsg(jcr, type, mtime, "%s", pool_buf);
1795 free_memory(pool_buf);
1799 /* not all in alphabetical order. New commands are added after existing commands with similar letters
1800 to prevent breakage of existing user scripts. */
1802 const char *tag; /* command */
1803 int64_t bit; /* bit to set */
1804 const char *help; /* main purpose */
1807 /* setdebug tag=all,-plugin */
1808 static struct debugtags debug_tags[] = {
1809 { NT_("lock"), DT_LOCK, _("Debug lock information")},
1810 { NT_("network"), DT_NETWORK, _("Debug network information")},
1811 { NT_("plugin"), DT_PLUGIN, _("Debug plugin information")},
1812 { NT_("volume"), DT_VOLUME, _("Debug volume information")},
1813 { NT_("sql"), DT_SQL, _("Debug SQL queries")},
1814 { NT_("bvfs"), DT_BVFS, _("Debug BVFS queries")},
1815 { NT_("memory"), DT_MEMORY, _("Debug memory allocation")},
1816 { NT_("scheduler"), DT_SCHEDULER,_("Debug scheduler information")},
1817 { NT_("protocol"), DT_PROTOCOL, _("Debug protocol information")},
1818 { NT_("snapshot"), DT_SNAPSHOT, _("Debug snapshots")},
1819 { NT_("asx"), DT_ASX, _("ASX personal's debugging")},
1820 { NT_("all"), DT_ALL, _("Debug all information")},
1824 #define MAX_TAG (sizeof(debug_tags) / sizeof(struct debugtags))
1826 const char *debug_get_tag(uint32_t pos, const char **desc)
1828 if (pos < MAX_TAG) {
1830 *desc = debug_tags[pos].help;
1832 return debug_tags[pos].tag;
1838 bool debug_find_tag(const char *tagname, bool add, int64_t *current_level)
1840 Dmsg3(010, "add=%d tag=%s level=%lld\n", add, tagname, *current_level);
1842 /* Nothing in the buffer */
1845 for (int i=0; debug_tags[i].tag ; i++) {
1846 if (strcasecmp(debug_tags[i].tag, tagname) == 0) {
1848 *current_level |= debug_tags[i].bit;
1850 *current_level &= ~(debug_tags[i].bit);
1858 bool debug_parse_tags(const char *options, int64_t *current_level)
1860 bool operation; /* + => true, - false */
1861 char *p, *t, tag[256];
1862 int max = sizeof(tag) - 1;
1864 int64_t level= *current_level;
1868 operation = true; /* add by default */
1871 Dmsg0(100, "No options for tags\n");
1875 for (p = (char *)options; *p ; p++) {
1876 if (*p == ',' || *p == '+' || *p == '-' || *p == '!') {
1877 /* finish tag keyword */
1880 ret &= debug_find_tag(tag, operation, &level);
1892 operation = (*p == '+');
1895 } else if (isalpha(*p) && (t - tag) < max) {
1898 } else { /* not isalpha or too long */
1899 Dmsg1(010, "invalid %c\n", *p);
1904 /* At the end, finish the string and look it */
1906 if (t > tag) { /* something found */
1908 ret &= debug_find_tag(tag, operation, &level);
1911 *current_level = level;
1915 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
1917 void setup_daemon_message_queue()
1919 static MQUEUE_ITEM *item = NULL;
1920 daemon_msg_queue = New(dlist(item, &item->link));
1923 void free_daemon_message_queue()
1925 P(daemon_msg_queue_mutex);
1926 daemon_msg_queue->destroy();
1927 free(daemon_msg_queue);
1928 V(daemon_msg_queue_mutex);