2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 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 const char *working_directory = NULL; /* working directory path stored here */
44 const char *assert_msg = NULL; /* ASSERT2 error message */
45 const char *version = VERSION " (" BDATE ")";
46 const char *dist_name = DISTNAME " " DISTVER;
47 char *exepath = (char *)NULL;
48 char *exename = (char *)NULL;
49 char db_engine_name[50] = {0}; /* Database engine name or type */
50 char con_fname[500]; /* Console filename */
51 char my_name[MAX_NAME_LENGTH] = {0}; /* daemon name is stored here */
52 char host_name[50] = {0}; /* host machine name */
53 char fail_time[30] = {0}; /* Time of failure */
54 int verbose = 0; /* increase User messages */
55 int64_t debug_level = 0; /* debug level */
56 int64_t debug_level_tags = 0; /* debug tags */
57 int32_t debug_flags = 0; /* debug flags */
58 int console_msg_pending = false;
59 utime_t daemon_start_time = 0; /* Daemon start time */
60 FILE *con_fd = NULL; /* Console file descriptor */
61 brwlock_t con_lock; /* Console lock structure */
62 bool dbg_timestamp = false; /* print timestamp in debug output */
63 bool dbg_thread = false; /* add thread_id to details */
64 bool prt_kaboom = false; /* Print kaboom output */
65 job_code_callback_t message_job_code_callback = NULL; /* Job code callback. Only used by director. */
67 /* Forward referenced functions */
69 /* Imported functions */
70 void create_jcr_key();
74 /* Exclude spaces but require .mail at end */
75 #define MAIL_REGEX "^[^ ]+\\.mail$"
77 /* Allow only one thread to tweak d->fd at a time */
78 static pthread_mutex_t fides_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static MSGS *daemon_msgs; /* global messages */
80 static void (*message_callback)(int type, char *msg) = NULL;
81 static FILE *trace_fd = NULL;
82 #if defined(HAVE_WIN32)
83 static bool trace = true;
85 static bool trace = false;
87 static int hangup = 0;
88 static int blowup = 0;
91 const char *host_os = HOST_OS;
92 const char *distname = DISTNAME;
93 const char *distver = DISTVER;
96 * Walk back in a string from end looking for a
98 * This routine is passed the start of the string and
99 * the end of the string, it returns either the beginning
100 * of the string or where it found a path separator.
102 static const char *bstrrpath(const char *start, const char *end)
104 while ( end > start ) {
106 if (IsPathSeparator(*end)) {
113 /* Some message class methods */
125 * Wait for not in use variable to be clear
127 void MSGS::wait_not_in_use() /* leaves fides_mutex set */
130 while (m_in_use || m_closing) {
132 bmicrosleep(0, 200); /* wait */
138 * Handle message delivery errors
140 static void delivery_error(const char *fmt,...)
145 char dt[MAX_TIME_LENGTH];
148 pool_buf = get_pool_memory(PM_EMSG);
150 bstrftime_ny(dt, sizeof(dt), time(NULL));
155 i = Mmsg(pool_buf, "%s Message delivery ERROR: ", dt);
158 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
159 va_start(arg_ptr, fmt);
160 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
162 if (len < 0 || len >= (maxlen-5)) {
163 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
169 fputs(pool_buf, stdout); /* print this here to INSURE that it is printed */
171 syslog(LOG_DAEMON|LOG_ERR, "%s", pool_buf);
172 free_memory(pool_buf);
175 void set_debug_flags(char *options)
177 for (char *p = options; *p ; p++) {
179 case '0': /* clear flags */
183 case 'i': /* used by FD */
184 case 'd': /* used by FD */
188 dbg_timestamp = true;
192 dbg_timestamp = false;
204 /* truncate the trace file */
205 if (trace && trace_fd) {
206 ftruncate(fileno(trace_fd), 0);
211 /* Turn on/off add_events for P()/V() */
212 debug_flags |= DEBUG_MUTEX_EVENT;
216 /* Display event stack during lockdump */
217 debug_flags |= DEBUG_PRINT_EVENT;
221 Dmsg1(000, "Unknown debug flag %c\n", *p);
226 void register_message_callback(void msg_callback(int type, char *msg))
228 message_callback = msg_callback;
233 * Set daemon name. Also, find canonical execution
234 * path. Note, exepath has spare room for tacking on
235 * the exename so that we can reconstruct the full name.
237 * Note, this routine can get called multiple times
238 * The second time is to put the name as found in the
239 * Resource record. On the second call, generally,
240 * argv is NULL to avoid doing the path code twice.
242 void my_name_is(int argc, char *argv[], const char *name)
248 if (gethostname(host_name, sizeof(host_name)) != 0) {
249 bstrncpy(host_name, "Hostname unknown", sizeof(host_name));
251 bstrncpy(my_name, name, sizeof(my_name));
252 if (argc>0 && argv && argv[0]) {
253 /* strip trailing filename and save exepath */
254 for (l=p=argv[0]; *p; p++) {
255 if (IsPathSeparator(*p)) {
256 l = p; /* set pos of last slash */
259 if (IsPathSeparator(*l)) {
263 #if defined(HAVE_WIN32)
264 /* On Windows allow c: drive specification */
274 exename = (char *)malloc(len);
280 exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
281 for (p=argv[0],q=exepath; p < l; ) {
285 if (strchr(exepath, '.') || !IsPathSeparator(exepath[0])) {
286 if (getcwd(cpath, sizeof(cpath))) {
288 exepath = (char *)malloc(strlen(cpath) + 1 + len);
289 strcpy(exepath, cpath);
292 Dmsg2(500, "exepath=%s\nexename=%s\n", exepath, exename);
296 /* Set special ASSERT2 message where debugger can find it */
298 set_assert_msg(const char *file, int line, const char *msg)
301 bsnprintf(buf, sizeof(buf), "ASSERT at %s:%d-%u ERR=%s",
302 get_basename(file), line, get_jobid_from_tsd(), msg);
303 assert_msg = bstrdup(buf);
306 void set_db_engine_name(const char *name)
308 bstrncpy(db_engine_name, name, sizeof(db_engine_name)-1);
312 * Initialize message handler for a daemon or a Job
313 * We make a copy of the MSGS resource passed, so it belows
314 * to the job or daemon and thus can be modified.
316 * NULL for jcr -> initialize global messages for daemon
317 * non-NULL -> initialize jcr using Message resource
320 init_msg(JCR *jcr, MSGS *msg, job_code_callback_t job_code_callback)
322 DEST *d, *dnew, *temp_chain = NULL;
325 if (jcr == NULL && msg == NULL) {
326 init_last_jobs_list();
327 /* Create a daemon key then set invalid jcr */
328 /* Maybe we should give the daemon a jcr??? */
330 set_jcr_in_tsd(INVALID_JCR);
333 message_job_code_callback = job_code_callback;
335 #if !defined(HAVE_WIN32)
337 * Make sure we have fd's 0, 1, 2 open
338 * If we don't do this one of our sockets may open
339 * there and if we then use stdout, it could
340 * send total garbage to our socket.
344 fd = open("/dev/null", O_RDONLY, 0644);
348 for(i=1; fd + i <= 2; i++) {
355 * If msg is NULL, initialize global chain for STDOUT and syslog
358 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
359 memset(daemon_msgs, 0, sizeof(MSGS));
360 for (i=1; i<=M_MAX; i++) {
361 add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL);
363 Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs);
368 * Walk down the message resource chain duplicating it
369 * for the current Job.
371 for (d=msg->dest_chain; d; d=d->next) {
372 dnew = (DEST *)malloc(sizeof(DEST));
373 memcpy(dnew, d, sizeof(DEST));
374 dnew->next = temp_chain;
376 dnew->mail_filename = NULL;
378 dnew->mail_cmd = bstrdup(d->mail_cmd);
381 dnew->where = bstrdup(d->where);
387 jcr->jcr_msgs = (MSGS *)malloc(sizeof(MSGS));
388 memset(jcr->jcr_msgs, 0, sizeof(MSGS));
389 jcr->jcr_msgs->dest_chain = temp_chain;
390 memcpy(jcr->jcr_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
392 /* If we have default values, release them now */
394 free_msgs_res(daemon_msgs);
396 daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
397 memset(daemon_msgs, 0, sizeof(MSGS));
398 daemon_msgs->dest_chain = temp_chain;
399 memcpy(daemon_msgs->send_msg, msg->send_msg, sizeof(msg->send_msg));
402 Dmsg2(250, "Copy message resource %p to %p\n", msg, temp_chain);
405 /* Initialize so that the console (User Agent) can
406 * receive messages -- stored in a file.
408 void init_console_msg(const char *wd)
412 bsnprintf(con_fname, sizeof(con_fname), "%s%c%s.conmsg", wd, PathSeparator, my_name);
413 fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
416 Emsg2(M_ERROR_TERM, 0, _("Could not open console message file %s: ERR=%s\n"),
417 con_fname, be.bstrerror());
419 if (lseek(fd, 0, SEEK_END) > 0) {
420 console_msg_pending = 1;
423 con_fd = fopen(con_fname, "a+b");
426 Emsg2(M_ERROR, 0, _("Could not open console message file %s: ERR=%s\n"),
427 con_fname, be.bstrerror());
429 if (rwl_init(&con_lock) != 0) {
431 Emsg1(M_ERROR_TERM, 0, _("Could not get con mutex: ERR=%s\n"),
437 * Called only during parsing of the config file.
439 * Add a message destination. I.e. associate a message type with
440 * a destination (code).
441 * Note, where in the case of dest_code FILE is a filename,
442 * but in the case of MAIL is a space separated list of
443 * email addresses, ...
445 void add_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where, char *mail_cmd)
449 * First search the existing chain and see if we
450 * can simply add this msg_type to an existing entry.
452 for (d=msg->dest_chain; d; d=d->next) {
453 if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
454 (strcmp(where, d->where) == 0))) {
455 Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n",
456 d, msg_type, dest_code, NPRT(where));
457 set_bit(msg_type, d->msg_types);
458 set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */
462 /* Not found, create a new entry */
463 d = (DEST *)malloc(sizeof(DEST));
464 memset(d, 0, sizeof(DEST));
465 d->next = msg->dest_chain;
466 d->dest_code = dest_code;
467 set_bit(msg_type, d->msg_types); /* set type bit in structure */
468 set_bit(msg_type, msg->send_msg); /* set type bit in our local */
470 d->where = bstrdup(where);
473 d->mail_cmd = bstrdup(mail_cmd);
475 Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n",
476 d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd));
481 * Called only during parsing of the config file.
483 * Remove a message destination
485 void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where)
489 for (d=msg->dest_chain; d; d=d->next) {
490 Dmsg2(850, "Remove_msg_dest d=%p where=%s\n", d, NPRT(d->where));
491 if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
492 ((where == NULL && d->where == NULL) ||
493 (strcmp(where, d->where) == 0))) {
494 Dmsg3(850, "Found for remove d=%p msgtype=%d destcode=%d\n",
495 d, msg_type, dest_code);
496 clear_bit(msg_type, d->msg_types);
497 Dmsg0(850, "Return rem_msg_dest\n");
505 * Create a unique filename for the mail command
507 static void make_unique_mail_filename(JCR *jcr, POOLMEM *&name, DEST *d)
510 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
511 jcr->Job, (int)(intptr_t)d);
513 Mmsg(name, "%s/%s.%s.%d.mail", working_directory, my_name,
514 my_name, (int)(intptr_t)d);
516 Dmsg1(850, "mailname=%s\n", name);
522 static BPIPE *open_mail_pipe(JCR *jcr, POOLMEM *&cmd, DEST *d)
527 cmd = edit_job_codes(jcr, cmd, d->mail_cmd, d->where, message_job_code_callback);
529 Mmsg(cmd, "/usr/lib/sendmail -F Bacula %s", d->where);
533 if ((bpipe = open_bpipe(cmd, 120, "rw"))) {
534 /* If we had to use sendmail, add subject */
536 fprintf(bpipe->wfd, "Subject: %s\r\n\r\n", _("Bacula Message"));
540 delivery_error(_("open mail pipe %s failed: ERR=%s\n"),
541 cmd, be.bstrerror());
547 * Close the messages for this Messages resource, which means to close
548 * any open files, and dispatch any pending email messages.
550 void close_msg(JCR *jcr)
558 Dmsg1(580, "Close_msg jcr=%p\n", jcr);
560 if (jcr == NULL) { /* NULL -> global chain */
563 msgs = jcr->jcr_msgs;
564 jcr->jcr_msgs = NULL;
570 /* Wait for item to be not in use, then mark closing */
571 if (msgs->is_closing()) {
574 msgs->wait_not_in_use(); /* leaves fides_mutex set */
575 /* Note get_closing() does not lock because we are already locked */
576 if (msgs->get_closing()) {
583 Dmsg1(850, "===Begin close msg resource at %p\n", msgs);
584 cmd = get_pool_memory(PM_MESSAGE);
585 for (d=msgs->dest_chain; d; ) {
588 switch (d->dest_code) {
592 fclose(d->fd); /* close open file descriptor */
597 case MD_MAIL_ON_ERROR:
598 case MD_MAIL_ON_SUCCESS:
599 Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n");
603 success = jcr && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings);
604 if (d->dest_code == MD_MAIL_ON_ERROR && success) {
605 goto rem_temp_file; /* no mail */
606 } else if (d->dest_code == MD_MAIL_ON_SUCCESS && !success) {
607 goto rem_temp_file; /* no mail */
610 if (!(bpipe=open_mail_pipe(jcr, cmd, d))) {
611 Pmsg0(000, _("open mail pipe failed.\n"));
612 goto rem_temp_file; /* error get out */
614 Dmsg0(850, "Opened mail pipe\n");
616 line = get_memory(len);
618 while (fgets(line, len, d->fd)) {
619 fputs(line, bpipe->wfd);
621 if (!close_wpipe(bpipe)) { /* close write pipe sending mail */
623 Pmsg1(000, _("close error: ERR=%s\n"), be.bstrerror());
627 * Since we are closing all messages, before "recursing"
628 * make sure we are not closing the daemon messages, otherwise
631 if (msgs != daemon_msgs) {
632 /* read what mail prog returned -- should be nothing */
633 while (fgets(line, len, bpipe->rfd)) {
634 delivery_error(_("Mail prog: %s"), line);
638 stat = close_bpipe(bpipe);
639 if (stat != 0 && msgs != daemon_msgs) {
642 Dmsg1(850, "Calling emsg. CMD=%s\n", cmd);
643 delivery_error(_("Mail program terminated in error.\n"
645 "ERR=%s\n"), cmd, be.bstrerror());
650 /* Remove temp mail file */
655 /* Exclude spaces in mail_filename */
656 if (d->mail_filename) {
657 safer_unlink(d->mail_filename, MAIL_REGEX);
658 free_pool_memory(d->mail_filename);
659 d->mail_filename = NULL;
661 Dmsg0(850, "end mail or mail on error\n");
668 d = d->next; /* point to next buffer */
670 free_pool_memory(cmd);
671 Dmsg0(850, "Done walking message chain.\n");
676 msgs->clear_closing();
678 Dmsg0(850, "===End close msg resource\n");
682 * Free memory associated with Messages resource
684 void free_msgs_res(MSGS *msgs)
688 /* Walk down the message chain releasing allocated buffers */
689 for (d=msgs->dest_chain; d; ) {
698 old = d; /* save pointer to release */
699 d = d->next; /* point to next buffer */
700 free(old); /* free the destination item */
702 msgs->dest_chain = NULL;
703 free(msgs); /* free the head */
708 * Terminate the message handler for good.
709 * Release the global destination chain.
711 * Also, clean up a few other items (cons, exepath). Note,
712 * these really should be done elsewhere.
716 Dmsg0(850, "Enter term_msg\n");
717 close_msg(NULL); /* close global chain */
718 free_msgs_res(daemon_msgs); /* free the resources */
738 working_directory = NULL;
739 term_last_jobs_list();
742 static bool open_dest_file(JCR *jcr, DEST *d, const char *mode)
744 d->fd = fopen(d->where, mode);
747 delivery_error(_("fopen %s failed: ERR=%s\n"), d->where, be.bstrerror());
753 /* Split the output for syslog (it converts \n to ' ' and is
754 * limited to 1024 characters per syslog message
756 static void send_to_syslog(int mode, const char *msg)
763 while (*p && ((p2 = strchr(p, '\n')) != NULL)) {
764 len = MIN((int)sizeof(buf) - 1, p2 - p + 1); /* Add 1 to keep \n */
765 strncpy(buf, p, len);
767 syslog(mode, "%s", buf);
768 p = p2+1; /* skip \n */
770 if (*p != 0) { /* no \n at the end ? */
771 syslog(mode, "%s", p);
776 * Handle sending the message to the appropriate place
778 void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg)
781 char dt[MAX_TIME_LENGTH];
788 Dmsg2(850, "Enter dispatch_msg type=%d msg=%s", type, msg);
791 * Most messages are prefixed by a date and time. If mtime is
792 * zero, then we use the current time. If mtime is 1 (special
793 * kludge), we do not prefix the date and time. Otherwise,
794 * we assume mtime is a utime_t and use it.
802 mtime = time(NULL); /* get time for SQL log */
804 bstrftime_ny(dt, sizeof(dt), mtime);
810 /* If the program registered a callback, send it there */
811 if (message_callback) {
812 message_callback(type, msg);
816 /* For serious errors make sure message is printed or logged */
817 if (type == M_ABORT || type == M_ERROR_TERM) {
821 if (type == M_ABORT) {
822 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
827 /* Now figure out where to send the message */
830 jcr = get_jcr_from_tsd();
833 msgs = jcr->jcr_msgs;
839 * If closing this message resource, print and send to syslog,
842 if (msgs->is_closing()) {
846 syslog(LOG_DAEMON|LOG_ERR, "%s", msg);
850 for (d=msgs->dest_chain; d; d=d->next) {
851 if (bit_is_set(type, d->msg_types)) {
853 switch (d->dest_code) {
856 if (!jcr || !jcr->db) {
859 if (p_sql_query && p_sql_escape) {
860 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
861 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
863 int len = strlen(msg) + 1;
864 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
865 ok = p_sql_escape(jcr, jcr->db, esc_msg, msg, len);
867 bstrutime(dt, sizeof(dt), mtime);
868 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
869 edit_int64(jcr->JobId, ed1), dt, esc_msg);
870 ok = p_sql_query(jcr, cmd);
873 delivery_error(_("Message delivery error: Unable to store data in database.\n"));
875 free_pool_memory(cmd);
876 free_pool_memory(esc_msg);
880 Dmsg1(850, "CONSOLE for following msg: %s", msg);
882 con_fd = fopen(con_fname, "a+b");
883 Dmsg0(850, "Console file not open.\n");
886 Pw(con_lock); /* get write lock on console message file */
889 (void)fwrite(dt, dtlen, 1, con_fd);
893 (void)fwrite(msg, len, 1, con_fd);
894 if (msg[len-1] != '\n') {
895 (void)fwrite("\n", 2, 1, con_fd);
898 (void)fwrite("\n", 2, 1, con_fd);
901 console_msg_pending = true;
906 Dmsg1(850, "SYSLOG for following msg: %s\n", msg);
908 * We really should do an openlog() here.
910 send_to_syslog(LOG_DAEMON|LOG_ERR, msg);
913 Dmsg1(850, "OPERATOR for following msg: %s\n", msg);
914 mcmd = get_pool_memory(PM_MESSAGE);
915 if ((bpipe=open_mail_pipe(jcr, mcmd, d))) {
917 fputs(dt, bpipe->wfd);
918 fputs(msg, bpipe->wfd);
919 /* Messages to the operator go one at a time */
920 stat = close_bpipe(bpipe);
924 delivery_error(_("Msg delivery error: Operator mail program terminated in error.\n"
926 "ERR=%s\n"), mcmd, be.bstrerror());
929 free_pool_memory(mcmd);
932 case MD_MAIL_ON_ERROR:
933 case MD_MAIL_ON_SUCCESS:
934 Dmsg1(850, "MAIL for following msg: %s", msg);
935 if (msgs->is_closing()) {
940 POOLMEM *name = get_pool_memory(PM_MESSAGE);
941 make_unique_mail_filename(jcr, name, d);
942 d->fd = fopen(name, "w+b");
945 delivery_error(_("Msg delivery error: fopen %s failed: ERR=%s\n"), name,
947 free_pool_memory(name);
948 msgs->clear_in_use();
951 d->mail_filename = name;
954 len = strlen(msg) + dtlen;;
955 if (len > d->max_len) {
956 d->max_len = len; /* keep max line length */
959 msgs->clear_in_use();
962 Dmsg1(850, "APPEND for following msg: %s", msg);
966 Dmsg1(850, "FILE for following msg: %s", msg);
969 if (msgs->is_closing()) {
973 if (!d->fd && !open_dest_file(jcr, d, mode)) {
974 msgs->clear_in_use();
979 /* On error, we close and reopen to handle log rotation */
983 if (open_dest_file(jcr, d, mode)) {
988 msgs->clear_in_use();
991 Dmsg1(850, "DIRECTOR for following msg: %s", msg);
992 if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
993 jcr->dir_bsock->fsend("Jmsg Job=%s type=%d level=%lld %s",
994 jcr->Job, type, mtime, msg);
996 Dmsg1(800, "no jcr for following msg: %s", msg);
1000 Dmsg1(850, "STDOUT for following msg: %s", msg);
1001 if (type != M_ABORT && type != M_ERROR_TERM) { /* already printed */
1008 Dmsg1(850, "STDERR for following msg: %s", msg);
1020 /*********************************************************************
1022 * This subroutine returns the filename portion of a path.
1023 * It is used because some compilers set __FILE__
1024 * to the full path. Try to return base + next higher path.
1027 const char *get_basename(const char *pathname)
1029 const char *basename;
1031 if ((basename = bstrrpath(pathname, pathname+strlen(pathname))) == pathname) {
1033 } else if ((basename = bstrrpath(pathname, basename-1)) == pathname) {
1042 * print or write output to trace file
1044 static void pt_out(char *buf)
1047 * Used the "trace on" command in the console to turn on
1048 * output to the trace file. "trace off" will close the file.
1053 bsnprintf(fn, sizeof(fn), "%s/%s.trace", working_directory ? working_directory : "./", my_name);
1054 trace_fd = fopen(fn, "a+b");
1057 fputs(buf, trace_fd);
1061 /* Some problem, turn off tracing */
1070 /*********************************************************************
1072 * This subroutine prints a debug message if the level number
1073 * is less than or equal the debug_level. File and line numbers
1074 * are included for more detail if desired, but not currently
1077 * If the level is negative, the details of file and line number
1082 vd_msg(const char *file, int line, int64_t level, const char *fmt, va_list arg_ptr)
1085 int len = 0; /* space used in buf */
1086 bool details = true;
1094 if (chk_dbglvl(level)) {
1095 if (dbg_timestamp) {
1097 bstrftimes(buf+len, sizeof(buf)-len, mtime);
1102 #ifdef FULL_LOCATION
1105 len += bsnprintf(buf+len, sizeof(buf)-len, "%s[%lld]: %s:%d-%u ",
1106 my_name, bthread_get_thread_id(),
1107 get_basename(file), line, get_jobid_from_tsd());
1109 len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
1110 my_name, get_basename(file), line, get_jobid_from_tsd());
1114 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1121 d_msg(const char *file, int line, int64_t level, const char *fmt,...)
1124 va_start(arg_ptr, fmt);
1125 vd_msg(file, line, level, fmt, arg_ptr); /* without tags */
1131 * Set trace flag on/off. If argument is negative, there is no change
1133 void set_trace(int trace_flag)
1135 if (trace_flag < 0) {
1137 } else if (trace_flag > 0) {
1142 if (!trace && trace_fd) {
1143 FILE *ltrace_fd = trace_fd;
1145 bmicrosleep(0, 100000); /* yield to prevent seg faults */
1150 void set_hangup(int hangup_value)
1152 if (hangup_value < 0) {
1155 hangup = hangup_value;
1159 int get_hangup(void)
1164 void set_blowup(int blowup_value)
1166 if (blowup_value < 0) {
1169 blowup = blowup_value;
1173 int get_blowup(void)
1179 bool get_trace(void)
1184 /*********************************************************************
1186 * This subroutine prints a message regardless of the debug level
1188 * If the level is negative, the details of file and line number
1192 p_msg(const char *file, int line, int level, const char *fmt,...)
1195 int len = 0; /* space used in buf */
1198 if (dbg_timestamp) {
1199 utime_t mtime = time(NULL);
1200 bstrftimes(buf+len, sizeof(buf)-len, mtime);
1205 #ifdef FULL_LOCATION
1207 len += bsnprintf(buf+len, sizeof(buf)-len, "%s: %s:%d-%u ",
1208 my_name, get_basename(file), line, get_jobid_from_tsd());
1212 va_start(arg_ptr, fmt);
1213 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1220 /*********************************************************************
1222 * subroutine writes a debug message to the trace file if the level number
1223 * is less than or equal the debug_level. File and line numbers
1224 * are included for more detail if desired, but not currently
1227 * If the level is negative, the details of file and line number
1231 t_msg(const char *file, int line, int64_t level, const char *fmt,...)
1238 level = level & ~DT_ALL; /* level should be tag free */
1245 if (level <= debug_level) {
1247 bsnprintf(buf, sizeof(buf), "%s/%s.trace", working_directory ? working_directory : ".", my_name);
1248 trace_fd = fopen(buf, "a+b");
1251 #ifdef FULL_LOCATION
1253 len = bsnprintf(buf, sizeof(buf), "%s: %s:%d ", my_name, get_basename(file), line);
1260 va_start(arg_ptr, fmt);
1261 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1263 if (trace_fd != NULL) {
1264 fputs(buf, trace_fd);
1270 /* *********************************************************
1272 * print an error message
1276 e_msg(const char *file, int line, int type, int level, const char *fmt,...)
1283 * Check if we have a message destination defined.
1284 * We always report M_ABORT and M_ERROR_TERM
1286 if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) &&
1287 !bit_is_set(type, daemon_msgs->send_msg))) {
1288 return; /* no destination */
1292 len = bsnprintf(buf, sizeof(buf), _("%s: ABORTING due to ERROR in %s:%d\n"),
1293 my_name, get_basename(file), line);
1296 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR TERMINATION at %s:%d\n"),
1297 my_name, get_basename(file), line);
1300 if (level == -1) /* skip details */
1301 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error because: "), my_name);
1303 len = bsnprintf(buf, sizeof(buf), _("%s: Fatal Error at %s:%d because:\n"), my_name, get_basename(file), line);
1306 if (level == -1) /* skip details */
1307 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR: "), my_name);
1309 len = bsnprintf(buf, sizeof(buf), _("%s: ERROR in %s:%d "), my_name, get_basename(file), line);
1312 len = bsnprintf(buf, sizeof(buf), _("%s: Warning: "), my_name);
1315 len = bsnprintf(buf, sizeof(buf), _("%s: Security violation: "), my_name);
1318 len = bsnprintf(buf, sizeof(buf), "%s: ", my_name);
1322 va_start(arg_ptr, fmt);
1323 bvsnprintf(buf+len, sizeof(buf)-len, (char *)fmt, arg_ptr);
1327 dispatch_message(NULL, type, 0, buf);
1329 if (type == M_ABORT) {
1330 assert_msg = bstrdup(buf);
1332 p[0] = 0; /* generate segmentation violation */
1334 if (type == M_ERROR_TERM) {
1339 /* *********************************************************
1341 * Generate a Job message
1345 Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1354 Dmsg1(850, "Enter Jmsg type=%d\n", type);
1356 /* Special case for the console, which has a dir_bsock and JobId==0,
1357 * in that case, we send the message directly back to the
1360 if (jcr && jcr->JobId == 0 && jcr->dir_bsock) {
1361 BSOCK *dir = jcr->dir_bsock;
1362 va_start(arg_ptr, fmt);
1363 dir->msglen = bvsnprintf(dir->msg, sizeof_pool_memory(dir->msg),
1366 jcr->dir_bsock->send();
1370 /* The watchdog thread can't use Jmsg directly, we always queued it */
1371 if (is_watchdog()) {
1372 va_start(arg_ptr, fmt);
1373 bvsnprintf(rbuf, sizeof(rbuf), fmt, arg_ptr);
1375 Qmsg(jcr, type, mtime, "%s", rbuf);
1381 jcr = get_jcr_from_tsd();
1384 if (!jcr->dequeuing_msgs) { /* Avoid recursion */
1385 /* Dequeue messages to keep the original order */
1386 dequeue_messages(jcr);
1388 msgs = jcr->jcr_msgs;
1392 msgs = daemon_msgs; /* if no jcr, we use daemon handler */
1396 * Check if we have a message destination defined.
1397 * We always report M_ABORT and M_ERROR_TERM
1399 if (msgs && (type != M_ABORT && type != M_ERROR_TERM) &&
1400 !bit_is_set(type, msgs->send_msg)) {
1401 return; /* no destination */
1405 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ABORTING due to ERROR\n"), my_name);
1408 len = bsnprintf(rbuf, sizeof(rbuf), _("%s ERROR TERMINATION\n"), my_name);
1411 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Fatal error: "), my_name, JobId);
1413 jcr->setJobStatus(JS_FatalError);
1415 if (jcr && jcr->JobErrors == 0) {
1420 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Error: "), my_name, JobId);
1426 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Warning: "), my_name, JobId);
1432 len = bsnprintf(rbuf, sizeof(rbuf), _("%s JobId %u: Security violation: "),
1436 len = bsnprintf(rbuf, sizeof(rbuf), "%s JobId %u: ", my_name, JobId);
1440 va_start(arg_ptr, fmt);
1441 bvsnprintf(rbuf+len, sizeof(rbuf)-len, fmt, arg_ptr);
1444 dispatch_message(jcr, type, mtime, rbuf);
1446 if (type == M_ABORT){
1448 printf("Bacula forced SEG FAULT to obtain traceback.\n");
1449 syslog(LOG_DAEMON|LOG_ERR, "Bacula forced SEG FAULT to obtain traceback.\n");
1450 assert_msg = bstrdup(rbuf);
1451 p[0] = 0; /* generate segmentation violation */
1453 if (type == M_ERROR_TERM) {
1459 * If we come here, prefix the message with the file:line-number,
1460 * then pass it on to the normal Jmsg routine.
1462 void j_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1468 va_start(arg_ptr, fmt);
1469 vd_msg(file, line, 0, fmt, arg_ptr);
1472 pool_buf = get_pool_memory(PM_EMSG);
1473 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1476 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1477 va_start(arg_ptr, fmt);
1478 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1480 if (len < 0 || len >= (maxlen-5)) {
1481 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1487 Jmsg(jcr, type, mtime, "%s", pool_buf);
1488 free_memory(pool_buf);
1493 * Edit a message into a Pool memory buffer, with file:lineno
1495 int m_msg(const char *file, int line, POOLMEM **pool_buf, const char *fmt, ...)
1500 i = sprintf(*pool_buf, "%s:%d ", get_basename(file), line);
1503 maxlen = sizeof_pool_memory(*pool_buf) - i - 1;
1504 va_start(arg_ptr, fmt);
1505 len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
1507 if (len < 0 || len >= (maxlen-5)) {
1508 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
1516 int m_msg(const char *file, int line, POOLMEM *&pool_buf, const char *fmt, ...)
1521 i = sprintf(pool_buf, "%s:%d ", get_basename(file), line);
1524 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1525 va_start(arg_ptr, fmt);
1526 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1528 if (len < 0 || len >= (maxlen-5)) {
1529 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1539 * Edit a message into a Pool Memory buffer NO file:lineno
1540 * Returns: string length of what was edited.
1542 int Mmsg(POOLMEM **pool_buf, const char *fmt, ...)
1548 maxlen = sizeof_pool_memory(*pool_buf) - 1;
1549 va_start(arg_ptr, fmt);
1550 len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
1552 if (len < 0 || len >= (maxlen-5)) {
1553 *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
1561 int Mmsg(POOLMEM *&pool_buf, const char *fmt, ...)
1567 maxlen = sizeof_pool_memory(pool_buf) - 1;
1568 va_start(arg_ptr, fmt);
1569 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1571 if (len < 0 || len >= (maxlen-5)) {
1572 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1580 int Mmsg(POOL_MEM &pool_buf, const char *fmt, ...)
1586 maxlen = pool_buf.max_size() - 1;
1587 va_start(arg_ptr, fmt);
1588 len = bvsnprintf(pool_buf.c_str(), maxlen, fmt, arg_ptr);
1590 if (len < 0 || len >= (maxlen-5)) {
1591 pool_buf.realloc_pm(maxlen + maxlen/2);
1601 * We queue messages rather than print them directly. This
1602 * is generally used in low level routines (msg handler, bnet)
1603 * to prevent recursion (i.e. if you are in the middle of
1604 * sending a message, it is a bit messy to recursively call
1605 * yourself when the bnet packet is not reentrant).
1607 void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1614 pool_buf = get_pool_memory(PM_EMSG);
1617 maxlen = sizeof_pool_memory(pool_buf) - 1;
1618 va_start(arg_ptr, fmt);
1619 len = bvsnprintf(pool_buf, maxlen, fmt, arg_ptr);
1621 if (len < 0 || len >= (maxlen-5)) {
1622 pool_buf = realloc_pool_memory(pool_buf, maxlen + maxlen/2);
1627 item = (MQUEUE_ITEM *)malloc(sizeof(MQUEUE_ITEM) + strlen(pool_buf) + 1);
1629 item->mtime = time(NULL);
1630 strcpy(item->msg, pool_buf);
1632 jcr = get_jcr_from_tsd();
1635 if (jcr && type==M_FATAL) {
1636 // TODO ASX MUST use a lock to protect access jcr->JobStatus from another thread
1637 jcr->setJobStatus(JS_FatalError);
1640 /* If no jcr or no queue or dequeuing send to syslog */
1641 if (!jcr || !jcr->msg_queue || jcr->dequeuing_msgs) {
1642 syslog(LOG_DAEMON|LOG_ERR, "%s", item->msg);
1645 /* Queue message for later sending */
1646 P(jcr->msg_queue_mutex);
1647 jcr->msg_queue->append(item);
1648 V(jcr->msg_queue_mutex);
1650 free_memory(pool_buf);
1656 void dequeue_messages(JCR *jcr)
1659 if (!jcr->msg_queue) {
1662 P(jcr->msg_queue_mutex);
1663 jcr->dequeuing_msgs = true;
1664 foreach_dlist(item, jcr->msg_queue) {
1665 Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
1667 /* Remove messages just sent */
1668 jcr->msg_queue->destroy();
1669 jcr->dequeuing_msgs = false;
1670 V(jcr->msg_queue_mutex);
1675 * If we come here, prefix the message with the file:line-number,
1676 * then pass it on to the normal Qmsg routine.
1678 void q_msg(const char *file, int line, JCR *jcr, int type, utime_t mtime, const char *fmt,...)
1684 pool_buf = get_pool_memory(PM_EMSG);
1685 i = Mmsg(pool_buf, "%s:%d ", get_basename(file), line);
1688 maxlen = sizeof_pool_memory(pool_buf) - i - 1;
1689 va_start(arg_ptr, fmt);
1690 len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
1692 if (len < 0 || len >= (maxlen-5)) {
1693 pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
1699 Qmsg(jcr, type, mtime, "%s", pool_buf);
1700 free_memory(pool_buf);
1704 /* not all in alphabetical order. New commands are added after existing commands with similar letters
1705 to prevent breakage of existing user scripts. */
1707 const char *tag; /* command */
1708 int64_t bit; /* bit to set */
1709 const char *help; /* main purpose */
1712 /* setdebug tag=all,-plugin */
1713 static struct debugtags debug_tags[] = {
1714 { NT_("lock"), DT_LOCK, _("Debug lock information")},
1715 { NT_("network"), DT_NETWORK, _("Debug network information")},
1716 { NT_("plugin"), DT_PLUGIN, _("Debug plugin information")},
1717 { NT_("volume"), DT_VOLUME, _("Debug volume information")},
1718 { NT_("sql"), DT_SQL, _("Debug SQL queries")},
1719 { NT_("bvfs"), DT_BVFS, _("Debug BVFS queries")},
1720 { NT_("memory"), DT_MEMORY, _("Debug memory allocation")},
1721 { NT_("scheduler"), DT_SCHEDULER,_("Debug scheduler information")},
1722 { NT_("protocol"), DT_PROTOCOL, _("Debug protocol information")},
1723 { NT_("snapshot"), DT_SNAPSHOT, _("Debug snapshots")},
1724 { NT_("asx"), DT_ASX, _("ASX personal's debugging")},
1725 { NT_("all"), DT_ALL, _("Debug all information")},
1729 #define MAX_TAG (sizeof(debug_tags) / sizeof(struct debugtags))
1731 const char *debug_get_tag(uint32_t pos, const char **desc)
1733 if (pos < MAX_TAG) {
1735 *desc = debug_tags[pos].help;
1737 return debug_tags[pos].tag;
1743 bool debug_find_tag(const char *tagname, bool add, int64_t *current_level)
1745 Dmsg3(010, "add=%d tag=%s level=%lld\n", add, tagname, *current_level);
1747 /* Nothing in the buffer */
1750 for (int i=0; debug_tags[i].tag ; i++) {
1751 if (strcasecmp(debug_tags[i].tag, tagname) == 0) {
1753 *current_level |= debug_tags[i].bit;
1755 *current_level &= ~(debug_tags[i].bit);
1763 bool debug_parse_tags(const char *options, int64_t *current_level)
1765 bool operation; /* + => true, - false */
1766 char *p, *t, tag[256];
1767 int max = sizeof(tag) - 1;
1769 int64_t level= *current_level;
1773 operation = true; /* add by default */
1776 Dmsg0(100, "No options for tags\n");
1780 for (p = (char *)options; *p ; p++) {
1781 if (*p == ',' || *p == '+' || *p == '-' || *p == '!') {
1782 /* finish tag keyword */
1785 ret &= debug_find_tag(tag, operation, &level);
1797 operation = (*p == '+');
1800 } else if (isalpha(*p) && (t - tag) < max) {
1803 } else { /* not isalpha or too long */
1804 Dmsg1(010, "invalid %c\n", *p);
1809 /* At the end, finish the string and look it */
1811 if (t > tag) { /* something found */
1813 ret &= debug_find_tag(tag, operation, &level);
1816 *current_level = level;
1820 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }