diff src/util/logview.c @ 5366:a42014a7d8be HEAD

Added idxview and logview to dump index/cache/log file contents.
author Timo Sirainen <tss@iki.fi>
date Tue, 20 Mar 2007 17:00:25 +0200
parents
children cb5e25c3b300
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/util/logview.c	Tue Mar 20 17:00:25 2007 +0200
@@ -0,0 +1,288 @@
+/* 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;
+}