[dovecot-cvs] dovecot/src/util Makefile.am, 1.8, 1.8.2.1 idxview.c, NONE, 1.1.2.1 logview.c, NONE, 1.1.2.1
tss at dovecot.org
tss at dovecot.org
Tue Mar 20 17:00:24 EET 2007
Update of /var/lib/cvs/dovecot/src/util
In directory talvi:/tmp/cvs-serv10679
Modified Files:
Tag: branch_1_0
Makefile.am
Added Files:
Tag: branch_1_0
idxview.c logview.c
Log Message:
Added idxview and logview to dump index/cache/log file contents.
Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/util/Makefile.am,v
retrieving revision 1.8
retrieving revision 1.8.2.1
diff -u -d -r1.8 -r1.8.2.1
--- Makefile.am 14 Jan 2006 12:46:33 -0000 1.8
+++ Makefile.am 20 Mar 2007 15:00:22 -0000 1.8.2.1
@@ -1,10 +1,12 @@
pkglibexecdir = $(libexecdir)/dovecot
-pkglibexec_PROGRAMS = rawlog gdbhelper
+pkglibexec_PROGRAMS = rawlog gdbhelper idxview logview
sbin_PROGRAMS = dovecotpw
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-mail \
+ -I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/auth
rawlog_LDADD = \
@@ -19,6 +21,18 @@
gdbhelper_SOURCES = \
gdbhelper.c
+idxview_LDADD = \
+ ../lib/liblib.a
+
+idxview_SOURCES = \
+ idxview.c
+
+logview_LDADD = \
+ ../lib/liblib.a
+
+logview_SOURCES = \
+ logview.c
+
dovecotpw_LDADD = \
../auth/libpassword.a \
../lib-ntlm/libntlm.a \
--- NEW FILE: idxview.c ---
/* Copyright (C) 2007 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hex-binary.h"
#include "mail-index-private.h"
#include "mail-cache-private.h"
#include "mail-transaction-log.h"
#include <stdio.h>
#include <stdlib.h>
static struct mail_index_header hdr;
static array_t ARRAY_DEFINE(extensions, struct mail_index_ext);
static struct mail_cache_header cache_hdr;
static array_t ARRAY_DEFINE(cache_fields, struct mail_cache_field);
static unsigned int cache_ext = (unsigned int)-1;
static unsigned int cache_search_offset = 0;
static int cache_fd = -1;
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 size_t get_align(size_t name_len)
{
size_t size = sizeof(struct mail_index_ext_header) + name_len;
return MAIL_INDEX_HEADER_SIZE_ALIGN(size) - size;
}
static void dump_hdr(int fd)
{
const struct mail_index_ext_header *ext_hdr;
struct mail_index_ext ext;
char *base;
ssize_t ret;
unsigned int i, offset, name_offset;
ret = read(fd, &hdr, sizeof(hdr));
if (ret != sizeof(hdr)) {
i_fatal("file hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T,
ret, sizeof(hdr));
}
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\n", hdr.indexid);
printf("flags = %u\n", hdr.flags);
printf("uid validity = %u\n", hdr.uid_validity);
printf("next uid = %u\n", hdr.next_uid);
printf("messages count = %u\n", hdr.messages_count);
printf("recent messages count = %u\n", hdr.recent_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 lowwater = %u\n", hdr.first_recent_uid_lowwater);
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);
printf("log file int offset = %u\n", hdr.log_file_int_offset);
printf("log file ext offset = %u\n", hdr.log_file_ext_offset);
printf("sync size = %llu\n", (unsigned long long)hdr.sync_size);
printf("sync stamp = %u\n", hdr.sync_stamp);
printf("day stamp = %u\n", hdr.day_stamp);
for (i = 0; i < 8; i++)
printf("day first uid[%u] = %u\n", i, hdr.day_first_uid[i]);
ARRAY_CREATE(&extensions, default_pool, struct mail_index_ext, 16);
offset = MAIL_INDEX_HEADER_SIZE_ALIGN(hdr.base_header_size);
if (offset >= hdr.header_size) {
printf("no extensions\n");
return;
}
base = i_malloc(hdr.header_size);
ret = pread(fd, base, hdr.header_size, 0);
if (ret != hdr.header_size) {
i_fatal("file hdr read() %"PRIuSIZE_T" != %u",
ret, hdr.header_size);
}
memset(&ext, 0, sizeof(ext)); i = 0;
while (offset < hdr.header_size) {
ext_hdr = CONST_PTR_OFFSET(base, offset);
offset += sizeof(*ext_hdr);
name_offset = offset;
offset += ext_hdr->name_size + get_align(ext_hdr->name_size);
ext.name = i_strndup(CONST_PTR_OFFSET(base, name_offset),
ext_hdr->name_size);
ext.record_offset = ext_hdr->record_offset;
ext.record_size = ext_hdr->record_size;
ext.record_align = ext_hdr->record_align;
if (strcmp(ext.name, "cache") == 0)
cache_ext = i;
printf("-- Extension %u --\n", i);
printf("name: %s\n", ext.name);
printf("hdr_size: %u\n", ext_hdr->hdr_size);
printf("reset_id: %u\n", ext_hdr->reset_id);
printf("record_offset: %u\n", ext_hdr->record_offset);
printf("record_size: %u\n", ext_hdr->record_size);
printf("record_align: %u\n", ext_hdr->record_align);
printf("name_size: %u\n", ext_hdr->name_size);
offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
array_append(&extensions, &ext, 1);
i++;
}
}
static void dump_cache_hdr(int fd)
{
struct mail_cache_header_fields fields;
struct mail_cache_field field;
uint32_t field_offset, next_offset;
char *buf;
ssize_t ret;
const uint32_t *last_used, *size;
const uint8_t *type, *decision;
const char *names;
unsigned int i;
ret = read(fd, &cache_hdr, sizeof(cache_hdr));
if (ret != sizeof(cache_hdr)) {
i_fatal("cache file hdr read() %"PRIuSIZE_T" != %"PRIuSIZE_T,
ret, sizeof(cache_hdr));
}
field_offset =
mail_index_offset_to_uint32(cache_hdr.field_header_offset);
printf("Cache header:\n");
printf("version: %u\n", cache_hdr.version);
printf("indexid: %u\n", cache_hdr.indexid);
printf("file_seq: %u\n", cache_hdr.file_seq);
printf("continued_record_count: %u\n", cache_hdr.continued_record_count);
printf("hole_offset: %u\n", cache_hdr.hole_offset);
printf("used_file_size: %u\n", cache_hdr.used_file_size);
printf("deleted_space: %u\n", cache_hdr.deleted_space);
printf("field_header_offset: %u / %u\n",
cache_hdr.field_header_offset, field_offset);
for (;;) {
ret = pread(fd, &fields, sizeof(fields), field_offset);
if (ret != sizeof(fields)) {
i_fatal("cache file fields read() %"
PRIuSIZE_T" != %"PRIuSIZE_T,
ret, sizeof(fields));
}
next_offset =
mail_index_offset_to_uint32(fields.next_offset);
if (next_offset == 0)
break;
field_offset = next_offset;
}
printf("-- Cache fields: --\n");
printf("actual used header offset: %u\n", field_offset);
buf = i_malloc(fields.size);
ret = pread(fd, buf, fields.size, field_offset);
if (ret != fields.size) {
i_fatal("cache file fields read() %"PRIuSIZE_T" != %u",
ret, fields.size);
}
last_used = CONST_PTR_OFFSET(buf, MAIL_CACHE_FIELD_LAST_USED());
size = CONST_PTR_OFFSET(buf, MAIL_CACHE_FIELD_SIZE(fields.fields_count));
type = CONST_PTR_OFFSET(buf, MAIL_CACHE_FIELD_TYPE(fields.fields_count));
decision = CONST_PTR_OFFSET(buf, MAIL_CACHE_FIELD_DECISION(fields.fields_count));
names = CONST_PTR_OFFSET(buf, MAIL_CACHE_FIELD_NAMES(fields.fields_count));
ARRAY_CREATE(&cache_fields, default_pool, struct mail_cache_field, 64);
memset(&field, 0, sizeof(field));
for (i = 0; i < fields.fields_count; i++) {
field.name = names;
field.field_size = size[i];
field.type = type[i];
field.decision = decision[i];
array_append(&cache_fields, &field, 1);
printf("%u: name=%s size=%u type=%u decision=%u last_used=%u\n",
i, names, size[i], type[i], decision[i], last_used[i]);
names += strlen(names) + 1;
}
}
static void dump_cache(uint32_t offset)
{
const struct mail_cache_field *fields;
struct mail_cache_record rec;
ssize_t ret;
char *buf;
unsigned int idx, size, pos, next_pos, cache_fields_count;
string_t *str;
if (offset == 0 || cache_fd == -1)
return;
ret = pread(cache_fd, &rec, sizeof(rec), offset);
if (ret != sizeof(rec)) {
printf(" - cache at %u BROKEN: points outside file\n", offset);
return;
}
if (rec.size > 1000000) {
printf(" - cache at %u BROKEN: rec.size = %u\n",
offset, rec.size);
return;
}
if (offset <= cache_search_offset &&
offset + rec.size > cache_search_offset)
printf(" - SEARCH MATCH\n");
buf = t_malloc(rec.size);
ret = pread(cache_fd, buf, rec.size, offset);
if (ret != rec.size)
i_fatal("cache rec read() %"PRIuSIZE_T" != %u", ret, rec.size);
printf(" - cache at %u + %u (prev_offset = %u)\n",
offset, rec.size, rec.prev_offset);
fields = array_get(&cache_fields, &cache_fields_count);
str = t_str_new(512);
for (pos = sizeof(rec); pos < rec.size; ) {
idx = *((const uint32_t *)(buf+pos));
pos += sizeof(uint32_t);
if (idx >= cache_fields_count) {
printf("BROKEN: file_field = %u > %u\n",
idx, cache_fields_count);
return;
}
size = fields[idx].field_size;
if (size == (unsigned int)-1) {
size = *((const uint32_t *)(buf+pos));
pos += sizeof(uint32_t);
}
next_pos = pos + ((size + 3) & ~3);
if (size > rec.size || next_pos > rec.size) {
printf("BROKEN: record continues outside its allocated size\n");
return;
}
str_truncate(str, 0);
str_printfa(str, " - %s: ", fields[idx].name);
switch (fields[idx].type) {
case MAIL_CACHE_FIELD_FIXED_SIZE:
if (size == sizeof(uint32_t)) {
str_printfa(str, "%u", *((const uint32_t *)(buf+pos)));
break;
}
case MAIL_CACHE_FIELD_VARIABLE_SIZE:
case MAIL_CACHE_FIELD_BITMASK:
str_printfa(str, " (%s)", binary_to_hex((const unsigned char *)buf+pos, size));
break;
case MAIL_CACHE_FIELD_STRING:
if (size > 0)
str_printfa(str, "%.*s", (int)size, buf+pos);
break;
case MAIL_CACHE_FIELD_HEADER: {
const uint32_t *lines = (void *)(buf + pos);
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);
pos += 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 && buf[pos+size-1] == '\n') size--;
if (size > 0)
str_printfa(str, ": %.*s", (int)size, buf+pos);
break;
}
case MAIL_CACHE_FIELD_COUNT:
i_unreached();
break;
}
printf("%s\n", str_c(str));
pos = next_pos;
}
dump_cache(rec.prev_offset);
}
static int dump_record(int fd, void *buf, unsigned int seq)
{
off_t offset;
ssize_t ret;
const struct mail_index_record *rec = buf;
const struct mail_index_ext *ext;
const void *ptr;
unsigned int i, ext_count;
string_t *str;
ret = read(fd, buf, hdr.record_size);
if (ret == 0)
return 0;
if (ret != hdr.record_size) {
i_fatal("rec hdr read() %"PRIuSIZE_T" != %u",
ret, hdr.record_size);
}
offset = lseek(fd, 0, SEEK_CUR);
printf("RECORD: offset=%"PRIuUOFF_T", seq=%u, uid=%u, flags=%x\n",
offset, seq, rec->uid, rec->flags);
str = t_str_new(256);
ext = array_get(&extensions, &ext_count);
for (i = 0; i < ext_count; i++) {
str_truncate(str, 0);
str_printfa(str, " - ext %s(%u): ", ext[i].name, i);
ptr = CONST_PTR_OFFSET(buf, ext[i].record_offset);
if (ext[i].record_size == sizeof(uint32_t) &&
ext[i].record_align == sizeof(uint32_t))
str_printfa(str, "%u", *((const uint32_t *)ptr));
else if (ext[i].record_size == sizeof(uint64_t) &&
ext[i].record_align == sizeof(uint64_t)) {
uint64_t value = *((const uint64_t *)ptr);
str_printfa(str, "%llu", (unsigned long long)value);
}
str_printfa(str, " (%s)", binary_to_hex(ptr, ext[i].record_size));
printf("%s\n", str_c(str));
if (i == cache_ext)
dump_cache(*((const uint32_t *)ptr));
}
return 1;
}
int main(int argc, const char *argv[])
{
unsigned int seq;
void *buf;
int fd, ret;
lib_init();
if (argc < 2)
i_fatal("Usage: idxview dovecot.index [dovecot.index.cache]");
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
i_error("open(): %m");
return 1;
}
printf("-- INDEX: %s\n", argv[1]);
dump_hdr(fd);
lseek(fd, hdr.header_size, SEEK_SET);
printf("---------------\n");
if (argv[2] != NULL) {
cache_fd = open(argv[2], O_RDONLY);
if (cache_fd < 0) {
i_error("open(): %m");
return 1;
}
dump_cache_hdr(cache_fd);
printf("---------------\n");
if (argv[3] != NULL)
cache_search_offset = atoi(argv[3]);
}
buf = i_malloc(hdr.record_size);
seq = 1;
do {
t_push();
ret = dump_record(fd, buf, seq);
t_pop();
seq++;
} while (ret);
return 0;
}
--- NEW FILE: logview.c ---
/* Copyright (C) 2007 Timo Sirainen */
#include "lib.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)
{
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));
}
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);
}
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_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;
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 log_record_print(const struct mail_transaction_header *hdr,
const void *data)
{
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_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;
printf(" - offset = %u, size = %u: ", u->offset, u->size);
print_data(u + 1, u->size);
printf("\n");
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(" - name_size = %u\n", intro->name_size);
if (intro->name_size > 0) {
printf(" - name = '%.*s'\n",
intro->name_size, (const char *)(intro+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);
break;
}
case MAIL_TRANSACTION_EXT_HDR_UPDATE:
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_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;
}
default:
break;
}
}
static int dump_record(int fd)
{
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\n",
offset, log_record_type(hdr.type), hdr.size);
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);
} else {
lseek(fd, hdr.size - sizeof(hdr), SEEK_CUR);
}
return 1;
}
int main(int argc, const char *argv[])
{
int fd;
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);
for (;;) {
t_push();
if (!dump_record(fd))
break;
t_pop();
}
t_pop();
return 0;
}
More information about the dovecot-cvs
mailing list