bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "lib.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "ioloop.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "istream.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "hash.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "str.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "strescape.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "time-util.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "master-service-private.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "master-service-settings.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "doveadm.h"
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi#include "doveadm-print.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <stdio.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <unistd.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <fcntl.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <dirent.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <signal.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include <sys/stat.h>
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#define LAST_LOG_TYPE LOG_TYPE_PANIC
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#define TEST_LOG_MSG_PREFIX "This is Dovecot's "
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#define LOG_ERRORS_FNAME "log-errors"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#define LOG_TIMESTAMP_FORMAT "%b %d %H:%M:%S"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainenextern struct doveadm_cmd doveadm_cmd_log[];
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(2)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainencmd_log_test(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen struct failure_context ctx;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
8a2df8a89fc61c584429534a57a2ea20fcaf2d28Timo Sirainen master_service->log_initialized = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen master_service->flags |= MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen master_service_init_log(master_service, "doveadm: ");
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = 0; i < LAST_LOG_TYPE; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *prefix = failure_log_type_prefixes[i];
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen /* add timestamp so that syslog won't just write
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen "repeated message" text */
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen ctx.type = i;
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen i_log_type(&ctx, TEST_LOG_MSG_PREFIX"%s log (%u)",
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen t_str_lcase(t_strcut(prefix, ':')),
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen (unsigned int)ioloop_time);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void cmd_log_reopen(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen doveadm_master_send_signal(SIGUSR1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstruct log_find_file {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *path;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen uoff_t size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* 1 << enum log_type */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int mask;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen};
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstruct log_find_context {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen pool_t pool;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct log_find_file *) files;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen};
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void cmd_log_find_add(struct log_find_context *ctx,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *path, enum log_type type)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct log_find_file *file;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen char *key;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file = hash_table_lookup(ctx->files, path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (file == NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file = p_new(ctx->pool, struct log_find_file, 1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->path = key = p_strdup(ctx->pool, path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hash_table_insert(ctx->files, key, file);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->mask |= 1 << type;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainencmd_log_find_syslog_files(struct log_find_context *ctx, const char *path)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct log_find_file *file;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen DIR *dir;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct dirent *d;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct stat st;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen char *key;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen string_t *full_path;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t dir_len;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen dir = opendir(path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (dir == NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_error("opendir(%s) failed: %m", path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen full_path = t_str_new(256);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_append(full_path, path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_append_c(full_path, '/');
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen dir_len = str_len(full_path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen while ((d = readdir(dir)) != NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (d->d_name[0] == '.')
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_truncate(full_path, dir_len);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_append(full_path, d->d_name);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (stat(str_c(full_path), &st) < 0)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (S_ISDIR(st.st_mode)) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* recursively go through all subdirectories */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_syslog_files(ctx, str_c(full_path));
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen } else if (hash_table_lookup(ctx->files,
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen str_c(full_path)) == NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file = p_new(ctx->pool, struct log_find_file, 1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->size = st.st_size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->path = key =
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen p_strdup(ctx->pool, str_c(full_path));
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hash_table_insert(ctx->files, key, file);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (void)closedir(dir);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic bool log_type_find(const char *str, enum log_type *type_r)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len = strlen(str);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = 0; i < LAST_LOG_TYPE; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (strncasecmp(str, failure_log_type_prefixes[i], len) == 0 &&
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen failure_log_type_prefixes[i][len] == ':') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen *type_r = i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void cmd_log_find_syslog_file_messages(struct log_find_file *file)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct istream *input;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *line, *p;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen enum log_type type;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen int fd;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen fd = open(file->path, O_RDONLY);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (fd == -1)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return;
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen input = i_stream_create_fd_autoclose(&fd, 1024);
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen i_stream_seek(input, file->size);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen p = strstr(line, TEST_LOG_MSG_PREFIX);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (p == NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen p += strlen(TEST_LOG_MSG_PREFIX);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* <type> log */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen T_BEGIN {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (log_type_find(t_strcut(p, ' '), &type))
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->mask |= 1 << type;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } T_END;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_stream_destroy(&input);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void cmd_log_find_syslog_messages(struct log_find_context *ctx)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct hash_iterate_context *iter;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct stat st;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen char *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct log_find_file *file;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen iter = hash_table_iterate_init(ctx->files);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, ctx->files, &key, &file)) {
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen if (stat(file->path, &st) < 0 ||
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (uoff_t)st.st_size <= file->size)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_syslog_file_messages(file);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hash_table_iterate_deinit(&iter);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainencmd_log_find_syslog(struct log_find_context *ctx, int argc, char *argv[])
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *log_dir;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct stat st;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (argc > 1)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen log_dir = argv[1];
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen else if (stat("/var/log", &st) == 0 && S_ISDIR(st.st_mode))
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen log_dir = "/var/log";
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen else if (stat("/var/adm", &st) == 0 && S_ISDIR(st.st_mode))
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen log_dir = "/var/adm";
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen else
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen printf("Looking for log files from %s\n", log_dir);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_syslog_files(ctx, log_dir);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_test(0, NULL);
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen /* give syslog some time to write the messages to files */
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen sleep(1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_syslog_messages(ctx);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstatic void cmd_log_find(int argc, char *argv[])
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const struct master_service_settings *set;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const char *log_file_path;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct log_find_context ctx;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx.pool = pool_alloconly_create("log file", 1024*32);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&ctx.files, ctx.pool, 0, str_hash, strcmp);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* first get the paths that we know are used */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen set = master_service_settings_get(master_service);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen log_file_path = set->log_path;
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen if (strcmp(log_file_path, "syslog") == 0)
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen log_file_path = "";
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen if (*log_file_path != '\0') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_WARNING);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_ERROR);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_FATAL);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(set->info_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (*set->info_log_path != '\0')
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen log_file_path = set->info_log_path;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (*log_file_path != '\0')
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_INFO);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(set->debug_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (*set->debug_log_path != '\0')
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen log_file_path = set->debug_log_path;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (*log_file_path != '\0')
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_DEBUG);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (*set->log_path == '\0' ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(set->log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(set->info_log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(set->debug_log_path, "syslog") == 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* at least some logs were logged via syslog */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen cmd_log_find_syslog(&ctx, argc, argv);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* print them */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = 0; i < LAST_LOG_TYPE; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen char *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct log_find_file *file;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen bool found = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen iter = hash_table_iterate_init(ctx.files);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, ctx.files, &key, &file)) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if ((file->mask & (1 << i)) != 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen printf("%s%s\n", failure_log_type_prefixes[i],
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen file->path);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen found = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hash_table_iterate_deinit(&iter);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (!found)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen printf("%sNot found\n", failure_log_type_prefixes[i]);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomistatic const char *t_cmd_log_error_trim(const char *orig)
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi{
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t pos;
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen /* Trim whitespace from suffix and remove ':' if it exists */
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen for (pos = strlen(orig); pos > 0; pos--) {
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen if (orig[pos-1] != ' ') {
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen if (orig[pos-1] == ':')
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen pos--;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi break;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi }
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi }
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen return orig[pos] == '\0' ? orig : t_strndup(orig, pos);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi}
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainenstatic void cmd_log_error_write(const char *const *args, time_t min_timestamp)
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen{
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* <type> <timestamp> <prefix> <text> */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen const char *type_prefix = "?";
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen unsigned int type;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen time_t t;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* find type's prefix */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen for (type = 0; type < LOG_TYPE_COUNT; type++) {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (strcmp(args[0], failure_log_type_names[type]) == 0) {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen type_prefix = failure_log_type_prefixes[type];
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen break;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (str_to_time(args[1], &t) < 0) {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_error("Invalid timestamp: %s", args[1]);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen t = 0;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (t >= min_timestamp) {
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print(t_strflocaltime(LOG_TIMESTAMP_FORMAT, t));
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print(t_cmd_log_error_trim(args[2]));
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print(t_cmd_log_error_trim(type_prefix));
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print(args[3]);
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen}
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainenstatic void cmd_log_errors(int argc, char *argv[])
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen{
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen struct istream *input;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen const char *path, *line, *const *args;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen time_t min_timestamp = 0;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen int c, fd;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen while ((c = getopt(argc, argv, "s:")) > 0) {
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen switch (c) {
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen case 's':
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (str_to_time(optarg, &min_timestamp) < 0)
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen i_fatal("Invalid timestamp: %s", optarg);
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen break;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen default:
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen help(&doveadm_cmd_log[3]);
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen argv += optind - 1;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (argv[1] != NULL)
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen help(&doveadm_cmd_log[3]);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen path = t_strconcat(doveadm_settings->base_dir,
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen "/"LOG_ERRORS_FNAME, NULL);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen fd = net_connect_unix(path);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (fd == -1)
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_fatal("net_connect_unix(%s) failed: %m", path);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen net_set_nonblock(fd, FALSE);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_formatted_set_format("%{timestamp} %{type}: %{prefix}: %{text}\n");
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_header_simple("timestamp");
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_header_simple("prefix");
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_header_simple("type");
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi doveadm_print_header_simple("text");
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen args = t_strsplit_tabescaped(line);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (str_array_length(args) == 4)
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen cmd_log_error_write(args, min_timestamp);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen else {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_error("Invalid input from log: %s", line);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen doveadm_exit_code = EX_PROTOCOL;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen } T_END;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_stream_destroy(&input);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen}
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstruct doveadm_cmd doveadm_cmd_log[] = {
bde78a7bf5f9000f1ae4dc7ce6cabd012e1f8b79Pascal Volk { cmd_log_test, "log test", "" },
bde78a7bf5f9000f1ae4dc7ce6cabd012e1f8b79Pascal Volk { cmd_log_reopen, "log reopen", "" },
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen { cmd_log_find, "log find", "[<dir>]" },
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi};
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomistruct doveadm_cmd_ver2 doveadm_cmd_log_errors_ver2 = {
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi .name = "log errors",
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi .usage = "[-s <min_timestamp>]",
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi .old_cmd = cmd_log_errors,
0ed5452f5fcff082087622e473d790403f66a0e2Aki TuomiDOVEADM_CMD_PARAMS_START
0ed5452f5fcff082087622e473d790403f66a0e2Aki TuomiDOVEADM_CMD_PARAM('s', "since", CMD_PARAM_STR, 0)
0ed5452f5fcff082087622e473d790403f66a0e2Aki TuomiDOVEADM_CMD_PARAMS_END
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen};
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenvoid doveadm_register_log_commands(void)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi doveadm_cmd_register_ver2(&doveadm_cmd_log_errors_ver2);
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_log); i++)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen doveadm_register_cmd(&doveadm_cmd_log[i]);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}