};
/* Initialize working defaults */
-static fatal_failure_callback_t *fatal_handler ATTR_NORETURN =
+static failure_callback_t *fatal_handler ATTR_NORETURN =
default_fatal_handler;
static failure_callback_t *error_handler = default_error_handler;
static failure_callback_t *info_handler = default_error_handler;
static failure_callback_t *debug_handler = default_error_handler;
static void (*failure_exit_callback)(int *) = NULL;
+static struct failure_context failure_ctx_debug = { .type = LOG_TYPE_DEBUG };
+static struct failure_context failure_ctx_info = { .type = LOG_TYPE_INFO };
+static struct failure_context failure_ctx_warning = { .type = LOG_TYPE_WARNING };
+static struct failure_context failure_ctx_error = { .type = LOG_TYPE_ERROR };
+
static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
log_debug_fd = STDERR_FILENO;
static char *log_prefix = NULL, *log_stamp_format = NULL;
static bool failure_ignore_errors = FALSE;
static void ATTR_FORMAT(2, 0)
-i_internal_error_handler(enum log_type type, const char *fmt, va_list args);
+i_internal_error_handler(const struct failure_context *ctx,
+ const char *format, va_list args);
/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
static const char *get_log_stamp_format(const char *unused)
failure_exit(status);
}
-void default_fatal_handler(enum log_type type, int status,
+void default_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
- if (default_handler(failure_log_type_prefixes[type], log_fd, format,
- args) < 0 && status == FATAL_DEFAULT)
+ int status = ctx->exit_status;
+
+ if (default_handler(failure_log_type_prefixes[ctx->type],
+ log_fd, format, args) < 0 &&
+ status == FATAL_DEFAULT)
status = FATAL_LOGWRITE;
- default_fatal_finish(type, status);
+ default_fatal_finish(ctx->type, status);
}
-void default_error_handler(enum log_type type, const char *format, va_list args)
+void default_error_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
int fd;
- switch (type) {
+ switch (ctx->type) {
case LOG_TYPE_DEBUG:
fd = log_debug_fd;
break;
fd = log_fd;
}
- if (default_handler(failure_log_type_prefixes[type],
+ if (default_handler(failure_log_type_prefixes[ctx->type],
fd, format, args) < 0) {
if (fd == log_fd)
failure_exit(FATAL_LOGWRITE);
}
}
-void i_log_type(enum log_type type, const char *format, ...)
+void i_log_type(const struct failure_context *ctx, const char *format, ...)
{
va_list args;
va_start(args, format);
- switch (type) {
+ switch (ctx->type) {
case LOG_TYPE_DEBUG:
- debug_handler(type, format, args);
+ debug_handler(ctx, format, args);
break;
case LOG_TYPE_INFO:
- info_handler(type, format, args);
+ info_handler(ctx, format, args);
break;
default:
- error_handler(type, format, args);
+ error_handler(ctx, format, args);
}
va_end(args);
void i_panic(const char *format, ...)
{
+ struct failure_context ctx;
va_list args;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.type = LOG_TYPE_PANIC;
+
va_start(args, format);
- fatal_handler(LOG_TYPE_PANIC, 0, format, args);
+ fatal_handler(&ctx, format, args);
va_end(args);
}
void i_fatal(const char *format, ...)
{
+ struct failure_context ctx;
va_list args;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.type = LOG_TYPE_FATAL;
+ ctx.exit_status = FATAL_DEFAULT;
+
va_start(args, format);
- fatal_handler(LOG_TYPE_FATAL, FATAL_DEFAULT, format, args);
+ fatal_handler(&ctx, format, args);
va_end(args);
}
void i_fatal_status(int status, const char *format, ...)
{
+ struct failure_context ctx;
va_list args;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.type = LOG_TYPE_FATAL;
+ ctx.exit_status = status;
+
va_start(args, format);
- fatal_handler(LOG_TYPE_FATAL, status, format, args);
+ fatal_handler(&ctx, format, args);
va_end(args);
}
va_list args;
va_start(args, format);
- error_handler(LOG_TYPE_ERROR, format, args);
+ error_handler(&failure_ctx_error, format, args);
va_end(args);
errno = old_errno;
va_list args;
va_start(args, format);
- error_handler(LOG_TYPE_WARNING, format, args);
+ error_handler(&failure_ctx_warning, format, args);
va_end(args);
errno = old_errno;
va_list args;
va_start(args, format);
- info_handler(LOG_TYPE_INFO, format, args);
+ info_handler(&failure_ctx_info, format, args);
va_end(args);
errno = old_errno;
va_list args;
va_start(args, format);
- debug_handler(LOG_TYPE_DEBUG, format, args);
+ debug_handler(&failure_ctx_debug, format, args);
va_end(args);
errno = old_errno;
}
-void i_set_fatal_handler(fatal_failure_callback_t *callback ATTR_NORETURN)
+void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN)
{
if (callback == NULL)
callback = default_fatal_handler;
debug_handler = callback;
}
-void i_get_failure_handlers(fatal_failure_callback_t **fatal_callback_r,
+void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
failure_callback_t **info_callback_r,
failure_callback_t **debug_callback_r)
return 0;
}
-void i_syslog_fatal_handler(enum log_type type, int status,
- const char *fmt, va_list args)
+void i_syslog_fatal_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
- if (syslog_handler(LOG_CRIT, type, fmt, args) < 0 &&
+ int status = ctx->exit_status;
+
+ if (syslog_handler(LOG_CRIT, ctx->type, format, args) < 0 &&
status == FATAL_DEFAULT)
status = FATAL_LOGERROR;
- default_fatal_finish(type, status);
+ default_fatal_finish(ctx->type, status);
}
-void i_syslog_error_handler(enum log_type type, const char *fmt, va_list args)
+void i_syslog_error_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
int level = LOG_ERR;
- switch (type) {
+ switch (ctx->type) {
case LOG_TYPE_DEBUG:
level = LOG_DEBUG;
break;
i_unreached();
}
- if (syslog_handler(level, type, fmt, args) < 0)
+ if (syslog_handler(level, ctx->type, format, args) < 0)
failure_exit(FATAL_LOGERROR);
}
str_truncate(str, prefix_len);
str_append_n(str, str_c(full_str) + pos, max_text_len);
str_append_c(str, '\n');
- if (log_fd_write(2, str_data(str), str_len(str)) < 0)
+ if (log_fd_write(STDERR_FILENO,
+ str_data(str), str_len(str)) < 0)
return -1;
pos += max_text_len;
}
}
static int ATTR_FORMAT(2, 0)
-internal_handler(enum log_type log_type, const char *format, va_list args)
+internal_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
static int recursed = 0;
int ret;
unsigned int prefix_len;
str = t_str_new(128);
- str_printfa(str, "\001%c%s ", log_type + 1, my_pid);
+ str_printfa(str, "\001%c%s ", ctx->type + 1, my_pid);
prefix_len = str_len(str);
str_vprintfa(str, format, args);
if (str_len(str)+1 <= PIPE_BUF) {
str_append_c(str, '\n');
- ret = log_fd_write(2, str_data(str), str_len(str));
+ ret = log_fd_write(STDERR_FILENO,
+ str_data(str), str_len(str));
} else {
ret = internal_send_split(str, prefix_len);
}
failure->text = line + 1;
}
-static void ATTR_NORETURN ATTR_FORMAT(3, 0)
-i_internal_fatal_handler(enum log_type type, int status,
- const char *fmt, va_list args)
+static void ATTR_NORETURN ATTR_FORMAT(2, 0)
+i_internal_fatal_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
- if (internal_handler(type, fmt, args) < 0 &&
+ int status = ctx->exit_status;
+
+ if (internal_handler(ctx, format, args) < 0 &&
status == FATAL_DEFAULT)
status = FATAL_LOGERROR;
- default_fatal_finish(type, status);
+ default_fatal_finish(ctx->type, status);
}
static void
-i_internal_error_handler(enum log_type type, const char *fmt, va_list args)
+i_internal_error_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
{
- if (internal_handler(type, fmt, args) < 0)
+ if (internal_handler(ctx, format, args) < 0)
failure_exit(FATAL_LOGERROR);
}
const char *text;
};
+struct failure_context {
+ enum log_type type;
+ int exit_status; /* for LOG_TYPE_FATAL */
+};
+
#define DEFAULT_FAILURE_STAMP_FORMAT "%b %d %H:%M:%S "
-typedef void failure_callback_t(enum log_type type, const char *, va_list);
-typedef void fatal_failure_callback_t(enum log_type type, int status,
- const char *, va_list);
+typedef void failure_callback_t(const struct failure_context *ctx,
+ const char *format, va_list args);
extern const char *failure_log_type_prefixes[];
-void i_log_type(enum log_type type, const char *format, ...) ATTR_FORMAT(2, 3);
+void i_log_type(const struct failure_context *ctx, const char *format, ...)
+ ATTR_FORMAT(2, 3);
void i_panic(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
void i_fatal(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
/* Change failure handlers. */
#ifndef __cplusplus
-void i_set_fatal_handler(fatal_failure_callback_t *callback ATTR_NORETURN);
+void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN);
#else
/* Older g++ doesn't like attributes in parameters */
-void i_set_fatal_handler(fatal_failure_callback_t *callback);
+void i_set_fatal_handler(failure_callback_t *callback);
#endif
void i_set_error_handler(failure_callback_t *callback);
void i_set_info_handler(failure_callback_t *callback);
void i_set_debug_handler(failure_callback_t *callback);
-void i_get_failure_handlers(fatal_failure_callback_t **fatal_callback_r,
+void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
failure_callback_t **info_callback_r,
failure_callback_t **debug_callback_r);
/* Send failures to file. */
-void default_fatal_handler(enum log_type type, int status,
+void default_fatal_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
+ ATTR_NORETURN ATTR_FORMAT(2, 0);
+void default_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
- ATTR_NORETURN ATTR_FORMAT(3, 0);
-void default_error_handler(enum log_type type, const char *format, va_list args)
ATTR_FORMAT(2, 0);
/* Send failures to syslog() */
-void i_syslog_fatal_handler(enum log_type type, int status,
- const char *fmt, va_list args)
- ATTR_NORETURN ATTR_FORMAT(3, 0);
-void i_syslog_error_handler(enum log_type type, const char *fmt, va_list args)
+void i_syslog_fatal_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
+ ATTR_NORETURN ATTR_FORMAT(2, 0);
+void i_syslog_error_handler(const struct failure_context *ctx,
+ const char *format, va_list args)
ATTR_FORMAT(2, 0);
/* Open syslog and set failure/info/debug handlers to use it. */
struct service_list *services;
static char *pidfile_path;
-static fatal_failure_callback_t *orig_fatal_callback;
+static failure_callback_t *orig_fatal_callback;
static failure_callback_t *orig_error_callback;
static const char *child_process_env[3]; /* @UNSAFE */
}
static void ATTR_NORETURN ATTR_FORMAT(3, 0)
-master_fatal_callback(enum log_type type, int status,
+master_fatal_callback(const struct failure_context *ctx,
const char *format, va_list args)
{
const char *path, *str;
}
}
- orig_fatal_callback(type, status, format, args);
+ orig_fatal_callback(ctx, format, args);
abort(); /* just to silence the noreturn attribute warnings */
}
static void ATTR_NORETURN
-startup_fatal_handler(enum log_type type, int status,
+startup_fatal_handler(const struct failure_context *ctx,
const char *fmt, va_list args)
{
va_list args2;
VA_COPY(args2, args);
- fprintf(stderr, "%s%s\n", failure_log_type_prefixes[type],
+ fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
t_strdup_vprintf(fmt, args2));
- orig_fatal_callback(type, status, fmt, args);
+ orig_fatal_callback(ctx, fmt, args);
abort();
}
static void
-startup_error_handler(enum log_type type, const char *fmt, va_list args)
+startup_error_handler(const struct failure_context *ctx,
+ const char *fmt, va_list args)
{
va_list args2;
VA_COPY(args2, args);
- fprintf(stderr, "%s%s\n", failure_log_type_prefixes[type],
+ fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
t_strdup_vprintf(fmt, args2));
- orig_error_callback(type, fmt, args);
+ orig_error_callback(ctx, fmt, args);
}
static void fatal_log_check(const struct master_settings *set)