failures.c revision e173d24c0b3f444eaa4d461de8f7c28b9ea3c65c
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenconst char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenconst char *failure_log_type_names[LOG_TYPE_COUNT] = {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "debug", "info", "warning", "error", "fatal", "panic"
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen/* Initialize working defaults */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic failure_callback_t *fatal_handler ATTR_NORETURN =
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 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 };
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int log_fd = STDERR_FILENO, log_info_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 Siraineni_internal_error_handler(const struct failure_context *ctx,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic const char *get_log_stamp_format(const char *unused)
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainenstatic const char *get_log_stamp_format(const char *unused ATTR_UNUSED)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainenstatic void log_prefix_add(const struct failure_context *ctx, string_t *str)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic void log_fd_flush_stop(struct ioloop *ioloop)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic int log_fd_write(int fd, const unsigned char *data, unsigned int len)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen unsigned int prev_signal_term_counter = signal_term_counter;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen unsigned int terminal_eintr_count = 0;
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen while ((ret = write(fd, data, len)) != (ssize_t)len) {
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen /* some was written, continue.. */
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen /* out of disk space? */
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen /* wait until we can write more. this can happen at
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen least when writing to terminal, even if fd is
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
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 */
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen /* received two terminal signals.
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen someone wants us dead. */
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen prev_signal_term_counter = signal_term_counter;
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainendefault_handler(const struct failure_context *ctx, int fd,
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen static int recursed = 0;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen /* we're being called from some signal handler or we ran
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen out of memory */
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen str_append(str, failure_log_type_prefixes[ctx->type]);
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 ret = log_fd_write(fd, str_data(str), str_len(str));
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainendefault_fatal_finish(enum log_type type, int status)
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) {
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (type == LOG_TYPE_PANIC || getenv("CORE_ERROR") != NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (status == FATAL_OUTOFMEM && getenv("CORE_OUTOFMEM") != NULL))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid default_fatal_handler(const struct failure_context *ctx,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (default_handler(ctx, log_fd, format, args) < 0 &&
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenvoid default_error_handler(const struct failure_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (default_handler(ctx, fd, format, args) < 0) {
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",
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (ctx->type == LOG_TYPE_ERROR && coredump_on_error)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid i_log_type(const struct failure_context *ctx, const char *format, ...)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid i_fatal_status(int status, const char *format, ...)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen error_handler(&failure_ctx_error, format, args);
33b469d1ca66dd2cc496d2d990b8b98e72952a29Timo Sirainen error_handler(&failure_ctx_warning, format, args);
b3484b5b1f47e4cf112f0e371478a2d7794b31bbTimo Sirainen info_handler(&failure_ctx_info, format, args);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen debug_handler(&failure_ctx_debug, format, args);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_error_handler(failure_callback_t *callback)
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen coredump_on_error = getenv("CORE_ERROR") != NULL;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_info_handler(failure_callback_t *callback)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid i_set_debug_handler(failure_callback_t *callback)
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainenvoid i_get_failure_handlers(failure_callback_t **fatal_callback_r,
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainensyslog_handler(int level, enum log_type type, const char *format, va_list args)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen static int recursed = 0;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen /* syslogs don't generatelly bother to log the level in any way,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen so make sure errors are shown clearly */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid i_syslog_fatal_handler(const struct failure_context *ctx,
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen if (syslog_handler(LOG_CRIT, ctx->type, format, args) < 0 &&
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenvoid i_syslog_error_handler(const struct failure_context *ctx,
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen if (syslog_handler(level, ctx->type, format, args) < 0)
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainenvoid i_set_failure_syslog(const char *ident, int options, int facility)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void open_log_file(int *fd, const char *path)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen const char *str;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen str = t_strdup_printf("close(%d) failed: %m", *fd);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen if (path == NULL || strcmp(path, "/dev/stderr") == 0)
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen *fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
900bb5e316d030cdebff7ee128ce65881dfb27f7Timo Sirainen str = t_strdup_printf("Can't open log file %s: %m\n",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid i_set_failure_file(const char *path, const char *prefix)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (log_info_fd != STDERR_FILENO && log_info_fd != log_fd) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (log_debug_fd != STDERR_FILENO && log_debug_fd != log_info_fd &&
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen i_error("close(%d) failed: %m", log_debug_fd);
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen /* if info/debug logs are elsewhere, i_set_info/debug_file()
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen overrides these later. */
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic void i_failure_send_option(const char *key, const char *value)
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen const char *str;
9617ac7078a17bd346fed69526861c3e7fd9d809Timo Sirainen if (error_handler != i_internal_error_handler)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str = t_strdup_printf("\001%c%s %s=%s\n", LOG_TYPE_OPTION+1,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainenvoid i_set_failure_prefix(const char *prefix_fmt, ...)
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen log_prefix = i_strdup_vprintf(prefix_fmt, args);
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainenstatic int internal_send_split(string_t *full_str, unsigned int prefix_len)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append_n(str, str_c(full_str), prefix_len);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen str_append_n(str, str_c(full_str) + pos, max_text_len);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Siraineninternal_handler(const struct failure_context *ctx,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen static int recursed = 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we're being called from some signal handler or we ran
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen out of memory */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen str_printfa(str, "\001%c%s ", ctx->type + 1, my_pid);
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen i_warning("Broken log line follows (type=NUL)");
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen i_warning("Broken log line follows (type=%d)", line[1]-1);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenvoid i_failure_parse_line(const char *line, struct failure_line *failure)
line++;
void i_set_failure_internal(void)
void failures_deinit(void)