failures.c revision e173d24c0b3f444eaa4d461de8f7c28b9ea3c65c
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "ioloop.h"
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen#include "str.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "hostpid.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "net.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "lib-signals.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "backtrace-string.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "printf-format-fix.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen#include "fd-close-on-exec.h"
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen#include <stdlib.h>
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include <unistd.h>
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include <fcntl.h>
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include <syslog.h>
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen#include <time.h>
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenconst char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Debug: ",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Info: ",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Warning: ",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Error: ",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Fatal: ",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "Panic: "
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen};
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenconst char *failure_log_type_names[LOG_TYPE_COUNT] = {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "debug", "info", "warning", "error", "fatal", "panic"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen};
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen/* Initialize working defaults */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic failure_callback_t *fatal_handler ATTR_NORETURN =
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen default_fatal_handler;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic failure_callback_t *error_handler = default_error_handler;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic failure_callback_t *info_handler = default_error_handler;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic failure_callback_t *debug_handler = default_error_handler;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void (*failure_exit_callback)(int *) = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic struct failure_context failure_ctx_debug = { .type = LOG_TYPE_DEBUG };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct failure_context failure_ctx_info = { .type = LOG_TYPE_INFO };
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic struct failure_context failure_ctx_warning = { .type = LOG_TYPE_WARNING };
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic struct failure_context failure_ctx_error = { .type = LOG_TYPE_ERROR };
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen log_debug_fd = STDERR_FILENO;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic char *log_prefix = NULL, *log_stamp_format = NULL;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic bool failure_ignore_errors = FALSE, log_prefix_sent = FALSE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic bool coredump_on_error = FALSE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic void ATTR_FORMAT(2, 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Siraineni_internal_error_handler(const struct failure_context *ctx,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *format, va_list args);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic const char *get_log_stamp_format(const char *unused)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen ATTR_FORMAT_ARG(1);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainenstatic const char *get_log_stamp_format(const char *unused ATTR_UNUSED)
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen{
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen return log_stamp_format;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen}
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid failure_exit(int status)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen if (failure_exit_callback != NULL)
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen failure_exit_callback(&status);
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen exit(status);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainenstatic void log_prefix_add(const struct failure_context *ctx, string_t *str)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen{
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen const struct tm *tm = ctx->timestamp;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen char buf[256];
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen time_t now;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen if (log_stamp_format != NULL) {
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen if (tm == NULL) {
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen now = time(NULL);
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen tm = localtime(&now);
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen if (strftime(buf, sizeof(buf),
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen get_log_stamp_format("unused"), tm) > 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen str_append(str, buf);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (log_prefix != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, log_prefix);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic void log_fd_flush_stop(struct ioloop *ioloop)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen{
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen io_loop_stop(ioloop);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen}
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic int log_fd_write(int fd, const unsigned char *data, unsigned int len)
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen{
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen struct ioloop *ioloop;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct io *io;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ssize_t ret;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen unsigned int prev_signal_term_counter = signal_term_counter;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen unsigned int terminal_eintr_count = 0;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen while ((ret = write(fd, data, len)) != (ssize_t)len) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ret > 0) {
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen /* some was written, continue.. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen data += ret;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen len -= ret;
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen if (ret == 0) {
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen /* out of disk space? */
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen errno = ENOSPC;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen return -1;
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen }
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen switch (errno) {
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen case EAGAIN:
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen /* wait until we can write more. this can happen at
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen least when writing to terminal, even if fd is
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen blocking. */
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen ioloop = io_loop_create();
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen io_loop_run(ioloop);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_remove(&io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_destroy(&ioloop);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case EINTR:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (prev_signal_term_counter == signal_term_counter) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* non-terminal signal. ignore. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (terminal_eintr_count++ == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* we'd rather not die in the middle of
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen writing to log. try again once more */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen /* received two terminal signals.
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen someone wants us dead. */
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen return -1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen break;
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen }
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen prev_signal_term_counter = signal_term_counter;
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen }
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen return 0;
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen}
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenstatic int ATTR_FORMAT(3, 0)
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainendefault_handler(const struct failure_context *ctx, int fd,
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen const char *format, va_list args)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen{
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen static int recursed = 0;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen int ret;
6469cf211a57433335641725dc236ebb2b9fdd3bTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (recursed >= 2) {
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen /* we're being called from some signal handler or we ran
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen out of memory */
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen return -1;
9c32eb25e7b90e753e0cd7b30f7a70e8ca9121d9Timo Sirainen }
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen recursed++;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen T_BEGIN {
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen string_t *str = t_str_new(256);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen log_prefix_add(ctx, str);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen str_append(str, failure_log_type_prefixes[ctx->type]);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen /* make sure there's no %n in there and fix %m */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen str_vprintfa(str, printf_format_fix(format), args);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen str_append_c(str, '\n');
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen ret = log_fd_write(fd, str_data(str), str_len(str));
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen } T_END;
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen if (ret < 0 && failure_ignore_errors)
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen ret = 0;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen recursed--;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return ret;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainenstatic void ATTR_NORETURN
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainendefault_fatal_finish(enum log_type type, int status)
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const char *backtrace;
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) {
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (backtrace_get(&backtrace) == 0)
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen i_error("Raw backtrace: %s", backtrace);
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen }
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (type == LOG_TYPE_PANIC || getenv("CORE_ERROR") != NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (status == FATAL_OUTOFMEM && getenv("CORE_OUTOFMEM") != NULL))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen abort();
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen else
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen failure_exit(status);
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen}
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid default_fatal_handler(const struct failure_context *ctx,
dbe64f3893616a4005c8946be75d2dc8f6823d72Timo Sirainen const char *format, va_list args)
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int status = ctx->exit_status;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (default_handler(ctx, log_fd, format, args) < 0 &&
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen status == FATAL_DEFAULT)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen status = FATAL_LOGWRITE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen default_fatal_finish(ctx->type, status);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenvoid default_error_handler(const struct failure_context *ctx,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen const char *format, va_list args)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int fd;
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen switch (ctx->type) {
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen case LOG_TYPE_DEBUG:
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen fd = log_debug_fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen case LOG_TYPE_INFO:
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen fd = log_info_fd;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen break;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen default:
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen fd = log_fd;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen }
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (default_handler(ctx, fd, format, args) < 0) {
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen if (fd == log_fd)
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen failure_exit(FATAL_LOGWRITE);
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen /* we failed to log to info/debug log, try to log the
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen write error to error log - maybe that'll work. */
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen fd == log_info_fd ? "info" : "debug");
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (ctx->type == LOG_TYPE_ERROR && coredump_on_error)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen abort();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid i_log_type(const struct failure_context *ctx, const char *format, ...)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen va_list args;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen va_start(args, format);
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen switch (ctx->type) {
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen case LOG_TYPE_DEBUG:
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen debug_handler(ctx, format, args);
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen case LOG_TYPE_INFO:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen info_handler(ctx, format, args);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen break;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen default:
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen error_handler(ctx, format, args);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen va_end(args);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
d938e9e4ec4c0f326dffd5ebe42c1ad893ce7e52Timo Sirainen
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainenvoid i_panic(const char *format, ...)
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct failure_context ctx;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen va_list args;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen memset(&ctx, 0, sizeof(ctx));
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen ctx.type = LOG_TYPE_PANIC;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen va_start(args, format);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen fatal_handler(&ctx, format, args);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen va_end(args);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainenvoid i_fatal(const char *format, ...)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen struct failure_context ctx;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen va_list args;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen memset(&ctx, 0, sizeof(ctx));
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen ctx.type = LOG_TYPE_FATAL;
eb1572d7c44ebc7b0b039d085c3dbab2ef7043ddTimo Sirainen ctx.exit_status = FATAL_DEFAULT;
eb1572d7c44ebc7b0b039d085c3dbab2ef7043ddTimo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen va_start(args, format);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen fatal_handler(&ctx, format, args);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen va_end(args);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid i_fatal_status(int status, const char *format, ...)
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct failure_context ctx;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen va_list args;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen memset(&ctx, 0, sizeof(ctx));
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen ctx.type = LOG_TYPE_FATAL;
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen ctx.exit_status = status;
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen va_start(args, format);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen fatal_handler(&ctx, format, args);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen va_end(args);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen}
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainenvoid i_error(const char *format, ...)
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen int old_errno = errno;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen va_list args;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen va_start(args, format);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen error_handler(&failure_ctx_error, format, args);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen va_end(args);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen errno = old_errno;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainenvoid i_warning(const char *format, ...)
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen{
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen int old_errno = errno;
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen va_list args;
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen
33b469d1ca66dd2cc496d2d990b8b98e72952a29Timo Sirainen va_start(args, format);
33b469d1ca66dd2cc496d2d990b8b98e72952a29Timo Sirainen error_handler(&failure_ctx_warning, format, args);
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen va_end(args);
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen errno = old_errno;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen}
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainenvoid i_info(const char *format, ...)
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen{
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen int old_errno = errno;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen va_list args;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen
b3484b5b1f47e4cf112f0e371478a2d7794b31bbTimo Sirainen va_start(args, format);
b3484b5b1f47e4cf112f0e371478a2d7794b31bbTimo Sirainen info_handler(&failure_ctx_info, format, args);
d81131d3bbb4f0befb62a661d1785cf8c84a17e2Timo Sirainen va_end(args);
d81131d3bbb4f0befb62a661d1785cf8c84a17e2Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen errno = old_errno;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainenvoid i_debug(const char *format, ...)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen int old_errno = errno;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen va_list args;
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen va_start(args, format);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen debug_handler(&failure_ctx_debug, format, args);
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen va_end(args);
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen errno = old_errno;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN)
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen{
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen fatal_handler = callback;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_error_handler(failure_callback_t *callback)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen coredump_on_error = getenv("CORE_ERROR") != NULL;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen error_handler = callback;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_info_handler(failure_callback_t *callback)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen info_handler = callback;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_debug_handler(failure_callback_t *callback)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen debug_handler = callback;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainenvoid i_get_failure_handlers(failure_callback_t **fatal_callback_r,
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen failure_callback_t **error_callback_r,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen failure_callback_t **info_callback_r,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen failure_callback_t **debug_callback_r)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen{
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen *fatal_callback_r = fatal_handler;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen *error_callback_r = error_handler;
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen *info_callback_r = info_handler;
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen *debug_callback_r = debug_handler;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int ATTR_FORMAT(3, 0)
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainensyslog_handler(int level, enum log_type type, const char *format, va_list args)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen static int recursed = 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (recursed >= 2)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return -1;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen recursed++;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen /* syslogs don't generatelly bother to log the level in any way,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen so make sure errors are shown clearly */
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen T_BEGIN {
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen syslog(level, "%s%s%s",
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen log_prefix == NULL ? "" : log_prefix,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen type != LOG_TYPE_INFO ?
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen failure_log_type_prefixes[type] : "",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen t_strdup_vprintf(format, args));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } T_END;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen recursed--;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid i_syslog_fatal_handler(const struct failure_context *ctx,
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen const char *format, va_list args)
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen{
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen int status = ctx->exit_status;
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen if (syslog_handler(LOG_CRIT, ctx->type, format, args) < 0 &&
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen status == FATAL_DEFAULT)
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen status = FATAL_LOGERROR;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen default_fatal_finish(ctx->type, status);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenvoid i_syslog_error_handler(const struct failure_context *ctx,
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen const char *format, va_list args)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen{
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen int level = LOG_ERR;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen switch (ctx->type) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen case LOG_TYPE_DEBUG:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen level = LOG_DEBUG;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen case LOG_TYPE_INFO:
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen level = LOG_INFO;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case LOG_TYPE_WARNING:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen level = LOG_WARNING;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen break;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen case LOG_TYPE_ERROR:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen level = LOG_ERR;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen break;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen case LOG_TYPE_FATAL:
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen case LOG_TYPE_PANIC:
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen level = LOG_CRIT;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen break;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen case LOG_TYPE_COUNT:
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen case LOG_TYPE_OPTION:
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen i_unreached();
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen }
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen if (syslog_handler(level, ctx->type, format, args) < 0)
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen failure_exit(FATAL_LOGERROR);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainenvoid i_set_failure_syslog(const char *ident, int options, int facility)
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen{
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen openlog(ident, options, facility);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen i_set_fatal_handler(i_syslog_fatal_handler);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen i_set_error_handler(i_syslog_error_handler);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen i_set_info_handler(i_syslog_error_handler);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen i_set_debug_handler(i_syslog_error_handler);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen}
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void open_log_file(int *fd, const char *path)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen const char *str;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (*fd != STDERR_FILENO) {
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (close(*fd) < 0) {
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen str = t_strdup_printf("close(%d) failed: %m", *fd);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen }
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen }
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen if (path == NULL || strcmp(path, "/dev/stderr") == 0)
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen *fd = STDERR_FILENO;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen else {
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen *fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen if (*fd == -1) {
900bb5e316d030cdebff7ee128ce65881dfb27f7Timo Sirainen *fd = STDERR_FILENO;
900bb5e316d030cdebff7ee128ce65881dfb27f7Timo Sirainen str = t_strdup_printf("Can't open log file %s: %m\n",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen path);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (fd == &log_fd)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen failure_exit(FATAL_LOGOPEN);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal_status(FATAL_LOGOPEN, "%s", str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen fd_close_on_exec(*fd, TRUE);
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen}
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid i_set_failure_file(const char *path, const char *prefix)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen i_set_failure_prefix("%s", prefix);
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (log_info_fd != STDERR_FILENO && log_info_fd != log_fd) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (close(log_info_fd) < 0)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_error("close(%d) failed: %m", log_info_fd);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (log_debug_fd != STDERR_FILENO && log_debug_fd != log_info_fd &&
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen log_debug_fd != log_fd) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (close(log_debug_fd) < 0)
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen i_error("close(%d) failed: %m", log_debug_fd);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen open_log_file(&log_fd, path);
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen /* if info/debug logs are elsewhere, i_set_info/debug_file()
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen overrides these later. */
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen log_info_fd = log_fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log_debug_fd = log_fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_set_fatal_handler(default_fatal_handler);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen i_set_error_handler(default_error_handler);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen i_set_info_handler(default_error_handler);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_set_debug_handler(default_error_handler);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen}
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic void i_failure_send_option(const char *key, const char *value)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen const char *str;
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen
9617ac7078a17bd346fed69526861c3e7fd9d809Timo Sirainen if (error_handler != i_internal_error_handler)
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen return;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str = t_strdup_printf("\001%c%s %s=%s\n", LOG_TYPE_OPTION+1,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen my_pid, key, value);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen (void)write_full(2, str, strlen(str));
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen}
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainenvoid i_set_failure_prefix(const char *prefix_fmt, ...)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen{
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen va_list args;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen va_start(args, prefix_fmt);
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen i_free(log_prefix);
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen log_prefix = i_strdup_vprintf(prefix_fmt, args);
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen va_end(args);
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen
b09eaeb9a81e5b58c6e605eb762573a2b4a69e0eTimo Sirainen log_prefix_sent = FALSE;
b09eaeb9a81e5b58c6e605eb762573a2b4a69e0eTimo Sirainen}
b09eaeb9a81e5b58c6e605eb762573a2b4a69e0eTimo Sirainen
abec3f4c5ec486c393e1513950f2d4819dcbc30fTimo Sirainenvoid i_unset_failure_prefix(void)
abec3f4c5ec486c393e1513950f2d4819dcbc30fTimo Sirainen{
00aaafa8619b4e6aaf23f15d30c36f06ccb820bcTimo Sirainen i_free(log_prefix);
00aaafa8619b4e6aaf23f15d30c36f06ccb820bcTimo Sirainen log_prefix = i_strdup("");
02f884382018f4435407374a059407caa44c9239Timo Sirainen log_prefix_sent = FALSE;
02f884382018f4435407374a059407caa44c9239Timo Sirainen}
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainenstatic int internal_send_split(string_t *full_str, unsigned int prefix_len)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen string_t *str;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen unsigned int max_text_len, pos = prefix_len;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str = t_str_new(PIPE_BUF);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append_n(str, str_c(full_str), prefix_len);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen max_text_len = PIPE_BUF - prefix_len - 1;
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen while (pos < str_len(full_str)) {
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen str_truncate(str, prefix_len);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen str_append_n(str, str_c(full_str) + pos, max_text_len);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen str_append_c(str, '\n');
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen if (log_fd_write(STDERR_FILENO,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_data(str), str_len(str)) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen pos += max_text_len;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen }
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen return 0;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen}
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenstatic int ATTR_FORMAT(2, 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Siraineninternal_handler(const struct failure_context *ctx,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen const char *format, va_list args)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen static int recursed = 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen int ret;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (recursed >= 2) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we're being called from some signal handler or we ran
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen out of memory */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen return -1;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen }
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen recursed++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen T_BEGIN {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen string_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int prefix_len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (!log_prefix_sent && log_prefix != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log_prefix_sent = TRUE;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen i_failure_send_option("prefix", log_prefix);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen str = t_str_new(128);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen str_printfa(str, "\001%c%s ", ctx->type + 1, my_pid);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen prefix_len = str_len(str);
268b72128fc3400912e9a6b83faf4950a367c2ffTimo Sirainen
268b72128fc3400912e9a6b83faf4950a367c2ffTimo Sirainen str_vprintfa(str, format, args);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (str_len(str)+1 <= PIPE_BUF) {
d9a129b491613014ce5f31fe1ab20903e2899ea4Timo Sirainen str_append_c(str, '\n');
d9a129b491613014ce5f31fe1ab20903e2899ea4Timo Sirainen ret = log_fd_write(STDERR_FILENO,
d9a129b491613014ce5f31fe1ab20903e2899ea4Timo Sirainen str_data(str), str_len(str));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen ret = internal_send_split(str, prefix_len);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen }
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen } T_END;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen
b83deefd2cf1e293373673eefb4d5cf60907978cTimo Sirainen if (ret < 0 && failure_ignore_errors)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = 0;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen recursed--;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen return ret;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic bool line_is_ok(const char *line)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (*line != 1)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen return FALSE;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (line[1] == '\0') {
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen i_warning("Broken log line follows (type=NUL)");
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen return FALSE;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen }
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (line[1]-1 > LOG_TYPE_OPTION) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen i_warning("Broken log line follows (type=%d)", line[1]-1);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen return FALSE;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen }
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen return TRUE;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen}
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenvoid i_failure_parse_line(const char *line, struct failure_line *failure)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen{
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen memset(failure, 0, sizeof(*failure));
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (!line_is_ok(line)) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen failure->log_type = LOG_TYPE_ERROR;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen failure->text = line;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen return;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen }
b3b4f3875850099c9292ad74d08bb385c3988f8fTimo Sirainen failure->log_type = line[1] - 1;
7a2d48763b43c4fd8bc17c444271f0b802113a5fTimo Sirainen
7a2d48763b43c4fd8bc17c444271f0b802113a5fTimo Sirainen line += 2;
7a2d48763b43c4fd8bc17c444271f0b802113a5fTimo Sirainen failure->text = line;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*line >= '0' && *line <= '9') {
failure->pid = failure->pid*10 + (*line - '0');
line++;
}
if (*line != ' ') {
/* some old protocol? */
failure->pid = 0;
return;
}
failure->text = line + 1;
}
static void ATTR_NORETURN ATTR_FORMAT(2, 0)
i_internal_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
int status = ctx->exit_status;
if (internal_handler(ctx, format, args) < 0 &&
status == FATAL_DEFAULT)
status = FATAL_LOGERROR;
default_fatal_finish(ctx->type, status);
}
static void
i_internal_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
if (internal_handler(ctx, format, args) < 0)
failure_exit(FATAL_LOGERROR);
}
void i_set_failure_internal(void)
{
i_set_fatal_handler(i_internal_fatal_handler);
i_set_error_handler(i_internal_error_handler);
i_set_info_handler(i_internal_error_handler);
i_set_debug_handler(i_internal_error_handler);
}
void i_set_failure_ignore_errors(bool ignore)
{
failure_ignore_errors = ignore;
}
void i_set_info_file(const char *path)
{
if (log_info_fd == log_fd)
log_info_fd = STDERR_FILENO;
open_log_file(&log_info_fd, path);
info_handler = default_error_handler;
/* write debug-level messages to the info_log_path,
until i_set_debug_file() was called */
log_debug_fd = log_info_fd;
i_set_debug_handler(default_error_handler);
}
void i_set_debug_file(const char *path)
{
if (log_debug_fd == log_fd || log_debug_fd == log_info_fd)
log_debug_fd = STDERR_FILENO;
open_log_file(&log_debug_fd, path);
debug_handler = default_error_handler;
}
void i_set_failure_timestamp_format(const char *fmt)
{
i_free(log_stamp_format);
log_stamp_format = i_strdup(fmt);
}
void i_set_failure_send_ip(const struct ip_addr *ip)
{
i_failure_send_option("ip", net_ip2addr(ip));
}
void i_set_failure_send_prefix(const char *prefix)
{
i_failure_send_option("prefix", prefix);
}
void i_set_failure_exit_callback(void (*callback)(int *status))
{
failure_exit_callback = callback;
}
void failures_deinit(void)
{
if (log_debug_fd == log_info_fd || log_debug_fd == log_fd)
log_debug_fd = STDERR_FILENO;
if (log_info_fd == log_fd)
log_info_fd = STDERR_FILENO;
if (log_fd != STDERR_FILENO) {
i_close_fd(&log_fd);
log_fd = STDERR_FILENO;
}
if (log_info_fd != STDERR_FILENO) {
i_close_fd(&log_info_fd);
log_info_fd = STDERR_FILENO;
}
if (log_debug_fd != STDERR_FILENO) {
i_close_fd(&log_debug_fd);
log_debug_fd = STDERR_FILENO;
}
i_free_and_null(log_prefix);
i_free_and_null(log_stamp_format);
}