extern bool have_proc_sys_kernel_core_pattern;
extern const char *ssl_manual_key_password;
extern int global_master_dead_pipe_fd[2];
+extern struct log_error_buffer *log_error_buffer;
extern struct service_list *services;
extern bool startup_finished;
#include "master-instance.h"
#include "master-service-private.h"
#include "master-service-settings.h"
+#include "log-error-buffer.h"
#include "askpass.h"
#include "capabilities.h"
#include "master-client.h"
bool have_proc_sys_kernel_core_pattern;
const char *ssl_manual_key_password;
int global_master_dead_pipe_fd[2];
+struct log_error_buffer *log_error_buffer;
struct service_list *services;
bool startup_finished = FALSE;
}
}
+static void ATTR_FORMAT(2, 0)
+master_error_handler(const struct failure_context *ctx,
+ const char *fmt, va_list args)
+{
+ va_list args2;
+
+ VA_COPY(args2, args);
+ struct log_error error = {
+ .type = ctx->type,
+ .timestamp = ioloop_timeval,
+ .prefix = ctx->log_prefix != NULL ? ctx->log_prefix : "",
+ .text = t_strdup_vprintf(fmt, args2),
+ };
+ log_error_buffer_add(log_error_buffer, &error);
+ va_end(args2);
+
+ orig_error_callback(ctx, fmt, args);
+}
+
static void ATTR_NORETURN ATTR_FORMAT(2, 0)
master_fatal_callback(const struct failure_context *ctx,
const char *format, va_list args)
service_pids_deinit();
/* notify systemd that we are done */
i_sd_notify(0, "STATUS=Dovecot stopped");
+
+ i_set_error_handler(orig_error_callback);
+ log_error_buffer_deinit(&log_error_buffer);
}
static const char *get_full_config_path(struct service_list *list)
if (chdir(set->base_dir) < 0)
i_fatal("chdir(%s) failed: %m", set->base_dir);
+ log_error_buffer = log_error_buffer_init();
i_set_fatal_handler(master_fatal_callback);
- i_set_error_handler(orig_error_callback);
+ i_set_error_handler(master_error_handler);
if (!foreground)
daemonize();
#include "strescape.h"
#include "ostream.h"
#include "connection.h"
+#include "log-error-buffer.h"
#include "service.h"
#include "service-process.h"
#include "service-monitor.h"
return 1;
}
+static int master_client_send_errors(struct master_client *client)
+{
+ struct log_error_buffer_iter *iter;
+ const struct log_error *error;
+ string_t *str = t_str_new(256);
+ int ret = 0;
+
+ iter = log_error_buffer_iter_init(log_error_buffer);
+ while ((error = log_error_buffer_iter_next(iter)) != NULL) {
+ str_truncate(str, 0);
+ str_printfa(str, "%s\t%"PRIdTIME_T".%06u\t",
+ failure_log_type_names[error->type],
+ error->timestamp.tv_sec,
+ (unsigned int)error->timestamp.tv_usec);
+ str_append_tabescaped(str, error->prefix);
+ str_append_c(str, '\t');
+ str_append_tabescaped(str, error->text);
+ str_append_c(str, '\n');
+ if (o_stream_send(client->conn.output,
+ str_data(str), str_len(str)) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ log_error_buffer_iter_deinit(&iter);
+ o_stream_nsend_str(client->conn.output, "\n");
+ return ret;
+}
+
static int
master_client_stop(struct master_client *client, const char *const *args)
{
return master_client_service_status(client);
if (strcmp(cmd, "PROCESS-STATUS") == 0)
return master_client_process_status(client, args);
+ if (strcmp(cmd, "ERROR-LOG") == 0)
+ return master_client_send_errors(client);
if (strcmp(cmd, "STOP") == 0)
return master_client_stop(client, args);
e_error(conn->event, "Unknown command: %s", cmd);