failures.c revision 81333312b6be6cdf054959f519544fddfe350a6e
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen/* Initialize working defaults */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic fatal_failure_callback_t *fatal_handler ATTR_NORETURN =
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic failure_callback_t *error_handler = default_error_handler;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic failure_callback_t *info_handler = default_error_handler;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic failure_callback_t *debug_handler = default_error_handler;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void (*failure_exit_callback)(int *) = NULL;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic char *log_prefix = NULL, *log_stamp_format = NULL;
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipekstatic bool failure_ignore_errors = FALSE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Siraineni_internal_error_handler(enum log_type type, const char *fmt, va_list args);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic const char *get_log_stamp_format(const char *unused)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic const char *get_log_stamp_format(const char *unused ATTR_UNUSED)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstatic void log_fd_flush_stop(struct ioloop *ioloop)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenstatic int log_fd_write(int fd, const unsigned char *data, unsigned int len)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int eintr_count = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen while ((ret = write(fd, data, len)) != (ssize_t)len) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* some was written, continue.. */
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen /* out of disk space? */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* we don't want to die because of this.
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen try again a couple of times. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* wait until we can write more. this can happen at least
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen when writing to terminal, even if fd is blocking. */
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainendefault_handler(const char *prefix, int fd, const char *format, va_list args)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen static int recursed = 0;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* we're being called from some signal handler or we ran
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen out of memory */
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen /* make sure there's no %n in there and fix %m */
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_vprintfa(str, printf_format_fix(format), args);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen ret = log_fd_write(fd, str_data(str), str_len(str));
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainendefault_fatal_finish(enum log_type type, int status)
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen if (type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) {
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainenvoid default_fatal_handler(enum log_type type, int status,
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (default_handler(failure_log_type_prefixes[type], log_fd, format,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenvoid default_error_handler(enum log_type type, const char *format, va_list args)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (default_handler(failure_log_type_prefixes[type],
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* we failed to log to info/debug log, try to log the
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen write error to error log - maybe that'll work. */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainenvoid i_log_type(enum log_type type, const char *format, ...)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen fatal_handler(LOG_TYPE_PANIC, 0, format, args);
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen fatal_handler(LOG_TYPE_FATAL, FATAL_DEFAULT, format, args);
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainenvoid i_fatal_status(int status, const char *format, ...)
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen fatal_handler(LOG_TYPE_FATAL, status, format, args);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen error_handler(LOG_TYPE_WARNING, format, args);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenvoid i_set_fatal_handler(fatal_failure_callback_t *callback ATTR_NORETURN)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenvoid i_set_error_handler(failure_callback_t *callback)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenvoid i_set_info_handler(failure_callback_t *callback)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenvoid i_set_debug_handler(failure_callback_t *callback)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenvoid i_get_failure_handlers(fatal_failure_callback_t **fatal_callback_r,
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainensyslog_handler(int level, enum log_type type, const char *format, va_list args)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen static int recursed = 0;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen /* syslogs don't generatelly bother to log the level in any way,
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen so make sure errors are shown clearly */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid i_syslog_fatal_handler(enum log_type type, int status,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (syslog_handler(LOG_CRIT, type, fmt, args) < 0 &&
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid i_syslog_error_handler(enum log_type type, const char *fmt, va_list args)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen if (syslog_handler(level, type, fmt, args) < 0)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainenvoid i_set_failure_syslog(const char *ident, int options, int facility)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainenstatic void open_log_file(int *fd, const char *path)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *str;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen str = t_strdup_printf("close(%d) failed: %m", *fd);
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (path == NULL || strcmp(path, "/dev/stderr") == 0)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen *fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi str = t_strdup_printf("Can't open log file %s: %m\n",
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)write_full(STDERR_FILENO, str, strlen(str));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenvoid i_set_failure_file(const char *path, const char *prefix)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (log_info_fd != STDERR_FILENO && log_info_fd != log_fd) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (log_debug_fd != STDERR_FILENO && log_debug_fd != log_info_fd &&
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_error("close(%d) failed: %m", log_debug_fd);
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi /* if info/debug logs are elsewhere, i_set_info/debug_file()
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen overrides these later. */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void i_failure_send_option(const char *key, const char *value)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (error_handler != i_internal_error_handler)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen str = t_strdup_printf("\001%c%s %s=%s\n", LOG_TYPE_OPTION+1,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic int internal_send_split(string_t *full_str, unsigned int prefix_len)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen str_append_n(str, str_c(full_str), prefix_len);
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi max_text_len = PIPE_BUF - prefix_len - 1;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi str_append_n(str, str_c(full_str) + pos, max_text_len);
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi if (log_fd_write(2, str_data(str), str_len(str)) < 0)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Siraineninternal_handler(enum log_type log_type, const char *format, va_list args)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen static int recursed = 0;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi /* we're being called from some signal handler or we ran
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi out of memory */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen str_printfa(str, "\001%c%s ", log_type + 1, my_pid);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen ret = log_fd_write(2, str_data(str), str_len(str));
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen i_warning("Broken log line follows (type=NUL)");
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_warning("Broken log line follows (type=%d)", line[1]-1);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid i_failure_parse_line(const char *line, struct failure_line *failure)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen failure->pid = failure->pid*10 + (*line - '0');
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* some old protocol? */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Siraineni_internal_fatal_handler(enum log_type type, int status,
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Siraineni_internal_error_handler(enum log_type type, const char *fmt, va_list args)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen i_set_fatal_handler(i_internal_fatal_handler);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen i_set_error_handler(i_internal_error_handler);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen i_set_debug_handler(i_internal_error_handler);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen /* write debug-level messages to the info_log_path,
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen until i_set_debug_file() was called */
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (log_debug_fd == log_fd || log_debug_fd == log_info_fd)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid i_set_failure_timestamp_format(const char *fmt)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid i_set_failure_ip(const struct ip_addr *ip)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid i_set_failure_exit_callback(void (*callback)(int *status))