Mercurial > dovecot > core-2.2
changeset 10007:c862648185b8 HEAD
util/*view binaries are now accessed via "doveadm dump".
listview binary stays for now, since mailbox list indexes won't work
anyway and they might get a complete redesign.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 08 Oct 2009 20:43:25 -0400 |
parents | a425ba46a64c |
children | a15182f41f30 |
files | .hgignore src/doveadm/Makefile.am src/doveadm/doveadm-dump-index.c src/doveadm/doveadm-dump-log.c src/doveadm/doveadm-dump-mailboxlog.c src/doveadm/doveadm-dump-thread.c src/doveadm/doveadm-dump.c src/doveadm/doveadm-dump.h src/doveadm/doveadm.c src/doveadm/doveadm.h src/util/Makefile.am src/util/idxview.c src/util/logview.c src/util/mailboxlogview.c src/util/threadview.c |
diffstat | 15 files changed, 1399 insertions(+), 1300 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Oct 08 20:10:49 2009 -0400 +++ b/.hgignore Thu Oct 08 20:43:25 2009 -0400 @@ -79,14 +79,10 @@ src/pop3-login/pop3-login src/pop3/pop3 src/util/gdbhelper -src/util/idxview src/util/imap-utf7 src/util/listview -src/util/logview -src/util/mailboxlogview src/util/maildirlock src/util/rawlog -src/util/threadview src/plugins/quota/rquota_xdr.c src/plugins/quota/rquota.h
--- a/src/doveadm/Makefile.am Thu Oct 08 20:10:49 2009 -0400 +++ b/src/doveadm/Makefile.am Thu Oct 08 20:43:25 2009 -0400 @@ -30,8 +30,14 @@ doveadm_SOURCES = \ doveadm.c \ doveadm-auth.c \ + doveadm-dump.c \ + doveadm-dump-index.c \ + doveadm-dump-log.c \ + doveadm-dump-mailboxlog.c \ + doveadm-dump-thread.c \ doveadm-mail.c \ doveadm-pw.c noinst_HEADERS = \ + doveadm-dump.h \ doveadm-mail.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump-index.c Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,531 @@ +/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "hex-binary.h" +#include "file-lock.h" +#include "mail-index-private.h" +#include "mail-cache-private.h" +#include "mail-cache-private.h" +#include "mail-index-modseq.h" +#include "doveadm-dump.h" + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +struct maildir_index_header { + uint32_t new_check_time, new_mtime, new_mtime_nsecs; + uint32_t cur_check_time, cur_mtime, cur_mtime_nsecs; + uint32_t uidlist_mtime, uidlist_mtime_nsecs, uidlist_size; +}; +struct mbox_index_header { + uint64_t sync_size; + uint32_t sync_mtime; + uint8_t dirty_flag; + uint8_t unused[3]; + uint8_t mailbox_guid[16]; +}; +struct dbox_index_header { + uint32_t map_uid_validity; + uint32_t highest_maildir_uid; + uint8_t mailbox_guid[16]; +}; +struct dbox_mail_index_record { + uint32_t map_uid; + uint32_t save_date; +}; + +struct virtual_mail_index_record { + uint32_t mailbox_id; + uint32_t real_uid; +}; + +struct dbox_mail_index_map_record { + uint32_t file_id; + uint32_t offset; + uint32_t size; +}; + +static const char *unixdate2str(time_t timestamp) +{ + static char buf[64]; + struct tm *tm; + + tm = localtime(×tamp); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); + return buf; +} + +static void dump_hdr(struct mail_index *index) +{ + const struct mail_index_header *hdr = &index->map->hdr; + unsigned int i; + + printf("version .................. = %u.%u\n", hdr->major_version, hdr->minor_version); + printf("base header size ......... = %u\n", hdr->base_header_size); + printf("header size .............. = %u\n", hdr->header_size); + printf("record size .............. = %u\n", hdr->record_size); + printf("compat flags ............. = %u\n", hdr->compat_flags); + printf("index id ................. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid)); + printf("flags .................... = %u\n", hdr->flags); + printf("uid validity ............. = %u (%s)\n", hdr->uid_validity, unixdate2str(hdr->uid_validity)); + printf("next uid ................. = %u\n", hdr->next_uid); + printf("messages count ........... = %u\n", hdr->messages_count); + printf("seen messages count ...... = %u\n", hdr->seen_messages_count); + printf("deleted messages count ... = %u\n", hdr->deleted_messages_count); + printf("first recent uid ......... = %u\n", hdr->first_recent_uid); + printf("first unseen uid lowwater = %u\n", hdr->first_unseen_uid_lowwater); + printf("first deleted uid lowwater = %u\n", hdr->first_deleted_uid_lowwater); + printf("log file seq ............. = %u\n", hdr->log_file_seq); + if (hdr->minor_version == 0) { + printf("log file int offset ...... = %u\n", hdr->log_file_tail_offset); + printf("log file ext offset ...... = %u\n", hdr->log_file_head_offset); + } else { + printf("log file tail offset ..... = %u\n", hdr->log_file_tail_offset); + printf("log file head offset ..... = %u\n", hdr->log_file_head_offset); + } + printf("sync size ................ = %llu\n", (unsigned long long)hdr->sync_size); + printf("sync stamp ............... = %u (%s)\n", hdr->sync_stamp, unixdate2str(hdr->sync_stamp)); + printf("day stamp ................ = %u (%s)\n", hdr->day_stamp, unixdate2str(hdr->day_stamp)); + for (i = 0; i < N_ELEMENTS(hdr->day_first_uid); i++) + printf("day first uid[%u] ......... = %u\n", i, hdr->day_first_uid[i]); +} + +static void dump_extension_header(struct mail_index *index, + const struct mail_index_ext *ext) +{ + const void *data; + + if (strcmp(ext->name, MAIL_INDEX_EXT_KEYWORDS) == 0) + return; + + data = CONST_PTR_OFFSET(index->map->hdr_base, ext->hdr_offset); + if (strcmp(ext->name, "maildir") == 0) { + const struct maildir_index_header *hdr = data; + + printf("header\n"); + printf(" - new_check_time .... = %s\n", unixdate2str(hdr->new_check_time)); + printf(" - new_mtime ......... = %s\n", unixdate2str(hdr->new_mtime)); + printf(" - new_mtime_nsecs ... = %u\n", hdr->new_mtime_nsecs); + printf(" - cur_check_time .... = %s\n", unixdate2str(hdr->cur_check_time)); + printf(" - cur_mtime ......... = %s\n", unixdate2str(hdr->cur_mtime)); + printf(" - cur_mtime_nsecs.... = %u\n", hdr->cur_mtime_nsecs); + printf(" - uidlist_mtime ..... = %s\n", unixdate2str(hdr->uidlist_mtime)); + printf(" - uidlist_mtime_nsecs = %u\n", hdr->uidlist_mtime_nsecs); + printf(" - uidlist_size ...... = %u\n", hdr->uidlist_size); + } else if (strcmp(ext->name, "mbox") == 0) { + const struct mbox_index_header *hdr = data; + + printf("header\n"); + printf(" - sync_mtime . = %s\n", unixdate2str(hdr->sync_mtime)); + printf(" - sync_size .. = %llu\n", + (unsigned long long)hdr->sync_size); + printf(" - dirty_flag . = %d\n", hdr->dirty_flag); + printf(" - mailbox_guid = %s\n", + binary_to_hex(hdr->mailbox_guid, + sizeof(hdr->mailbox_guid))); + } else if (strcmp(ext->name, "dbox-hdr") == 0) { + const struct dbox_index_header *hdr = data; + + printf("header\n"); + printf(" - map_uid_validity .. = %u\n", hdr->map_uid_validity); + printf(" - highest_maildir_uid = %u\n", hdr->highest_maildir_uid); + printf(" - mailbox_guid ...... = %s\n", + binary_to_hex(hdr->mailbox_guid, + sizeof(hdr->mailbox_guid))); + } else if (strcmp(ext->name, "modseq") == 0) { + const struct mail_index_modseq_header *hdr = data; + + printf("header\n"); + printf(" - highest_modseq = %llu\n", + (unsigned long long)hdr->highest_modseq); + printf(" - log_seq ...... = %u\n", hdr->log_seq); + printf(" - log_offset ... = %u\n", hdr->log_offset); + } else { + printf("header ........ = %s\n", + binary_to_hex(data, ext->hdr_size)); + } +} + +static void dump_extensions(struct mail_index *index) +{ + const struct mail_index_ext *extensions; + unsigned int i, count; + + if (array_is_created(&index->map->extensions)) + extensions = array_get(&index->map->extensions, &count); + else + count = 0; + if (count == 0) { + printf("no extensions\n"); + return; + } + + for (i = 0; i < count; i++) { + const struct mail_index_ext *ext = &extensions[i]; + + printf("-- Extension %u --\n", i); + printf("name ........ = %s\n", ext->name); + printf("hdr_size .... = %u\n", ext->hdr_size); + printf("reset_id .... = %u\n", ext->reset_id); + printf("record_offset = %u\n", ext->record_offset); + printf("record_size . = %u\n", ext->record_size); + printf("record_align = %u\n", ext->record_align); + if (ext->hdr_size > 0) + dump_extension_header(index, ext); + } +} + +static void dump_keywords(struct mail_index *index) +{ + const unsigned int *kw_indexes; + const char *const *keywords; + unsigned int i, count; + + printf("-- Keywords --\n"); + if (!array_is_created(&index->map->keyword_idx_map)) + return; + + kw_indexes = array_get(&index->map->keyword_idx_map, &count); + if (count == 0) + return; + + keywords = array_idx(&index->keywords, 0); + for (i = 0; i < count; i++) + printf("%3u = %s\n", i, keywords[kw_indexes[i]]); +} + +static const char *cache_decision2str(enum mail_cache_decision_type type) +{ + const char *str; + + switch (type & ~MAIL_CACHE_DECISION_FORCED) { + case MAIL_CACHE_DECISION_NO: + str = "no"; + break; + case MAIL_CACHE_DECISION_TEMP: + str = "tmp"; + break; + case MAIL_CACHE_DECISION_YES: + str = "yes"; + break; + default: + return t_strdup_printf("0x%x", type); + } + + if ((type & MAIL_CACHE_DECISION_FORCED) != 0) + str = t_strconcat(str, "!", NULL); + return str; +} + +#define CACHE_TYPE_IS_FIXED_SIZE(type) \ + ((type) == MAIL_CACHE_FIELD_FIXED_SIZE || \ + (type) == MAIL_CACHE_FIELD_BITMASK) +static const char *cache_type2str(enum mail_cache_field_type type) +{ + switch (type) { + case MAIL_CACHE_FIELD_FIXED_SIZE: + return "fix"; + case MAIL_CACHE_FIELD_VARIABLE_SIZE: + return "var"; + case MAIL_CACHE_FIELD_STRING: + return "str"; + case MAIL_CACHE_FIELD_BITMASK: + return "bit"; + case MAIL_CACHE_FIELD_HEADER: + return "hdr"; + default: + return t_strdup_printf("0x%x", type); + } +} + +static void dump_cache_hdr(struct mail_cache *cache) +{ + const struct mail_cache_header *hdr; + const struct mail_cache_field *fields, *field; + unsigned int i, count, cache_idx; + + (void)mail_cache_open_and_verify(cache); + if (MAIL_CACHE_IS_UNUSABLE(cache)) { + printf("cache is unusable\n"); + return; + } + + hdr = cache->hdr; + printf("version .............. = %u\n", hdr->version); + printf("indexid .............. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid)); + printf("file_seq ............. = %u (%s) (%d compressions)\n", + hdr->file_seq, unixdate2str(hdr->file_seq), + hdr->file_seq - hdr->indexid); + printf("continued_record_count = %u\n", hdr->continued_record_count); + printf("hole_offset .......... = %u\n", hdr->hole_offset); + printf("used_file_size ....... = %u\n", hdr->used_file_size); + printf("deleted_space ........ = %u\n", hdr->deleted_space); + printf("field_header_offset .. = %u (0x%08x nontranslated)\n", + mail_index_offset_to_uint32(hdr->field_header_offset), + hdr->field_header_offset); + + printf("-- Cache fields --\n"); + fields = mail_cache_register_get_list(cache, pool_datastack_create(), + &count); + printf( +" # Name Type Size Dec Last used\n"); + for (i = 0; i < cache->file_fields_count; i++) { + cache_idx = cache->file_field_map[i]; + field = &fields[cache_idx]; + + printf("%2u: %-44s %-4s ", i, field->name, + cache_type2str(field->type)); + if (field->field_size != (uint32_t)-1 || + CACHE_TYPE_IS_FIXED_SIZE(field->type)) + printf("%4u ", field->field_size); + else + printf(" - "); + printf("%-4s %.16s\n", + cache_decision2str(field->decision), + unixdate2str(cache->fields[cache_idx].last_used)); + } +} + +static void dump_cache(struct mail_cache_view *cache_view, unsigned int seq) +{ + struct mail_cache_lookup_iterate_ctx iter; + const struct mail_cache_record *prev_rec = NULL; + const struct mail_cache_field *field; + struct mail_cache_iterate_field iter_field; + const void *data; + unsigned int size; + string_t *str; + int ret; + + str = t_str_new(512); + mail_cache_lookup_iter_init(cache_view, seq, &iter); + while ((ret = mail_cache_lookup_iter_next(&iter, &iter_field)) > 0) { + if (iter.rec != prev_rec) { + printf(" - cache offset=%u size=%u, prev_offset = %u\n", + iter.offset, iter.rec->size, + iter.rec->prev_offset); + prev_rec = iter.rec; + } + + field = &cache_view->cache->fields[iter_field.field_idx].field; + data = iter_field.data; + size = iter_field.size; + + str_truncate(str, 0); + str_printfa(str, " - %s: ", field->name); + switch (field->type) { + case MAIL_CACHE_FIELD_FIXED_SIZE: + if (size == sizeof(uint32_t)) + str_printfa(str, "%u ", *((const uint32_t *)data)); + else if (size == sizeof(uint64_t)) + str_printfa(str, "%llu ", (unsigned long long)*((const uint64_t *)data)); + case MAIL_CACHE_FIELD_VARIABLE_SIZE: + case MAIL_CACHE_FIELD_BITMASK: + str_printfa(str, "(%s)", binary_to_hex(data, size)); + break; + case MAIL_CACHE_FIELD_STRING: + if (size > 0) + str_printfa(str, "%.*s", (int)size, (const char *)data); + break; + case MAIL_CACHE_FIELD_HEADER: { + const uint32_t *lines = data; + int i; + + for (i = 0;; i++) { + if (size < sizeof(uint32_t)) { + if (i == 0 && size == 0) { + /* header doesn't exist */ + break; + } + + str_append(str, "\n - BROKEN: header field doesn't end with 0 line"); + size = 0; + break; + } + + size -= sizeof(uint32_t); + data = CONST_PTR_OFFSET(data, sizeof(uint32_t)); + if (lines[i] == 0) + break; + + if (i > 0) + str_append(str, ", "); + str_printfa(str, "%u", lines[i]); + } + + if (i == 1 && size > 0 && + ((const char *)data)[size-1] == '\n') + size--; + if (size > 0) + str_printfa(str, ": %.*s", (int)size, (const char *)data); + break; + } + case MAIL_CACHE_FIELD_COUNT: + i_unreached(); + break; + } + + printf("%s\n", str_c(str)); + } + if (ret < 0) + printf(" - broken cache\n"); +} + +static const char *flags2str(enum mail_flags flags) +{ + string_t *str; + + str = t_str_new(64); + str_append_c(str, '('); + if ((flags & MAIL_SEEN) != 0) + str_append(str, "Seen "); + if ((flags & MAIL_ANSWERED) != 0) + str_append(str, "Answered "); + if ((flags & MAIL_FLAGGED) != 0) + str_append(str, "Flagged "); + if ((flags & MAIL_DELETED) != 0) + str_append(str, "Deleted "); + if ((flags & MAIL_DRAFT) != 0) + str_append(str, "Draft "); + if (str_len(str) == 1) + return ""; + + str_truncate(str, str_len(str)-1); + str_append_c(str, ')'); + return str_c(str); +} + +static void dump_record(struct mail_index_view *view, unsigned int seq) +{ + struct mail_index *index = mail_index_view_get_index(view); + const struct mail_index_record *rec; + const struct mail_index_registered_ext *ext; + const void *data; + unsigned int i, ext_count; + string_t *str; + bool expunged; + + rec = mail_index_lookup(view, seq); + printf("RECORD: seq=%u, uid=%u, flags=0x%02x %s\n", + seq, rec->uid, rec->flags, flags2str(rec->flags)); + + str = t_str_new(256); + ext = array_get(&index->extensions, &ext_count); + for (i = 0; i < ext_count; i++) { + mail_index_lookup_ext(view, seq, i, &data, &expunged); + if (data == NULL || ext[i].record_size == 0) + continue; + + str_truncate(str, 0); + str_printfa(str, " - ext %d %-10s: ", i, ext[i].name); + if (ext[i].record_size == sizeof(uint16_t) && + ext[i].record_align == sizeof(uint16_t)) + str_printfa(str, "%10u", *((const uint16_t *)data)); + else if (ext[i].record_size == sizeof(uint32_t) && + ext[i].record_align == sizeof(uint32_t)) + str_printfa(str, "%10u", *((const uint32_t *)data)); + else if (ext[i].record_size == sizeof(uint64_t) && + ext[i].record_align == sizeof(uint64_t)) { + uint64_t value = *((const uint64_t *)data); + str_printfa(str, "%10llu", (unsigned long long)value); + } else { + str_append(str, " "); + } + str_printfa(str, " (%s)", + binary_to_hex(data, ext[i].record_size)); + printf("%s\n", str_c(str)); + if (strcmp(ext[i].name, "virtual") == 0) { + const struct virtual_mail_index_record *vrec = data; + printf(" : mailbox_id = %u\n", vrec->mailbox_id); + printf(" : real_uid = %u\n", vrec->real_uid); + } else if (strcmp(ext[i].name, "map") == 0) { + const struct dbox_mail_index_map_record *mrec = data; + printf(" : file_id = %u\n", mrec->file_id); + printf(" : offset = %u\n", mrec->offset); + printf(" : size = %u\n", mrec->size); + } else if (strcmp(ext[i].name, "dbox") == 0) { + const struct dbox_mail_index_record *drec = data; + printf(" : map_uid = %u\n", drec->map_uid); + printf(" : save_date = %u (%s)\n", drec->save_date, unixdate2str(drec->save_date)); + } + } +} + +static void cmd_dump_index(int argc ATTR_UNUSED, char *argv[]) +{ + struct mail_index *index; + struct mail_index_view *view; + struct mail_cache_view *cache_view; + struct stat st; + const char *p; + unsigned int seq, uid = 0; + + if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) + index = mail_index_alloc(argv[1], "dovecot.index"); + else if ((p = strrchr(argv[1], '/')) != NULL) + index = mail_index_alloc(t_strdup_until(argv[1], p), p + 1); + else + index = mail_index_alloc(".", argv[1]); + if (mail_index_open(index, MAIL_INDEX_OPEN_FLAG_READONLY, + FILE_LOCK_METHOD_FCNTL) <= 0) + i_fatal("Couldn't open index %s", argv[1]); + if (argv[2] != NULL) + uid = atoi(argv[2]); + + view = mail_index_view_open(index); + cache_view = mail_cache_view_open(index->cache, view); + + if (uid == 0) { + printf("-- INDEX: %s\n", index->filepath); + dump_hdr(index); + dump_extensions(index); + dump_keywords(index); + + printf("\n-- CACHE: %s\n", index->cache->filepath); + dump_cache_hdr(index->cache); + + printf("\n-- RECORDS: %u\n", index->map->hdr.messages_count); + } + for (seq = 1; seq <= index->map->hdr.messages_count; seq++) { + if (uid == 0 || mail_index_lookup(view, seq)->uid == uid) { + T_BEGIN { + dump_record(view, seq); + dump_cache(cache_view, seq); + printf("\n"); + } T_END; + } + } + mail_cache_view_close(cache_view); + mail_index_view_close(&view); + mail_index_close(index); + mail_index_free(&index); +} + +static bool test_dump_index(const char *path) +{ + struct mail_index *index; + struct stat st; + const char *p; + bool ret; + + if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) + index = mail_index_alloc(path, "dovecot.index"); + else if ((p = strrchr(path, '/')) != NULL) + index = mail_index_alloc(t_strdup_until(path, p), p + 1); + else + index = mail_index_alloc(".", path); + + ret = mail_index_open(index, MAIL_INDEX_OPEN_FLAG_READONLY, + FILE_LOCK_METHOD_FCNTL) > 0; + mail_index_free(&index); + return ret; +} + +struct doveadm_cmd_dump doveadm_cmd_dump_index = { + "index", + test_dump_index, + cmd_dump_index +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump-log.c Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,505 @@ +/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hex-binary.h" +#include "mail-index-private.h" +#include "mail-transaction-log.h" +#include "doveadm-dump.h" + +#include <stdio.h> + +static struct mail_transaction_ext_intro prev_intro; + +static void dump_hdr(int fd, uint64_t *modseq_r) +{ + struct mail_transaction_log_header hdr; + ssize_t ret; + + ret = read(fd, &hdr, sizeof(hdr)); + if (ret != sizeof(hdr)) { + i_fatal("file hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T, + ret, sizeof(hdr)); + } + if (hdr.hdr_size < sizeof(hdr)) { + memset(PTR_OFFSET(&hdr, hdr.hdr_size), 0, + sizeof(hdr) - hdr.hdr_size); + } + lseek(fd, hdr.hdr_size, SEEK_SET); + + printf("version = %u.%u\n", hdr.major_version, hdr.minor_version); + printf("hdr size = %u\n", hdr.hdr_size); + printf("index id = %u\n", hdr.indexid); + printf("file seq = %u\n", hdr.file_seq); + printf("prev file = %u/%u\n", hdr.prev_file_seq, hdr.prev_file_offset); + printf("create stamp = %u\n", hdr.create_stamp); + printf("initial modseq = %llu\n", + (unsigned long long)hdr.initial_modseq); + printf("compat flags = %x\n", hdr.compat_flags); + *modseq_r = hdr.initial_modseq; +} + +static bool +mail_transaction_header_has_modseq(const struct mail_transaction_header *hdr) +{ + switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { + case MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT: + case MAIL_TRANSACTION_EXPUNGE_GUID | MAIL_TRANSACTION_EXPUNGE_PROT: + if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) { + /* ignore expunge requests */ + break; + } + case MAIL_TRANSACTION_APPEND: + case MAIL_TRANSACTION_FLAG_UPDATE: + case MAIL_TRANSACTION_KEYWORD_UPDATE: + case MAIL_TRANSACTION_KEYWORD_RESET: + case MAIL_TRANSACTION_UID_UPDATE: + /* these changes increase modseq */ + return TRUE; + } + return FALSE; +} + +static const char *log_record_type(unsigned int type) +{ + const char *name; + + switch (type & MAIL_TRANSACTION_TYPE_MASK) { + case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: + name = "expunge"; + break; + case MAIL_TRANSACTION_EXPUNGE_GUID|MAIL_TRANSACTION_EXPUNGE_PROT: + name = "expunge-guid"; + break; + case MAIL_TRANSACTION_APPEND: + name = "append"; + break; + case MAIL_TRANSACTION_FLAG_UPDATE: + name = "flag-update"; + break; + case MAIL_TRANSACTION_HEADER_UPDATE: + name = "header-update"; + break; + case MAIL_TRANSACTION_EXT_INTRO: + name = "ext-intro"; + break; + case MAIL_TRANSACTION_EXT_RESET: + name = "ext-reset"; + break; + case MAIL_TRANSACTION_EXT_HDR_UPDATE: + name = "ext-hdr"; + break; + case MAIL_TRANSACTION_EXT_REC_UPDATE: + name = "ext-rec"; + break; + case MAIL_TRANSACTION_KEYWORD_UPDATE: + name = "keyword-update"; + break; + case MAIL_TRANSACTION_KEYWORD_RESET: + name = "keyword-reset"; + break; + case MAIL_TRANSACTION_EXT_ATOMIC_INC: + name = "ext-atomic-inc"; + break; + case MAIL_TRANSACTION_UID_UPDATE: + name = "uid-update"; + break; + case MAIL_TRANSACTION_MODSEQ_UPDATE: + name = "modseq-update"; + break; + default: + name = t_strdup_printf("unknown: %x", type); + break; + } + + if (type & MAIL_TRANSACTION_EXTERNAL) + name = t_strconcat(name, " (ext)", NULL); + return name; +} + +static void print_data(const void *data, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + printf("%02x", ((const unsigned char *)data)[i]); + if (size == 4) { + const uint32_t *n = (const uint32_t *)data; + + printf(" (dec=%u)", *n); + } +} + +static void print_try_uint(const void *data, size_t size) +{ + size_t i; + + switch (size) { + case 1: { + const uint8_t *n = data; + printf("%u", *n); + break; + } + case 2: { + const uint16_t *n = data; + uint32_t n16; + + memcpy(&n16, n, sizeof(n16)); + printf("%u", n16); + break; + } + case 4: { + const uint32_t *n = data; + uint32_t n32; + + memcpy(&n32, n, sizeof(n32)); + printf("%u", n32); + break; + } + case 8: { + const uint64_t *n = data; + uint64_t n64; + + memcpy(&n64, n, sizeof(n64)); + printf("%llu", (unsigned long long)n64); + break; + } + default: + for (i = 0; i < size; i++) + printf("%02x", ((const unsigned char *)data)[i]); + } +} + +#define HDRF(field) { \ + #field, offsetof(struct mail_index_header, field), \ + sizeof(((struct mail_index_header *)0)->field) } + +static struct { + const char *name; + unsigned int offset, size; +} header_fields[] = { + HDRF(minor_version), + HDRF(base_header_size), + HDRF(header_size), + HDRF(record_size), + HDRF(compat_flags), + HDRF(indexid), + HDRF(flags), + HDRF(uid_validity), + HDRF(next_uid), + HDRF(messages_count), + HDRF(unused_old_recent_messages_count), + HDRF(seen_messages_count), + HDRF(deleted_messages_count), + HDRF(first_recent_uid), + HDRF(first_unseen_uid_lowwater), + HDRF(first_deleted_uid_lowwater), + HDRF(log_file_seq), + HDRF(log_file_tail_offset), + HDRF(log_file_head_offset), + HDRF(sync_size), + HDRF(sync_stamp), + HDRF(day_stamp) +}; + +static void log_header_update(const struct mail_transaction_header_update *u) +{ + const void *data = u + 1; + unsigned int offset = u->offset, size = u->size; + unsigned int i; + + while (size > 0) { + /* don't bother trying to handle header updates that include + unknown/unexpected fields offsets/sizes */ + for (i = 0; i < N_ELEMENTS(header_fields); i++) { + if (header_fields[i].offset == offset && + header_fields[i].size <= size) + break; + } + + if (i == N_ELEMENTS(header_fields)) { + printf(" - offset = %u, size = %u: ", offset, size); + print_data(data, size); + printf("\n"); + break; + } + + printf(" - %s = ", header_fields[i].name); + print_try_uint(data, header_fields[i].size); + printf("\n"); + + data = CONST_PTR_OFFSET(data, header_fields[i].size); + offset += header_fields[i].size; + size -= header_fields[i].size; + } +} + +static void log_record_print(const struct mail_transaction_header *hdr, + const void *data, uint64_t *modseq) +{ + unsigned int size = hdr->size - sizeof(*hdr); + + switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { + case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: { + const struct mail_transaction_expunge *exp = data; + + printf(" -"); + for (; size > 0; size -= sizeof(*exp), exp++) { + printf(" %u-%u", exp->uid1, exp->uid2); + } + printf("\n"); + break; + } + case MAIL_TRANSACTION_EXPUNGE_GUID|MAIL_TRANSACTION_EXPUNGE_PROT: { + const struct mail_transaction_expunge_guid *exp = data; + + for (; size > 0; size -= sizeof(*exp), exp++) { + printf(" - %u (guid ", exp->uid); + print_data(exp->guid_128, sizeof(exp->guid_128)); + printf(")\n"); + } + break; + } + case MAIL_TRANSACTION_APPEND: { + const struct mail_index_record *rec = data; + + printf(" - "); + for (; size > 0; size -= sizeof(*rec), rec++) { + printf("%u", rec->uid); + if (rec->flags != 0) + printf(" (flags=%x)", rec->flags); + printf(","); + } + printf("\n"); + break; + } + case MAIL_TRANSACTION_FLAG_UPDATE: { + const struct mail_transaction_flag_update *u = data; + + for (; size > 0; size -= sizeof(*u), u++) { + printf(" - %u-%u (flags +%x-%x)\n", u->uid1, u->uid2, + u->add_flags, u->remove_flags); + } + break; + } + case MAIL_TRANSACTION_HEADER_UPDATE: { + const struct mail_transaction_header_update *u = data; + + log_header_update(u); + break; + } + case MAIL_TRANSACTION_EXT_INTRO: { + const struct mail_transaction_ext_intro *intro = data; + + prev_intro = *intro; + printf(" - ext_id = %u\n", intro->ext_id); + printf(" - reset_id = %u\n", intro->reset_id); + printf(" - hdr_size = %u\n", intro->hdr_size); + printf(" - record_size = %u\n", intro->record_size); + printf(" - record_align = %u\n", intro->record_align); + printf(" - flags = %u\n", intro->flags); + printf(" - name_size = %u\n", intro->name_size); + if (intro->name_size > 0) { + const char *name = (const char *)(intro+1); + + printf(" - name = '%.*s'\n", intro->name_size, name); + if (*modseq == 0 && intro->name_size == 6 && + memcmp(name, "modseq", 6) == 0) + *modseq = 1; + } + break; + } + case MAIL_TRANSACTION_EXT_RESET: { + const struct mail_transaction_ext_reset *reset = data; + + printf(" - new_reset_id = %u\n", reset->new_reset_id); + printf(" - preserve_data = %u\n", reset->preserve_data); + break; + } + case MAIL_TRANSACTION_EXT_HDR_UPDATE: { + const struct mail_transaction_ext_hdr_update *u = data; + + printf(" - offset = %u, size = %u: ", u->offset, u->size); + print_data(u + 1, u->size); + printf("\n"); + break; + } + case MAIL_TRANSACTION_EXT_REC_UPDATE: { + const struct mail_transaction_ext_rec_update *rec = data, *end; + size_t record_size; + + end = CONST_PTR_OFFSET(data, size); + record_size = (sizeof(*rec) + prev_intro.record_size + 3) & ~3; + while (rec < end) { + printf(" - %u: ", rec->uid); + print_data(rec + 1, prev_intro.record_size); + printf("\n"); + rec = CONST_PTR_OFFSET(rec, record_size); + } + break; + } + case MAIL_TRANSACTION_EXT_ATOMIC_INC: { + const struct mail_transaction_ext_atomic_inc *rec = data, *end; + + end = CONST_PTR_OFFSET(data, size); + for (; rec < end; rec++) { + printf(" - %u: ", rec->uid); + if (rec->diff > 0) + printf("+%d\n", rec->diff); + else + printf("%d\n", rec->diff); + } + break; + } + case MAIL_TRANSACTION_KEYWORD_UPDATE: { + const struct mail_transaction_keyword_update *u = data; + const uint32_t *uid; + unsigned int uid_offset; + + printf(" - modify=%d, name=%.*s, ", + u->modify_type, u->name_size, (const char *)(u+1)); + + uid_offset = sizeof(*u) + u->name_size + + ((u->name_size % 4) == 0 ? 0 : 4 - (u->name_size%4)); + uid = (const uint32_t *)((const char *)u + uid_offset); + size -= uid_offset; + + for (; size > 0; size -= sizeof(*uid)*2, uid += 2) { + printf("%u-%u,", uid[0], uid[1]); + } + printf("\n"); + break; + } + case MAIL_TRANSACTION_KEYWORD_RESET: { + const struct mail_transaction_keyword_reset *u = data; + + printf(" - "); + for (; size > 0; size -= sizeof(*u), u++) { + printf("%u-%u, ", u->uid1, u->uid2); + } + printf("\n"); + break; + } + case MAIL_TRANSACTION_UID_UPDATE: { + const struct mail_transaction_uid_update *rec = data, *end; + + end = CONST_PTR_OFFSET(data, size); + for (rec = data; rec < end; rec++) { + printf(" - old uid=%u new uid=%u\n", + rec->old_uid, rec->new_uid); + } + break; + } + case MAIL_TRANSACTION_MODSEQ_UPDATE: { + const struct mail_transaction_modseq_update *rec = data, *end; + + end = CONST_PTR_OFFSET(data, size); + for (rec = data; rec < end; rec++) { + printf(" - uid=%u modseq=%llu\n", rec->uid, + ((unsigned long long)rec->modseq_high32 << 32) | + rec->modseq_low32); + } + break; + } + default: + break; + } +} + +static int dump_record(int fd, uint64_t *modseq) +{ + off_t offset; + ssize_t ret; + struct mail_transaction_header hdr; + unsigned int orig_size; + + offset = lseek(fd, 0, SEEK_CUR); + + ret = read(fd, &hdr, sizeof(hdr)); + if (ret == 0) + return 0; + + if (ret != sizeof(hdr)) { + i_fatal("rec hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T, + ret, sizeof(hdr)); + } + + orig_size = hdr.size; + hdr.size = mail_index_offset_to_uint32(hdr.size); + if (hdr.size == 0) { + printf("record: offset=%"PRIuUOFF_T", " + "type=%s, size=broken (%x)\n", + offset, log_record_type(hdr.type), orig_size); + return 0; + } + + printf("record: offset=%"PRIuUOFF_T", type=%s, size=%u", + offset, log_record_type(hdr.type), hdr.size); + if (*modseq > 0 && mail_transaction_header_has_modseq(&hdr)) { + *modseq += 1; + printf(", modseq=%llu", (unsigned long long)*modseq); + } + printf("\n"); + + if (hdr.size < 1024*1024) { + unsigned char *buf = t_malloc(hdr.size); + + ret = read(fd, buf, hdr.size - sizeof(hdr)); + if (ret != (ssize_t)(hdr.size - sizeof(hdr))) { + i_fatal("rec data read() %"PRIuSIZE_T" != %"PRIuSIZE_T, + ret, hdr.size - sizeof(hdr)); + } + log_record_print(&hdr, buf, modseq); + } else { + lseek(fd, hdr.size - sizeof(hdr), SEEK_CUR); + } + return 1; +} + +static void cmd_dump_log(int argc ATTR_UNUSED, char *argv[]) +{ + uint64_t modseq; + int fd, ret; + + fd = open(argv[1], O_RDONLY); + if (fd < 0) + i_fatal("open(%s) failed: %m", argv[1]); + + dump_hdr(fd, &modseq); + do { + T_BEGIN { + ret = dump_record(fd, &modseq); + } T_END; + } while (ret > 0); +} + +static bool test_dump_log(const char *path) +{ + struct mail_transaction_log_header hdr; + const char *p; + bool ret = FALSE; + int fd; + + p = strrchr(path, '/'); + if (p == NULL) + return FALSE; + p = strstr(p, ".log"); + if (p == NULL || !(p[4] == '\0' || p[4] == '.')) + return FALSE; + + fd = open(path, O_RDONLY); + if (fd == -1) + return FALSE; + + if (read(fd, &hdr, sizeof(hdr)) >= MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE && + hdr.major_version == MAIL_TRANSACTION_LOG_MAJOR_VERSION && + hdr.hdr_size >= MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) + ret = TRUE; + (void)close(fd); + return ret; +} + +struct doveadm_cmd_dump doveadm_cmd_dump_log = { + "log", + test_dump_log, + cmd_dump_log +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump-mailboxlog.c Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,121 @@ +/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hex-binary.h" +#include "mailbox-log.h" +#include "doveadm-dump.h" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +static const char *unixdate2str(time_t timestamp) +{ + static char buf[64]; + struct tm *tm; + + tm = localtime(×tamp); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); + return buf; +} + +static int dump_record(int fd) +{ + off_t offset; + ssize_t ret; + struct mailbox_log_record rec; + time_t timestamp; + + offset = lseek(fd, 0, SEEK_CUR); + + ret = read(fd, &rec, sizeof(rec)); + if (ret == 0) + return 0; + + if (ret != sizeof(rec)) { + i_fatal("rec read() %"PRIuSIZE_T" != %"PRIuSIZE_T, + ret, sizeof(rec)); + } + + printf("#%"PRIuUOFF_T": ", offset); + switch (rec.type) { + case MAILBOX_LOG_RECORD_DELETE_MAILBOX: + printf("delete-mailbox"); + break; + case MAILBOX_LOG_RECORD_DELETE_DIR: + printf("delete-dir"); + break; + case MAILBOX_LOG_RECORD_RENAME: + printf("rename"); + break; + case MAILBOX_LOG_RECORD_SUBSCRIBE: + printf("subscribe"); + break; + case MAILBOX_LOG_RECORD_UNSUBSCRIBE: + printf("unsubscribe"); + break; + } + printf(" %s", binary_to_hex(rec.mailbox_guid, + sizeof(rec.mailbox_guid))); + + timestamp = ((uint32_t)rec.timestamp[0] << 24) | + ((uint32_t)rec.timestamp[1] << 16) | + ((uint32_t)rec.timestamp[2] << 8) | + (uint32_t)rec.timestamp[3]; + printf(" (%s)\n", unixdate2str(timestamp)); + return 1; +} + +static void cmd_dump_mailboxlog(int argc ATTR_UNUSED, char *argv[]) +{ + int fd, ret; + + fd = open(argv[1], O_RDONLY); + if (fd < 0) + i_fatal("open(%s) failed: %m", argv[1]); + + do { + T_BEGIN { + ret = dump_record(fd); + } T_END; + } while (ret > 0); +} + +static bool test_dump_mailboxlog(const char *path) +{ + const char *p; + int fd; + struct mailbox_log_record rec; + bool ret = FALSE; + + p = strrchr(path, '.'); + if (p == NULL || strcmp(p, ".log") != 0) + return FALSE; + + fd = open(path, O_RDONLY); + if (fd == -1) + return FALSE; + + if (read(fd, &rec, sizeof(rec)) == sizeof(rec) && + rec.padding[0] == 0 && rec.padding[1] == 0 && rec.padding[2] == 0) { + enum mailbox_log_record_type type = rec.type; + switch (type) { + case MAILBOX_LOG_RECORD_DELETE_MAILBOX: + case MAILBOX_LOG_RECORD_DELETE_DIR: + case MAILBOX_LOG_RECORD_RENAME: + case MAILBOX_LOG_RECORD_SUBSCRIBE: + case MAILBOX_LOG_RECORD_UNSUBSCRIBE: + ret = TRUE; + break; + } + } + (void)close(fd); + return ret; +} + +struct doveadm_cmd_dump doveadm_cmd_dump_mailboxlog = { + "mailboxlog", + test_dump_mailboxlog, + cmd_dump_mailboxlog +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump-thread.c Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,137 @@ +/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mmap-util.h" +#include "mail-index-private.h" +#include "mail-index-strmap.h" +#include "doveadm-dump.h" + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + +static uint32_t max_likely_index; + +static size_t dump_hdr(const struct mail_index_strmap_header *hdr) +{ + printf("version = %u\n", hdr->version); + printf("uid validity = %u\n", hdr->uid_validity); + return sizeof(*hdr); +} + +static int dump_record(const uint8_t **p, const uint8_t *end, uint32_t *uid) +{ + uint32_t uid_diff, n, i, count, crc32, idx; + size_t size; + + /* <uid diff> <n> <crc32>*count <str_idx>*count */ + if (mail_index_unpack_num(p, end, &uid_diff) < 0) + return -1; + *uid += uid_diff; + + if (mail_index_unpack_num(p, end, &n) < 0) + return -1; + printf(" - uid %u: n=%u\n", *uid, n); + + count = n < 2 ? n + 1 : n; + size = sizeof(crc32)*count + sizeof(idx)*count; + if (*p + size > end) + return -1; + for (i = 0; i < count; i++) { + if (i == 0) + printf(" - message-id: "); + else if (i == 1) { + if (n == 1) + printf(" - in-reply-to: "); + else + printf(" - references[1]: "); + } else { + printf(" - references[%u]: ", i); + } + memcpy(&crc32, *p + sizeof(crc32)*i, sizeof(crc32)); + memcpy(&idx, *p + sizeof(crc32)*count + sizeof(idx)*i, sizeof(idx)); + printf("crc32=%08x index=%u\n", crc32, idx); + if (idx > max_likely_index) + printf(" - index probably broken\n"); + } + *p += size; + return 0; +} + +static int dump_block(const uint8_t *data, const uint8_t *end, uint32_t *uid) +{ + const uint8_t *p; + uint32_t block_size; + + if (data + 4 >= end) + return -1; + + memcpy(&block_size, data, sizeof(block_size)); + block_size = mail_index_offset_to_uint32(block_size) >> 2; + printf(" - block_size=%u\n", block_size); + if (block_size == 0) { + /* finished */ + return -1; + } + if (data + sizeof(block_size) + block_size > end) { + printf(" - broken!\n"); + return -1; + } + p = data + sizeof(block_size); + end = p + block_size; + + *uid += 1; + while (p != end) { + if (dump_record(&p, end, uid) < 0) { + printf(" - broken\n"); + return -1; + } + } + return p - data; +} + +static void cmd_dump_thread(int argc ATTR_UNUSED, char *argv[]) +{ + unsigned int pos; + const void *map, *end; + struct stat st; + uint32_t uid; + int fd, ret; + + fd = open(argv[1], O_RDONLY); + if (fd < 0) + i_fatal("open(%s) failed: %m", argv[1]); + + if (fstat(fd, &st) < 0) + i_fatal("fstat(%s) failed: %m", argv[1]); + max_likely_index = (st.st_size / 8) * 2; + + map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) + i_fatal("mmap() failed: %m"); + end = CONST_PTR_OFFSET(map, st.st_size); + pos = dump_hdr(map); + uid = 0; + do { + printf("block at offset %u:\n", pos); + T_BEGIN { + ret = dump_block(CONST_PTR_OFFSET(map, pos), end, &uid); + pos += ret; + } T_END; + } while (ret > 0); +} + +static bool test_dump_thread(const char *path) +{ + const char *p; + + p = strrchr(path, '.'); + return p != NULL && strcmp(p, ".thread") == 0; +} + +struct doveadm_cmd_dump doveadm_cmd_dump_thread = { + "thread", + test_dump_thread, + cmd_dump_thread +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump.c Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,79 @@ +/* Copyright (C) 2004 Joshua Goodall */ + +#include "lib.h" +#include "doveadm.h" +#include "doveadm-dump.h" + +#include <stdio.h> +#include <unistd.h> + +static const struct doveadm_cmd_dump *dumps[] = { + &doveadm_cmd_dump_index, + &doveadm_cmd_dump_log, + &doveadm_cmd_dump_mailboxlog, + &doveadm_cmd_dump_thread +}; + +static const struct doveadm_cmd_dump * +dump_find_name(const char *name) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(dumps); i++) { + if (strcmp(dumps[i]->name, name) == 0) + return dumps[i]; + } + return NULL; +} + +static const struct doveadm_cmd_dump * +dump_find_test(const char *path) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(dumps); i++) { + if (dumps[i]->test(path)) + return dumps[i]; + } + return NULL; +} + +static void cmd_dump(int argc, char *argv[]) +{ + const struct doveadm_cmd_dump *dump; + const char *type = NULL; + int c; + + while ((c = getopt(argc, argv, "t:")) > 0) { + switch (c) { + case 't': + type = optarg; + break; + default: + help(&doveadm_cmd_dump); + } + } + if (optind == argc) + help(&doveadm_cmd_dump); + + optind--; + argc -= optind; + argv += optind; + + dump = type != NULL ? dump_find_name(type) : dump_find_test(argv[1]); + if (dump == NULL) { + if (type != NULL) + i_fatal("Unknown type: %s", type); + else + i_fatal("Can't autodetect file type: %s", argv[1]); + } else { + if (type == NULL) + printf("Detected file type: %s\n", dump->name); + } + dump->cmd(argc, argv); +} + +struct doveadm_cmd doveadm_cmd_dump = { + cmd_dump, "dump", "[-t <type>] <path>", +" <type> can be: index log mailboxlog thread\n" +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-dump.h Thu Oct 08 20:43:25 2009 -0400 @@ -0,0 +1,17 @@ +#ifndef DOVEADM_DUMP_H +#define DOVEADM_DUMP_H + +#include "doveadm.h" + +struct doveadm_cmd_dump { + const char *name; + bool (*test)(const char *path); + doveadm_command_t *cmd; +}; + +extern struct doveadm_cmd_dump doveadm_cmd_dump_index; +extern struct doveadm_cmd_dump doveadm_cmd_dump_log; +extern struct doveadm_cmd_dump doveadm_cmd_dump_mailboxlog; +extern struct doveadm_cmd_dump doveadm_cmd_dump_thread; + +#endif
--- a/src/doveadm/doveadm.c Thu Oct 08 20:10:49 2009 -0400 +++ b/src/doveadm/doveadm.c Thu Oct 08 20:43:25 2009 -0400 @@ -81,6 +81,7 @@ doveadm_register_cmd(&doveadm_cmd_help); doveadm_register_cmd(&doveadm_cmd_auth); doveadm_register_cmd(&doveadm_cmd_user); + doveadm_register_cmd(&doveadm_cmd_dump); doveadm_register_cmd(&doveadm_cmd_pw); /* "+" is GNU extension to stop at the first non-option.
--- a/src/doveadm/doveadm.h Thu Oct 08 20:10:49 2009 -0400 +++ b/src/doveadm/doveadm.h Thu Oct 08 20:43:25 2009 -0400 @@ -14,6 +14,7 @@ extern struct doveadm_cmd doveadm_cmd_auth; extern struct doveadm_cmd doveadm_cmd_user; +extern struct doveadm_cmd doveadm_cmd_dump; extern struct doveadm_cmd doveadm_cmd_pw; void doveadm_register_cmd(const struct doveadm_cmd *cmd);
--- a/src/util/Makefile.am Thu Oct 08 20:10:49 2009 -0400 +++ b/src/util/Makefile.am Thu Oct 08 20:43:25 2009 -0400 @@ -3,13 +3,9 @@ pkglibexec_PROGRAMS = \ rawlog \ gdbhelper \ - idxview \ imap-utf7 \ listview \ - logview \ - mailboxlogview \ - maildirlock \ - threadview + maildirlock AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ @@ -33,11 +29,6 @@ gdbhelper_SOURCES = \ gdbhelper.c -idxview_LDADD = $(LIBDOVECOT_STORAGE) $(LIBDOVECOT) -idxview_DEPENDENCIES = $(LIBDOVECOT_STORAGE) $(LIBDOVECOT) -idxview_SOURCES = \ - idxview.c - imap_utf7_LDADD = $(LIBDOVECOT) imap_utf7_DEPENDENCIES = $(LIBDOVECOT) imap_utf7_SOURCES = \ @@ -48,22 +39,7 @@ listview_SOURCES = \ listview.c -logview_LDADD = $(LIBDOVECOT) -logview_DEPENDENCIES = $(LIBDOVECOT) -logview_SOURCES = \ - logview.c - -mailboxlogview_LDADD = $(LIBDOVECOT) -mailboxlogview_DEPENDENCIES = $(LIBDOVECOT) -mailboxlogview_SOURCES = \ - mailboxlogview.c - maildirlock_LDADD = $(LIBDOVECOT) maildirlock_DEPENDENCIES = $(LIBDOVECOT) maildirlock_SOURCES = \ maildirlock.c - -threadview_LDADD = $(LIBDOVECOT) -threadview_DEPENDENCIES = $(LIBDOVECOT) -threadview_SOURCES = \ - threadview.c
--- a/src/util/idxview.c Thu Oct 08 20:10:49 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,510 +0,0 @@ -/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "str.h" -#include "hex-binary.h" -#include "file-lock.h" -#include "mail-index-private.h" -#include "mail-cache-private.h" -#include "mail-cache-private.h" -#include "mail-index-modseq.h" - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -struct maildir_index_header { - uint32_t new_check_time, new_mtime, new_mtime_nsecs; - uint32_t cur_check_time, cur_mtime, cur_mtime_nsecs; - uint32_t uidlist_mtime, uidlist_mtime_nsecs, uidlist_size; -}; -struct mbox_index_header { - uint64_t sync_size; - uint32_t sync_mtime; - uint8_t dirty_flag; - uint8_t unused[3]; - uint8_t mailbox_guid[16]; -}; -struct dbox_index_header { - uint32_t map_uid_validity; - uint32_t highest_maildir_uid; - uint8_t mailbox_guid[16]; -}; -struct dbox_mail_index_record { - uint32_t map_uid; - uint32_t save_date; -}; - -struct virtual_mail_index_record { - uint32_t mailbox_id; - uint32_t real_uid; -}; - -struct dbox_mail_index_map_record { - uint32_t file_id; - uint32_t offset; - uint32_t size; -}; - -static const char *unixdate2str(time_t timestamp) -{ - static char buf[64]; - struct tm *tm; - - tm = localtime(×tamp); - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); - return buf; -} - -static void dump_hdr(struct mail_index *index) -{ - const struct mail_index_header *hdr = &index->map->hdr; - unsigned int i; - - printf("version .................. = %u.%u\n", hdr->major_version, hdr->minor_version); - printf("base header size ......... = %u\n", hdr->base_header_size); - printf("header size .............. = %u\n", hdr->header_size); - printf("record size .............. = %u\n", hdr->record_size); - printf("compat flags ............. = %u\n", hdr->compat_flags); - printf("index id ................. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid)); - printf("flags .................... = %u\n", hdr->flags); - printf("uid validity ............. = %u (%s)\n", hdr->uid_validity, unixdate2str(hdr->uid_validity)); - printf("next uid ................. = %u\n", hdr->next_uid); - printf("messages count ........... = %u\n", hdr->messages_count); - printf("seen messages count ...... = %u\n", hdr->seen_messages_count); - printf("deleted messages count ... = %u\n", hdr->deleted_messages_count); - printf("first recent uid ......... = %u\n", hdr->first_recent_uid); - printf("first unseen uid lowwater = %u\n", hdr->first_unseen_uid_lowwater); - printf("first deleted uid lowwater = %u\n", hdr->first_deleted_uid_lowwater); - printf("log file seq ............. = %u\n", hdr->log_file_seq); - if (hdr->minor_version == 0) { - printf("log file int offset ...... = %u\n", hdr->log_file_tail_offset); - printf("log file ext offset ...... = %u\n", hdr->log_file_head_offset); - } else { - printf("log file tail offset ..... = %u\n", hdr->log_file_tail_offset); - printf("log file head offset ..... = %u\n", hdr->log_file_head_offset); - } - printf("sync size ................ = %llu\n", (unsigned long long)hdr->sync_size); - printf("sync stamp ............... = %u (%s)\n", hdr->sync_stamp, unixdate2str(hdr->sync_stamp)); - printf("day stamp ................ = %u (%s)\n", hdr->day_stamp, unixdate2str(hdr->day_stamp)); - for (i = 0; i < N_ELEMENTS(hdr->day_first_uid); i++) - printf("day first uid[%u] ......... = %u\n", i, hdr->day_first_uid[i]); -} - -static void dump_extension_header(struct mail_index *index, - const struct mail_index_ext *ext) -{ - const void *data; - - if (strcmp(ext->name, MAIL_INDEX_EXT_KEYWORDS) == 0) - return; - - data = CONST_PTR_OFFSET(index->map->hdr_base, ext->hdr_offset); - if (strcmp(ext->name, "maildir") == 0) { - const struct maildir_index_header *hdr = data; - - printf("header\n"); - printf(" - new_check_time .... = %s\n", unixdate2str(hdr->new_check_time)); - printf(" - new_mtime ......... = %s\n", unixdate2str(hdr->new_mtime)); - printf(" - new_mtime_nsecs ... = %u\n", hdr->new_mtime_nsecs); - printf(" - cur_check_time .... = %s\n", unixdate2str(hdr->cur_check_time)); - printf(" - cur_mtime ......... = %s\n", unixdate2str(hdr->cur_mtime)); - printf(" - cur_mtime_nsecs.... = %u\n", hdr->cur_mtime_nsecs); - printf(" - uidlist_mtime ..... = %s\n", unixdate2str(hdr->uidlist_mtime)); - printf(" - uidlist_mtime_nsecs = %u\n", hdr->uidlist_mtime_nsecs); - printf(" - uidlist_size ...... = %u\n", hdr->uidlist_size); - } else if (strcmp(ext->name, "mbox") == 0) { - const struct mbox_index_header *hdr = data; - - printf("header\n"); - printf(" - sync_mtime . = %s\n", unixdate2str(hdr->sync_mtime)); - printf(" - sync_size .. = %llu\n", - (unsigned long long)hdr->sync_size); - printf(" - dirty_flag . = %d\n", hdr->dirty_flag); - printf(" - mailbox_guid = %s\n", - binary_to_hex(hdr->mailbox_guid, - sizeof(hdr->mailbox_guid))); - } else if (strcmp(ext->name, "dbox-hdr") == 0) { - const struct dbox_index_header *hdr = data; - - printf("header\n"); - printf(" - map_uid_validity .. = %u\n", hdr->map_uid_validity); - printf(" - highest_maildir_uid = %u\n", hdr->highest_maildir_uid); - printf(" - mailbox_guid ...... = %s\n", - binary_to_hex(hdr->mailbox_guid, - sizeof(hdr->mailbox_guid))); - } else if (strcmp(ext->name, "modseq") == 0) { - const struct mail_index_modseq_header *hdr = data; - - printf("header\n"); - printf(" - highest_modseq = %llu\n", - (unsigned long long)hdr->highest_modseq); - printf(" - log_seq ...... = %u\n", hdr->log_seq); - printf(" - log_offset ... = %u\n", hdr->log_offset); - } else { - printf("header ........ = %s\n", - binary_to_hex(data, ext->hdr_size)); - } -} - -static void dump_extensions(struct mail_index *index) -{ - const struct mail_index_ext *extensions; - unsigned int i, count; - - if (array_is_created(&index->map->extensions)) - extensions = array_get(&index->map->extensions, &count); - else - count = 0; - if (count == 0) { - printf("no extensions\n"); - return; - } - - for (i = 0; i < count; i++) { - const struct mail_index_ext *ext = &extensions[i]; - - printf("-- Extension %u --\n", i); - printf("name ........ = %s\n", ext->name); - printf("hdr_size .... = %u\n", ext->hdr_size); - printf("reset_id .... = %u\n", ext->reset_id); - printf("record_offset = %u\n", ext->record_offset); - printf("record_size . = %u\n", ext->record_size); - printf("record_align = %u\n", ext->record_align); - if (ext->hdr_size > 0) - dump_extension_header(index, ext); - } -} - -static void dump_keywords(struct mail_index *index) -{ - const unsigned int *kw_indexes; - const char *const *keywords; - unsigned int i, count; - - printf("-- Keywords --\n"); - if (!array_is_created(&index->map->keyword_idx_map)) - return; - - kw_indexes = array_get(&index->map->keyword_idx_map, &count); - if (count == 0) - return; - - keywords = array_idx(&index->keywords, 0); - for (i = 0; i < count; i++) - printf("%3u = %s\n", i, keywords[kw_indexes[i]]); -} - -static const char *cache_decision2str(enum mail_cache_decision_type type) -{ - const char *str; - - switch (type & ~MAIL_CACHE_DECISION_FORCED) { - case MAIL_CACHE_DECISION_NO: - str = "no"; - break; - case MAIL_CACHE_DECISION_TEMP: - str = "tmp"; - break; - case MAIL_CACHE_DECISION_YES: - str = "yes"; - break; - default: - return t_strdup_printf("0x%x", type); - } - - if ((type & MAIL_CACHE_DECISION_FORCED) != 0) - str = t_strconcat(str, "!", NULL); - return str; -} - -#define CACHE_TYPE_IS_FIXED_SIZE(type) \ - ((type) == MAIL_CACHE_FIELD_FIXED_SIZE || \ - (type) == MAIL_CACHE_FIELD_BITMASK) -static const char *cache_type2str(enum mail_cache_field_type type) -{ - switch (type) { - case MAIL_CACHE_FIELD_FIXED_SIZE: - return "fix"; - case MAIL_CACHE_FIELD_VARIABLE_SIZE: - return "var"; - case MAIL_CACHE_FIELD_STRING: - return "str"; - case MAIL_CACHE_FIELD_BITMASK: - return "bit"; - case MAIL_CACHE_FIELD_HEADER: - return "hdr"; - default: - return t_strdup_printf("0x%x", type); - } -} - -static void dump_cache_hdr(struct mail_cache *cache) -{ - const struct mail_cache_header *hdr; - const struct mail_cache_field *fields, *field; - unsigned int i, count, cache_idx; - - (void)mail_cache_open_and_verify(cache); - if (MAIL_CACHE_IS_UNUSABLE(cache)) { - printf("cache is unusable\n"); - return; - } - - hdr = cache->hdr; - printf("version .............. = %u\n", hdr->version); - printf("indexid .............. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid)); - printf("file_seq ............. = %u (%s) (%d compressions)\n", - hdr->file_seq, unixdate2str(hdr->file_seq), - hdr->file_seq - hdr->indexid); - printf("continued_record_count = %u\n", hdr->continued_record_count); - printf("hole_offset .......... = %u\n", hdr->hole_offset); - printf("used_file_size ....... = %u\n", hdr->used_file_size); - printf("deleted_space ........ = %u\n", hdr->deleted_space); - printf("field_header_offset .. = %u (0x%08x nontranslated)\n", - mail_index_offset_to_uint32(hdr->field_header_offset), - hdr->field_header_offset); - - printf("-- Cache fields --\n"); - fields = mail_cache_register_get_list(cache, pool_datastack_create(), - &count); - printf( -" # Name Type Size Dec Last used\n"); - for (i = 0; i < cache->file_fields_count; i++) { - cache_idx = cache->file_field_map[i]; - field = &fields[cache_idx]; - - printf("%2u: %-44s %-4s ", i, field->name, - cache_type2str(field->type)); - if (field->field_size != (uint32_t)-1 || - CACHE_TYPE_IS_FIXED_SIZE(field->type)) - printf("%4u ", field->field_size); - else - printf(" - "); - printf("%-4s %.16s\n", - cache_decision2str(field->decision), - unixdate2str(cache->fields[cache_idx].last_used)); - } -} - -static void dump_cache(struct mail_cache_view *cache_view, unsigned int seq) -{ - struct mail_cache_lookup_iterate_ctx iter; - const struct mail_cache_record *prev_rec = NULL; - const struct mail_cache_field *field; - struct mail_cache_iterate_field iter_field; - const void *data; - unsigned int size; - string_t *str; - int ret; - - str = t_str_new(512); - mail_cache_lookup_iter_init(cache_view, seq, &iter); - while ((ret = mail_cache_lookup_iter_next(&iter, &iter_field)) > 0) { - if (iter.rec != prev_rec) { - printf(" - cache offset=%u size=%u, prev_offset = %u\n", - iter.offset, iter.rec->size, - iter.rec->prev_offset); - prev_rec = iter.rec; - } - - field = &cache_view->cache->fields[iter_field.field_idx].field; - data = iter_field.data; - size = iter_field.size; - - str_truncate(str, 0); - str_printfa(str, " - %s: ", field->name); - switch (field->type) { - case MAIL_CACHE_FIELD_FIXED_SIZE: - if (size == sizeof(uint32_t)) - str_printfa(str, "%u ", *((const uint32_t *)data)); - else if (size == sizeof(uint64_t)) - str_printfa(str, "%llu ", (unsigned long long)*((const uint64_t *)data)); - case MAIL_CACHE_FIELD_VARIABLE_SIZE: - case MAIL_CACHE_FIELD_BITMASK: - str_printfa(str, "(%s)", binary_to_hex(data, size)); - break; - case MAIL_CACHE_FIELD_STRING: - if (size > 0) - str_printfa(str, "%.*s", (int)size, (const char *)data); - break; - case MAIL_CACHE_FIELD_HEADER: { - const uint32_t *lines = data; - int i; - - for (i = 0;; i++) { - if (size < sizeof(uint32_t)) { - if (i == 0 && size == 0) { - /* header doesn't exist */ - break; - } - - str_append(str, "\n - BROKEN: header field doesn't end with 0 line"); - size = 0; - break; - } - - size -= sizeof(uint32_t); - data = CONST_PTR_OFFSET(data, sizeof(uint32_t)); - if (lines[i] == 0) - break; - - if (i > 0) - str_append(str, ", "); - str_printfa(str, "%u", lines[i]); - } - - if (i == 1 && size > 0 && - ((const char *)data)[size-1] == '\n') - size--; - if (size > 0) - str_printfa(str, ": %.*s", (int)size, (const char *)data); - break; - } - case MAIL_CACHE_FIELD_COUNT: - i_unreached(); - break; - } - - printf("%s\n", str_c(str)); - } - if (ret < 0) - printf(" - broken cache\n"); -} - -static const char *flags2str(enum mail_flags flags) -{ - string_t *str; - - str = t_str_new(64); - str_append_c(str, '('); - if ((flags & MAIL_SEEN) != 0) - str_append(str, "Seen "); - if ((flags & MAIL_ANSWERED) != 0) - str_append(str, "Answered "); - if ((flags & MAIL_FLAGGED) != 0) - str_append(str, "Flagged "); - if ((flags & MAIL_DELETED) != 0) - str_append(str, "Deleted "); - if ((flags & MAIL_DRAFT) != 0) - str_append(str, "Draft "); - if (str_len(str) == 1) - return ""; - - str_truncate(str, str_len(str)-1); - str_append_c(str, ')'); - return str_c(str); -} - -static void dump_record(struct mail_index_view *view, unsigned int seq) -{ - struct mail_index *index = mail_index_view_get_index(view); - const struct mail_index_record *rec; - const struct mail_index_registered_ext *ext; - const void *data; - unsigned int i, ext_count; - string_t *str; - bool expunged; - - rec = mail_index_lookup(view, seq); - printf("RECORD: seq=%u, uid=%u, flags=0x%02x %s\n", - seq, rec->uid, rec->flags, flags2str(rec->flags)); - - str = t_str_new(256); - ext = array_get(&index->extensions, &ext_count); - for (i = 0; i < ext_count; i++) { - mail_index_lookup_ext(view, seq, i, &data, &expunged); - if (data == NULL || ext[i].record_size == 0) - continue; - - str_truncate(str, 0); - str_printfa(str, " - ext %d %-10s: ", i, ext[i].name); - if (ext[i].record_size == sizeof(uint16_t) && - ext[i].record_align == sizeof(uint16_t)) - str_printfa(str, "%10u", *((const uint16_t *)data)); - else if (ext[i].record_size == sizeof(uint32_t) && - ext[i].record_align == sizeof(uint32_t)) - str_printfa(str, "%10u", *((const uint32_t *)data)); - else if (ext[i].record_size == sizeof(uint64_t) && - ext[i].record_align == sizeof(uint64_t)) { - uint64_t value = *((const uint64_t *)data); - str_printfa(str, "%10llu", (unsigned long long)value); - } else { - str_append(str, " "); - } - str_printfa(str, " (%s)", - binary_to_hex(data, ext[i].record_size)); - printf("%s\n", str_c(str)); - if (strcmp(ext[i].name, "virtual") == 0) { - const struct virtual_mail_index_record *vrec = data; - printf(" : mailbox_id = %u\n", vrec->mailbox_id); - printf(" : real_uid = %u\n", vrec->real_uid); - } else if (strcmp(ext[i].name, "map") == 0) { - const struct dbox_mail_index_map_record *mrec = data; - printf(" : file_id = %u\n", mrec->file_id); - printf(" : offset = %u\n", mrec->offset); - printf(" : size = %u\n", mrec->size); - } else if (strcmp(ext[i].name, "dbox") == 0) { - const struct dbox_mail_index_record *drec = data; - printf(" : map_uid = %u\n", drec->map_uid); - printf(" : save_date = %u (%s)\n", drec->save_date, unixdate2str(drec->save_date)); - } - } -} - -int main(int argc, const char *argv[]) -{ - struct mail_index *index; - struct mail_index_view *view; - struct mail_cache_view *cache_view; - struct stat st; - const char *p; - unsigned int seq, uid = 0; - - lib_init(); - - if (argc < 2) - i_fatal("Usage: idxview <index dir> [<uid>]"); - - if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) - index = mail_index_alloc(argv[1], "dovecot.index"); - else if ((p = strrchr(argv[1], '/')) != NULL) - index = mail_index_alloc(t_strdup_until(argv[1], p), p + 1); - else - index = mail_index_alloc(".", argv[1]); - if (mail_index_open(index, MAIL_INDEX_OPEN_FLAG_READONLY, - FILE_LOCK_METHOD_FCNTL) <= 0) - i_fatal("Couldn't open index %s", argv[1]); - if (argv[2] != NULL) - uid = atoi(argv[2]); - - view = mail_index_view_open(index); - cache_view = mail_cache_view_open(index->cache, view); - - if (uid == 0) { - printf("-- INDEX: %s\n", index->filepath); - dump_hdr(index); - dump_extensions(index); - dump_keywords(index); - - printf("\n-- CACHE: %s\n", index->cache->filepath); - dump_cache_hdr(index->cache); - - printf("\n-- RECORDS: %u\n", index->map->hdr.messages_count); - } - for (seq = 1; seq <= index->map->hdr.messages_count; seq++) { - if (uid == 0 || mail_index_lookup(view, seq)->uid == uid) { - T_BEGIN { - dump_record(view, seq); - dump_cache(cache_view, seq); - printf("\n"); - } T_END; - } - } - mail_cache_view_close(cache_view); - mail_index_view_close(&view); - mail_index_close(index); - mail_index_free(&index); - return 0; -}
--- a/src/util/logview.c Thu Oct 08 20:10:49 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,492 +0,0 @@ -/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "hex-binary.h" -#include "mail-index-private.h" -#include "mail-transaction-log.h" - -#include <stdio.h> - -static struct mail_transaction_ext_intro prev_intro; - -uint32_t mail_index_offset_to_uint32(uint32_t offset) -{ - const unsigned char *buf = (const unsigned char *) &offset; - - if ((offset & 0x80808080) != 0x80808080) - return 0; - - return (((uint32_t)buf[3] & 0x7f) << 2) | - (((uint32_t)buf[2] & 0x7f) << 9) | - (((uint32_t)buf[1] & 0x7f) << 16) | - (((uint32_t)buf[0] & 0x7f) << 23); -} - -static void dump_hdr(int fd, uint64_t *modseq_r) -{ - struct mail_transaction_log_header hdr; - ssize_t ret; - - ret = read(fd, &hdr, sizeof(hdr)); - if (ret != sizeof(hdr)) { - i_fatal("file hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T, - ret, sizeof(hdr)); - } - if (hdr.hdr_size < sizeof(hdr)) { - memset(PTR_OFFSET(&hdr, hdr.hdr_size), 0, - sizeof(hdr) - hdr.hdr_size); - } - lseek(fd, hdr.hdr_size, SEEK_SET); - - printf("version = %u.%u\n", hdr.major_version, hdr.minor_version); - printf("hdr size = %u\n", hdr.hdr_size); - printf("index id = %u\n", hdr.indexid); - printf("file seq = %u\n", hdr.file_seq); - printf("prev file = %u/%u\n", hdr.prev_file_seq, hdr.prev_file_offset); - printf("create stamp = %u\n", hdr.create_stamp); - printf("initial modseq = %llu\n", - (unsigned long long)hdr.initial_modseq); - printf("compat flags = %x\n", hdr.compat_flags); - *modseq_r = hdr.initial_modseq; -} - -static bool -mail_transaction_header_has_modseq(const struct mail_transaction_header *hdr) -{ - switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { - case MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT: - case MAIL_TRANSACTION_EXPUNGE_GUID | MAIL_TRANSACTION_EXPUNGE_PROT: - if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) { - /* ignore expunge requests */ - break; - } - case MAIL_TRANSACTION_APPEND: - case MAIL_TRANSACTION_FLAG_UPDATE: - case MAIL_TRANSACTION_KEYWORD_UPDATE: - case MAIL_TRANSACTION_KEYWORD_RESET: - case MAIL_TRANSACTION_UID_UPDATE: - /* these changes increase modseq */ - return TRUE; - } - return FALSE; -} -static const char *log_record_type(unsigned int type) -{ - const char *name; - - switch (type & MAIL_TRANSACTION_TYPE_MASK) { - case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: - name = "expunge"; - break; - case MAIL_TRANSACTION_EXPUNGE_GUID|MAIL_TRANSACTION_EXPUNGE_PROT: - name = "expunge-guid"; - break; - case MAIL_TRANSACTION_APPEND: - name = "append"; - break; - case MAIL_TRANSACTION_FLAG_UPDATE: - name = "flag-update"; - break; - case MAIL_TRANSACTION_HEADER_UPDATE: - name = "header-update"; - break; - case MAIL_TRANSACTION_EXT_INTRO: - name = "ext-intro"; - break; - case MAIL_TRANSACTION_EXT_RESET: - name = "ext-reset"; - break; - case MAIL_TRANSACTION_EXT_HDR_UPDATE: - name = "ext-hdr"; - break; - case MAIL_TRANSACTION_EXT_REC_UPDATE: - name = "ext-rec"; - break; - case MAIL_TRANSACTION_KEYWORD_UPDATE: - name = "keyword-update"; - break; - case MAIL_TRANSACTION_KEYWORD_RESET: - name = "keyword-reset"; - break; - case MAIL_TRANSACTION_EXT_ATOMIC_INC: - name = "ext-atomic-inc"; - break; - case MAIL_TRANSACTION_UID_UPDATE: - name = "uid-update"; - break; - case MAIL_TRANSACTION_MODSEQ_UPDATE: - name = "modseq-update"; - break; - default: - name = t_strdup_printf("unknown: %x", type); - break; - } - - if (type & MAIL_TRANSACTION_EXTERNAL) - name = t_strconcat(name, " (ext)", NULL); - return name; -} - -static void print_data(const void *data, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++) - printf("%02x", ((const unsigned char *)data)[i]); - if (size == 4) { - const uint32_t *n = (const uint32_t *)data; - - printf(" (dec=%u)", *n); - } -} - -static void print_try_uint(const void *data, size_t size) -{ - size_t i; - - switch (size) { - case 1: { - const uint8_t *n = data; - printf("%u", *n); - break; - } - case 2: { - const uint16_t *n = data; - uint32_t n16; - - memcpy(&n16, n, sizeof(n16)); - printf("%u", n16); - break; - } - case 4: { - const uint32_t *n = data; - uint32_t n32; - - memcpy(&n32, n, sizeof(n32)); - printf("%u", n32); - break; - } - case 8: { - const uint64_t *n = data; - uint64_t n64; - - memcpy(&n64, n, sizeof(n64)); - printf("%llu", (unsigned long long)n64); - break; - } - default: - for (i = 0; i < size; i++) - printf("%02x", ((const unsigned char *)data)[i]); - } -} - -#define HDRF(field) { \ - #field, offsetof(struct mail_index_header, field), \ - sizeof(((struct mail_index_header *)0)->field) } - -static struct { - const char *name; - unsigned int offset, size; -} header_fields[] = { - HDRF(minor_version), - HDRF(base_header_size), - HDRF(header_size), - HDRF(record_size), - HDRF(compat_flags), - HDRF(indexid), - HDRF(flags), - HDRF(uid_validity), - HDRF(next_uid), - HDRF(messages_count), - HDRF(unused_old_recent_messages_count), - HDRF(seen_messages_count), - HDRF(deleted_messages_count), - HDRF(first_recent_uid), - HDRF(first_unseen_uid_lowwater), - HDRF(first_deleted_uid_lowwater), - HDRF(log_file_seq), - HDRF(log_file_tail_offset), - HDRF(log_file_head_offset), - HDRF(sync_size), - HDRF(sync_stamp), - HDRF(day_stamp) -}; - -static void log_header_update(const struct mail_transaction_header_update *u) -{ - const void *data = u + 1; - unsigned int offset = u->offset, size = u->size; - unsigned int i; - - while (size > 0) { - /* don't bother trying to handle header updates that include - unknown/unexpected fields offsets/sizes */ - for (i = 0; i < N_ELEMENTS(header_fields); i++) { - if (header_fields[i].offset == offset && - header_fields[i].size <= size) - break; - } - - if (i == N_ELEMENTS(header_fields)) { - printf(" - offset = %u, size = %u: ", offset, size); - print_data(data, size); - printf("\n"); - break; - } - - printf(" - %s = ", header_fields[i].name); - print_try_uint(data, header_fields[i].size); - printf("\n"); - - data = CONST_PTR_OFFSET(data, header_fields[i].size); - offset += header_fields[i].size; - size -= header_fields[i].size; - } -} - -static void log_record_print(const struct mail_transaction_header *hdr, - const void *data, uint64_t *modseq) -{ - unsigned int size = hdr->size - sizeof(*hdr); - - switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { - case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: { - const struct mail_transaction_expunge *exp = data; - - printf(" -"); - for (; size > 0; size -= sizeof(*exp), exp++) { - printf(" %u-%u", exp->uid1, exp->uid2); - } - printf("\n"); - break; - } - case MAIL_TRANSACTION_EXPUNGE_GUID|MAIL_TRANSACTION_EXPUNGE_PROT: { - const struct mail_transaction_expunge_guid *exp = data; - - for (; size > 0; size -= sizeof(*exp), exp++) { - printf(" - %u (guid ", exp->uid); - print_data(exp->guid_128, sizeof(exp->guid_128)); - printf(")\n"); - } - break; - } - case MAIL_TRANSACTION_APPEND: { - const struct mail_index_record *rec = data; - - printf(" - "); - for (; size > 0; size -= sizeof(*rec), rec++) { - printf("%u", rec->uid); - if (rec->flags != 0) - printf(" (flags=%x)", rec->flags); - printf(","); - } - printf("\n"); - break; - } - case MAIL_TRANSACTION_FLAG_UPDATE: { - const struct mail_transaction_flag_update *u = data; - - for (; size > 0; size -= sizeof(*u), u++) { - printf(" - %u-%u (flags +%x-%x)\n", u->uid1, u->uid2, - u->add_flags, u->remove_flags); - } - break; - } - case MAIL_TRANSACTION_HEADER_UPDATE: { - const struct mail_transaction_header_update *u = data; - - log_header_update(u); - break; - } - case MAIL_TRANSACTION_EXT_INTRO: { - const struct mail_transaction_ext_intro *intro = data; - - prev_intro = *intro; - printf(" - ext_id = %u\n", intro->ext_id); - printf(" - reset_id = %u\n", intro->reset_id); - printf(" - hdr_size = %u\n", intro->hdr_size); - printf(" - record_size = %u\n", intro->record_size); - printf(" - record_align = %u\n", intro->record_align); - printf(" - flags = %u\n", intro->flags); - printf(" - name_size = %u\n", intro->name_size); - if (intro->name_size > 0) { - const char *name = (const char *)(intro+1); - - printf(" - name = '%.*s'\n", intro->name_size, name); - if (*modseq == 0 && intro->name_size == 6 && - memcmp(name, "modseq", 6) == 0) - *modseq = 1; - } - break; - } - case MAIL_TRANSACTION_EXT_RESET: { - const struct mail_transaction_ext_reset *reset = data; - - printf(" - new_reset_id = %u\n", reset->new_reset_id); - printf(" - preserve_data = %u\n", reset->preserve_data); - break; - } - case MAIL_TRANSACTION_EXT_HDR_UPDATE: { - const struct mail_transaction_ext_hdr_update *u = data; - - printf(" - offset = %u, size = %u: ", u->offset, u->size); - print_data(u + 1, u->size); - printf("\n"); - break; - } - case MAIL_TRANSACTION_EXT_REC_UPDATE: { - const struct mail_transaction_ext_rec_update *rec = data, *end; - size_t record_size; - - end = CONST_PTR_OFFSET(data, size); - record_size = (sizeof(*rec) + prev_intro.record_size + 3) & ~3; - while (rec < end) { - printf(" - %u: ", rec->uid); - print_data(rec + 1, prev_intro.record_size); - printf("\n"); - rec = CONST_PTR_OFFSET(rec, record_size); - } - break; - } - case MAIL_TRANSACTION_EXT_ATOMIC_INC: { - const struct mail_transaction_ext_atomic_inc *rec = data, *end; - - end = CONST_PTR_OFFSET(data, size); - for (; rec < end; rec++) { - printf(" - %u: ", rec->uid); - if (rec->diff > 0) - printf("+%d\n", rec->diff); - else - printf("%d\n", rec->diff); - } - break; - } - case MAIL_TRANSACTION_KEYWORD_UPDATE: { - const struct mail_transaction_keyword_update *u = data; - const uint32_t *uid; - unsigned int uid_offset; - - printf(" - modify=%d, name=%.*s, ", - u->modify_type, u->name_size, (const char *)(u+1)); - - uid_offset = sizeof(*u) + u->name_size + - ((u->name_size % 4) == 0 ? 0 : 4 - (u->name_size%4)); - uid = (const uint32_t *)((const char *)u + uid_offset); - size -= uid_offset; - - for (; size > 0; size -= sizeof(*uid)*2, uid += 2) { - printf("%u-%u,", uid[0], uid[1]); - } - printf("\n"); - break; - } - case MAIL_TRANSACTION_KEYWORD_RESET: { - const struct mail_transaction_keyword_reset *u = data; - - printf(" - "); - for (; size > 0; size -= sizeof(*u), u++) { - printf("%u-%u, ", u->uid1, u->uid2); - } - printf("\n"); - break; - } - case MAIL_TRANSACTION_UID_UPDATE: { - const struct mail_transaction_uid_update *rec = data, *end; - - end = CONST_PTR_OFFSET(data, size); - for (rec = data; rec < end; rec++) { - printf(" - old uid=%u new uid=%u\n", - rec->old_uid, rec->new_uid); - } - break; - } - case MAIL_TRANSACTION_MODSEQ_UPDATE: { - const struct mail_transaction_modseq_update *rec = data, *end; - - end = CONST_PTR_OFFSET(data, size); - for (rec = data; rec < end; rec++) { - printf(" - uid=%u modseq=%llu\n", rec->uid, - ((unsigned long long)rec->modseq_high32 << 32) | - rec->modseq_low32); - } - break; - } - default: - break; - } -} - -static int dump_record(int fd, uint64_t *modseq) -{ - off_t offset; - ssize_t ret; - struct mail_transaction_header hdr; - unsigned int orig_size; - - offset = lseek(fd, 0, SEEK_CUR); - - ret = read(fd, &hdr, sizeof(hdr)); - if (ret == 0) - return 0; - - if (ret != sizeof(hdr)) { - i_fatal("rec hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T, - ret, sizeof(hdr)); - } - - orig_size = hdr.size; - hdr.size = mail_index_offset_to_uint32(hdr.size); - if (hdr.size == 0) { - printf("record: offset=%"PRIuUOFF_T", " - "type=%s, size=broken (%x)\n", - offset, log_record_type(hdr.type), orig_size); - return 0; - } - - printf("record: offset=%"PRIuUOFF_T", type=%s, size=%u", - offset, log_record_type(hdr.type), hdr.size); - if (*modseq > 0 && mail_transaction_header_has_modseq(&hdr)) { - *modseq += 1; - printf(", modseq=%llu", (unsigned long long)*modseq); - } - printf("\n"); - - if (hdr.size < 1024*1024) { - unsigned char *buf = t_malloc(hdr.size); - - ret = read(fd, buf, hdr.size - sizeof(hdr)); - if (ret != (ssize_t)(hdr.size - sizeof(hdr))) { - i_fatal("rec data read() %"PRIuSIZE_T" != %"PRIuSIZE_T, - ret, hdr.size - sizeof(hdr)); - } - log_record_print(&hdr, buf, modseq); - } else { - lseek(fd, hdr.size - sizeof(hdr), SEEK_CUR); - } - return 1; -} - -int main(int argc, const char *argv[]) -{ - uint64_t modseq; - int fd, ret; - - lib_init(); - - if (argc < 2) - i_fatal("Usage: logview dovecot.index.log"); - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - i_error("open(): %m"); - return 1; - } - - dump_hdr(fd, &modseq); - do { - T_BEGIN { - ret = dump_record(fd, &modseq); - } T_END; - } while (ret > 0); - return 0; -}
--- a/src/util/mailboxlogview.c Thu Oct 08 20:10:49 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "hex-binary.h" -#include "mailbox-log.h" - -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> - -static const char *unixdate2str(time_t timestamp) -{ - static char buf[64]; - struct tm *tm; - - tm = localtime(×tamp); - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); - return buf; -} - -static int dump_record(int fd) -{ - off_t offset; - ssize_t ret; - struct mailbox_log_record rec; - time_t timestamp; - - offset = lseek(fd, 0, SEEK_CUR); - - ret = read(fd, &rec, sizeof(rec)); - if (ret == 0) - return 0; - - if (ret != sizeof(rec)) { - i_fatal("rec read() %"PRIuSIZE_T" != %"PRIuSIZE_T, - ret, sizeof(rec)); - } - - printf("#%"PRIuUOFF_T": ", offset); - switch (rec.type) { - case MAILBOX_LOG_RECORD_DELETE_MAILBOX: - printf("delete-mailbox"); - break; - case MAILBOX_LOG_RECORD_DELETE_DIR: - printf("delete-dir"); - break; - case MAILBOX_LOG_RECORD_RENAME: - printf("rename"); - break; - case MAILBOX_LOG_RECORD_SUBSCRIBE: - printf("subscribe"); - break; - case MAILBOX_LOG_RECORD_UNSUBSCRIBE: - printf("unsubscribe"); - break; - } - printf(" %s", binary_to_hex(rec.mailbox_guid, - sizeof(rec.mailbox_guid))); - - timestamp = ((uint32_t)rec.timestamp[0] << 24) | - ((uint32_t)rec.timestamp[1] << 16) | - ((uint32_t)rec.timestamp[2] << 8) | - (uint32_t)rec.timestamp[3]; - printf(" (%s)\n", unixdate2str(timestamp)); - return 1; -} - -int main(int argc, const char *argv[]) -{ - int fd, ret; - - lib_init(); - - if (argc < 2) - i_fatal("Usage: logview dovecot.mailbox.log"); - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - i_error("open(): %m"); - return 1; - } - - do { - T_BEGIN { - ret = dump_record(fd); - } T_END; - } while (ret > 0); - return 0; -}
--- a/src/util/threadview.c Thu Oct 08 20:10:49 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "mmap-util.h" -#include "mail-index-private.h" -#include "mail-index-strmap.h" - -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/stat.h> - -static uint32_t max_likely_index; - -uint32_t mail_index_offset_to_uint32(uint32_t offset) -{ - const unsigned char *buf = (const unsigned char *) &offset; - - if ((offset & 0x80808080) != 0x80808080) - return 0; - - return (((uint32_t)buf[3] & 0x7f) << 2) | - (((uint32_t)buf[2] & 0x7f) << 9) | - (((uint32_t)buf[1] & 0x7f) << 16) | - (((uint32_t)buf[0] & 0x7f) << 23); -} - -int mail_index_unpack_num(const uint8_t **p, const uint8_t *end, - uint32_t *num_r) -{ - const uint8_t *c = *p; - uint32_t value = 0; - unsigned int bits = 0; - - for (;;) { - if (unlikely(c == end)) { - /* we should never see EOF */ - *num_r = 0; - return -1; - } - - value |= (*c & 0x7f) << bits; - if (*c < 0x80) - break; - - bits += 7; - c++; - } - - if (unlikely(bits >= 32)) { - /* broken input */ - *p = end; - *num_r = 0; - return -1; - } - - *p = c + 1; - *num_r = value; - return 0; -} - -static size_t dump_hdr(const struct mail_index_strmap_header *hdr) -{ - printf("version = %u\n", hdr->version); - printf("uid validity = %u\n", hdr->uid_validity); - return sizeof(*hdr); -} - -static int dump_record(const uint8_t **p, const uint8_t *end, uint32_t *uid) -{ - uint32_t uid_diff, n, i, count, crc32, idx; - size_t size; - - /* <uid diff> <n> <crc32>*count <str_idx>*count */ - if (mail_index_unpack_num(p, end, &uid_diff) < 0) - return -1; - *uid += uid_diff; - - if (mail_index_unpack_num(p, end, &n) < 0) - return -1; - printf(" - uid %u: n=%u\n", *uid, n); - - count = n < 2 ? n + 1 : n; - size = sizeof(crc32)*count + sizeof(idx)*count; - if (*p + size > end) - return -1; - for (i = 0; i < count; i++) { - if (i == 0) - printf(" - message-id: "); - else if (i == 1) { - if (n == 1) - printf(" - in-reply-to: "); - else - printf(" - references[1]: "); - } else { - printf(" - references[%u]: ", i); - } - memcpy(&crc32, *p + sizeof(crc32)*i, sizeof(crc32)); - memcpy(&idx, *p + sizeof(crc32)*count + sizeof(idx)*i, sizeof(idx)); - printf("crc32=%08x index=%u\n", crc32, idx); - if (idx > max_likely_index) - printf(" - index probably broken\n"); - } - *p += size; - return 0; -} - -static int dump_block(const uint8_t *data, const uint8_t *end, uint32_t *uid) -{ - const uint8_t *p; - uint32_t block_size; - - if (data + 4 >= end) - return -1; - - memcpy(&block_size, data, sizeof(block_size)); - block_size = mail_index_offset_to_uint32(block_size) >> 2; - printf(" - block_size=%u\n", block_size); - if (block_size == 0) { - /* finished */ - return -1; - } - if (data + sizeof(block_size) + block_size > end) { - printf(" - broken!\n"); - return -1; - } - p = data + sizeof(block_size); - end = p + block_size; - - *uid += 1; - while (p != end) { - if (dump_record(&p, end, uid) < 0) { - printf(" - broken\n"); - return -1; - } - } - return p - data; -} - -int main(int argc, const char *argv[]) -{ - unsigned int pos; - const void *map, *end; - struct stat st; - uint32_t uid; - int fd, ret; - - lib_init(); - - if (argc < 2) - i_fatal("Usage: threadview dovecot.index.thread"); - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - i_error("open(%s) failed: %m", argv[1]); - return 1; - } - - if (fstat(fd, &st) < 0) { - i_error("fstat(%s) failed: %m", argv[1]); - return 1; - } - max_likely_index = (st.st_size / 8) * 2; - - map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) - i_fatal("mmap() failed: %m"); - end = CONST_PTR_OFFSET(map, st.st_size); - pos = dump_hdr(map); - uid = 0; - do { - printf("block at offset %u:\n", pos); - T_BEGIN { - ret = dump_block(CONST_PTR_OFFSET(map, pos), end, &uid); - pos += ret; - } T_END; - } while (ret > 0); - return 0; -}