failures.c revision 39454303866b345d010f024e86adbd2f0fa66692
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenconst char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenconst char *failure_log_type_names[LOG_TYPE_COUNT] = {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen "debug", "info", "warning", "error", "fatal", "panic"
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen/* Initialize working defaults */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic failure_callback_t *fatal_handler ATTR_NORETURN =
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic failure_callback_t *error_handler = default_error_handler;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic failure_callback_t *info_handler = default_error_handler;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic failure_callback_t *debug_handler = default_error_handler;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic void (*failure_exit_callback)(int *) = NULL;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic struct failure_context failure_ctx_debug = { .type = LOG_TYPE_DEBUG };
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic struct failure_context failure_ctx_info = { .type = LOG_TYPE_INFO };
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic struct failure_context failure_ctx_warning = { .type = LOG_TYPE_WARNING };
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic struct failure_context failure_ctx_error = { .type = LOG_TYPE_ERROR };
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic char *log_stamp_format = NULL, *log_stamp_format_suffix = NULL;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic bool failure_ignore_errors = FALSE, log_prefix_sent = FALSE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Siraineni_internal_error_handler(const struct failure_context *ctx,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic const char *
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenget_log_stamp_format(const char *format_arg, unsigned int timestamp_usecs)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic const char *get_log_stamp_format(const char *format_arg ATTR_UNUSED,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return t_strdup_printf("%s%06u%s", log_stamp_format,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (failure_exit_callback != NULL && !recursed) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic void log_prefix_add(const struct failure_context *ctx, string_t *str)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen get_log_stamp_format("unused", now.tv_usec), tm) > 0)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic void log_fd_flush_stop(struct ioloop *ioloop)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic int log_fd_write(int fd, const unsigned char *data, size_t len)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen unsigned int prev_signal_term_counter = signal_term_counter;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen unsigned int terminal_eintr_count = 0;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen while ((ret = write(fd, data, len)) != (ssize_t)len) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* some was written, continue.. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* out of disk space? */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* wait until we can write more. this can happen at
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen least when writing to terminal, even if fd is
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen blocking. Internal logging fd is also now
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen non-blocking, so we can show warnings about blocking
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen on a log write. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen title = t_strdup_printf("%s - [blocking on log write]",
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (prev_signal_term_counter == signal_term_counter) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* non-terminal signal. ignore. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen } else if (terminal_eintr_count++ == 0) {
0e94016c18197cb42d00be0085e6da4223a1c84eTimo Sirainen /* we'd rather not die in the middle of
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen writing to log. try again once more */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* received two terminal signals.
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen someone wants us dead. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen prev_signal_term_counter = signal_term_counter;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainendefault_handler(const struct failure_context *ctx, int fd,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen static int recursed = 0;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* we're being called from some signal handler or we ran
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen out of memory */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen str_append(str, failure_log_type_prefixes[ctx->type]);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* make sure there's no %n in there and fix %m */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen str_vprintfa(str, printf_format_fix(format), args);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen ret = log_fd_write(fd, str_data(str), str_len(str));
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainendefault_fatal_finish(enum log_type type, int status)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen static int recursed = 0;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) &&
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (type == LOG_TYPE_PANIC || getenv("CORE_ERROR") != NULL ||
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen (status == FATAL_OUTOFMEM && getenv("CORE_OUTOFMEM") != NULL))
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenvoid default_fatal_handler(const struct failure_context *ctx,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (default_handler(ctx, log_fd, format, args) < 0 &&
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenvoid default_error_handler(const struct failure_context *ctx,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (default_handler(ctx, fd, format, args) < 0) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* we failed to log to info/debug log, try to log the
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen write error to error log - maybe that'll work. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (ctx->type == LOG_TYPE_ERROR && coredump_on_error)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenvoid i_log_type(const struct failure_context *ctx, const char *format, ...)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenvoid i_log_typev(const struct failure_context *ctx, const char *format,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /*va_end(args);*/
i_unreached();
static int recursed = 0;
recursed++;
T_BEGIN {
} T_END;
recursed--;
case LOG_TYPE_DEBUG:
case LOG_TYPE_INFO:
case LOG_TYPE_WARNING:
case LOG_TYPE_ERROR:
case LOG_TYPE_FATAL:
case LOG_TYPE_PANIC:
case LOG_TYPE_COUNT:
case LOG_TYPE_OPTION:
i_unreached();
const char *str;
path);
/* if info/debug logs are elsewhere, i_set_info/debug_file()
const char *str;
void i_unset_failure_prefix(void)
const char *i_get_failure_prefix(void)
static int recursed = 0;
int ret;
recursed++;
T_BEGIN {
} T_END;
ret = 0;
recursed--;
return ret;
bool *replace_prefix_r)
return FALSE;
return FALSE;
log_type--;
return FALSE;
return TRUE;
line++;
void i_set_failure_internal(void)
if (p == NULL)
void failures_deinit(void)