[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