From: Timo Sirainen Date: Fri, 28 May 2010 14:15:10 +0000 (+0100) Subject: doveadm: Added log test|reopen|find commands. X-Git-Tag: 2.0.beta6~114 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bf333c7645b8ddb6eedd6834db2fd908888793e1;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Added log test|reopen|find commands. --HG-- branch : HEAD --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 086d997380..68cd2e8b99 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -52,6 +52,7 @@ doveadm_SOURCES = \ doveadm-dump-mailboxlog.c \ doveadm-dump-thread.c \ doveadm-kick.c \ + doveadm-log.c \ doveadm-master.c \ doveadm-mail.c \ doveadm-mail-altmove.c \ diff --git a/src/doveadm/doveadm-log.c b/src/doveadm/doveadm-log.c new file mode 100644 index 0000000000..fd9855e356 --- /dev/null +++ b/src/doveadm/doveadm-log.c @@ -0,0 +1,269 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "hash.h" +#include "str.h" +#include "istream.h" +#include "master-service-private.h" +#include "master-service-settings.h" +#include "doveadm.h" + +#include +#include +#include +#include +#include +#include + +#define LAST_LOG_TYPE LOG_TYPE_PANIC +#define TEST_LOG_MSG_PREFIX "This is Dovecot's " + +static void cmd_log_test(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED) +{ + unsigned int i; + + master_service->flags |= MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR; + master_service_init_log(master_service, "doveadm: "); + + for (i = 0; i < LAST_LOG_TYPE; i++) { + const char *prefix = failure_log_type_prefixes[i]; + + i_log_type(i, TEST_LOG_MSG_PREFIX"%s log", + t_str_lcase(t_strcut(prefix, ':'))); + } +} + +static void cmd_log_reopen(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED) +{ + doveadm_master_send_signal(SIGUSR1); +} + +struct log_find_file { + const char *path; + uoff_t size; + + /* 1 << enum log_type */ + unsigned int mask; +}; + +struct log_find_context { + pool_t pool; + struct hash_table *files; +}; + +static void cmd_log_find_add(struct log_find_context *ctx, + const char *path, enum log_type type) +{ + struct log_find_file *file; + char *key; + + file = hash_table_lookup(ctx->files, path); + if (file == NULL) { + file = p_new(ctx->pool, struct log_find_file, 1); + file->path = key = p_strdup(ctx->pool, path); + hash_table_insert(ctx->files, key, file); + } + + file->mask |= 1 << type; +} + +static void +cmd_log_find_syslog_files(struct log_find_context *ctx, const char *path) +{ + struct log_find_file *file; + DIR *dir; + struct dirent *d; + struct stat st; + char *key; + string_t *full_path; + unsigned int dir_len; + + dir = opendir(path); + if (dir == NULL) { + i_error("opendir(%s) failed: %m", path); + return; + } + + full_path = t_str_new(256); + str_append(full_path, path); + str_append_c(full_path, '/'); + dir_len = str_len(full_path); + + while ((d = readdir(dir)) != NULL) { + if (d->d_name[0] == '.') + continue; + + str_truncate(full_path, dir_len); + str_append(full_path, d->d_name); + if (stat(str_c(full_path), &st) < 0) + continue; + + if (S_ISDIR(st.st_mode)) { + /* recursively go through all subdirectories */ + cmd_log_find_syslog_files(ctx, str_c(full_path)); + } else { + file = p_new(ctx->pool, struct log_find_file, 1); + file->size = st.st_size; + file->path = key = + p_strdup(ctx->pool, str_c(full_path)); + hash_table_insert(ctx->files, key, file); + } + } + + (void)closedir(dir); +} + +static bool log_type_find(const char *str, enum log_type *type_r) +{ + unsigned int i, len = strlen(str); + + for (i = 0; i < LAST_LOG_TYPE; i++) { + if (strncasecmp(str, failure_log_type_prefixes[i], len) == 0 && + failure_log_type_prefixes[i][len] == ':') { + *type_r = i; + return TRUE; + } + } + return FALSE; +} + +static void cmd_log_find_syslog_file_messages(struct log_find_file *file) +{ + struct istream *input; + const char *line, *p; + enum log_type type; + int fd; + + fd = open(file->path, O_RDONLY); + if (fd == -1) + return; + input = i_stream_create_fd(fd, 1024, TRUE); + while ((line = i_stream_read_next_line(input)) != NULL) { + p = strstr(line, TEST_LOG_MSG_PREFIX); + if (p == NULL) + continue; + p += strlen(TEST_LOG_MSG_PREFIX); + + /* log */ + T_BEGIN { + if (log_type_find(t_strcut(p, ' '), &type)) + file->mask |= 1 << type; + } T_END; + } + i_stream_destroy(&input); +} + +static void cmd_log_find_syslog_messages(struct log_find_context *ctx) +{ + struct hash_iterate_context *iter; + struct stat st; + void *key, *value; + + iter = hash_table_iterate_init(ctx->files); + while (hash_table_iterate(iter, &key, &value)) { + struct log_find_file *file = value; + + if (file->mask != 0 || + stat(file->path, &st) < 0 || + (uoff_t)st.st_size <= file->size) + continue; + + cmd_log_find_syslog_file_messages(file); + } + hash_table_iterate_deinit(&iter); +} + +static void +cmd_log_find_syslog(struct log_find_context *ctx, int argc, char *argv[]) +{ + const char *log_dir; + struct stat st; + + if (argc > 1) + log_dir = argv[1]; + else if (stat("/var/log", &st) == 0 && S_ISDIR(st.st_mode)) + log_dir = "/var/log"; + else if (stat("/var/adm", &st) == 0 && S_ISDIR(st.st_mode)) + log_dir = "/var/adm"; + else + return; + + printf("Looking for log files from %s\n", log_dir); + cmd_log_find_syslog_files(ctx, log_dir); + cmd_log_test(0, NULL); + cmd_log_find_syslog_messages(ctx); +} + +static void cmd_log_find(int argc, char *argv[]) +{ + const struct master_service_settings *set; + const char *log_file_path; + struct log_find_context ctx; + unsigned int i; + + memset(&ctx, 0, sizeof(ctx)); + ctx.pool = pool_alloconly_create("log file", 1024*32); + ctx.files = hash_table_create(default_pool, ctx.pool, 0, + str_hash, (hash_cmp_callback_t *)strcmp); + + /* first get the paths that we know are used */ + set = master_service_settings_get(master_service); + log_file_path = set->log_path; + if (*log_file_path != '\0') { + cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_WARNING); + cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_ERROR); + cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_FATAL); + } + + if (*set->info_log_path != '\0') + log_file_path = set->info_log_path; + if (*log_file_path != '\0') + cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_INFO); + + if (*set->debug_log_path != '\0') + log_file_path = set->debug_log_path; + if (*log_file_path != '\0') + cmd_log_find_add(&ctx, log_file_path, LOG_TYPE_DEBUG); + + if (*set->log_path == '\0') { + /* at least some logs were logged via syslog */ + cmd_log_find_syslog(&ctx, argc, argv); + } + + /* print them */ + for (i = 0; i < LAST_LOG_TYPE; i++) { + struct hash_iterate_context *iter; + void *key, *value; + bool found = FALSE; + + iter = hash_table_iterate_init(ctx.files); + while (hash_table_iterate(iter, &key, &value)) { + struct log_find_file *file = value; + + if ((file->mask & (1 << i)) != 0) { + printf("%s%s\n", failure_log_type_prefixes[i], + file->path); + found = TRUE; + } + } + hash_table_iterate_deinit(&iter); + + if (!found) + printf("%sNot found\n", failure_log_type_prefixes[i]); + } +} + +struct doveadm_cmd doveadm_cmd_log[] = { + { cmd_log_test, "log test", "", NULL }, + { cmd_log_reopen, "log reopen", "", NULL }, + { cmd_log_find, "log find", "[]", NULL } +}; + +void doveadm_register_log_commands(void) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(doveadm_cmd_log); i++) + doveadm_register_cmd(&doveadm_cmd_log[i]); +} diff --git a/src/doveadm/doveadm-master.c b/src/doveadm/doveadm-master.c index b56bd275a6..639ae02d12 100644 --- a/src/doveadm/doveadm-master.c +++ b/src/doveadm/doveadm-master.c @@ -45,7 +45,7 @@ static bool pid_file_read(const char *path, pid_t *pid_r) return found; } -static void send_master_signal(int signo) +void doveadm_master_send_signal(int signo) { const char *pidfile_path; unsigned int i; @@ -76,12 +76,12 @@ static void send_master_signal(int signo) static void cmd_stop(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED) { - send_master_signal(SIGTERM); + doveadm_master_send_signal(SIGTERM); } static void cmd_reload(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED) { - send_master_signal(SIGHUP); + doveadm_master_send_signal(SIGHUP); } struct doveadm_cmd doveadm_cmd_stop = { diff --git a/src/doveadm/doveadm.c b/src/doveadm/doveadm.c index 3b5b5bf172..cc8f3aa0b0 100644 --- a/src/doveadm/doveadm.c +++ b/src/doveadm/doveadm.c @@ -234,6 +234,7 @@ int main(int argc, char *argv[]) for (i = 0; i < N_ELEMENTS(doveadm_commands); i++) doveadm_register_cmd(doveadm_commands[i]); doveadm_register_director_commands(); + doveadm_register_log_commands(); doveadm_mail_init(); doveadm_load_modules(); diff --git a/src/doveadm/doveadm.h b/src/doveadm/doveadm.h index 4f7e452472..a51fd2c563 100644 --- a/src/doveadm/doveadm.h +++ b/src/doveadm/doveadm.h @@ -34,6 +34,9 @@ void help(const struct doveadm_cmd *cmd); const char *unixdate2str(time_t timestamp); const char *doveadm_plugin_getenv(const char *name); +void doveadm_master_send_signal(int signo); + void doveadm_register_director_commands(void); +void doveadm_register_log_commands(void); #endif