bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen#include "lib.h"
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen#include "array.h"
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen#include "istream.h"
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen#include "istream-multiplex.h"
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen#include "doveadm.h"
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen#include "doveadm-dump.h"
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen#include <stdio.h>
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen#include <unistd.h>
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(const struct doveadm_cmd_dump *) dumps;
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainenvoid doveadm_dump_register(const struct doveadm_cmd_dump *dump)
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen{
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen array_append(&dumps, &dump, 1);
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen}
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainenstatic const struct doveadm_cmd_dump *
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainendump_find_name(const char *name)
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen{
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen const struct doveadm_cmd_dump *const *dumpp;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen array_foreach(&dumps, dumpp) {
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen if (strcmp((*dumpp)->name, name) == 0)
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen return *dumpp;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen return NULL;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen}
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainenstatic const struct doveadm_cmd_dump *
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainendump_find_test(const char *path)
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen{
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen const struct doveadm_cmd_dump *const *dumpp;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen array_foreach(&dumps, dumpp) {
8fe0b13a23c5e98d090f94399581fe2c7b5239edTimo Sirainen if ((*dumpp)->test != NULL && (*dumpp)->test(path))
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen return *dumpp;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen return NULL;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen}
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainenstatic void cmd_dump(int argc, char *argv[])
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen{
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen const struct doveadm_cmd_dump *dump;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen const char *type = NULL;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen int c;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen while ((c = getopt(argc, argv, "t:")) > 0) {
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen switch (c) {
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen case 't':
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen type = optarg;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen break;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen default:
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen help(&doveadm_cmd_dump);
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen if (optind == argc)
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen help(&doveadm_cmd_dump);
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen optind--;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen argc -= optind;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen argv += optind;
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen dump = type != NULL ? dump_find_name(type) : dump_find_test(argv[1]);
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen if (dump == NULL) {
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk if (type != NULL) {
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk print_dump_types();
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen i_fatal_status(EX_USAGE, "Unknown type: %s", type);
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk } else {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen i_fatal_status(EX_DATAERR,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen "Can't autodetect file type: %s", argv[1]);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen } else {
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen if (type == NULL)
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen printf("Detected file type: %s\n", dump->name);
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen }
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen dump->cmd(argc, argv);
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen}
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainenstruct doveadm_cmd doveadm_cmd_dump = {
bde78a7bf5f9000f1ae4dc7ce6cabd012e1f8b79Pascal Volk cmd_dump, "dump", "[-t <type>] <path>"
c664d0da658c8d3200d88ea3c4cd580afd33fa73Timo Sirainen};
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainenstatic void cmd_dump_multiplex(int argc ATTR_UNUSED, char *argv[])
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen{
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen const unsigned int channels_count = 256;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen struct istream *file_input, *channels[channels_count];
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen const unsigned char *data;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen size_t size;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen unsigned int i;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen file_input = i_stream_create_file(argv[1], IO_BLOCK_SIZE);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen /* A bit kludgy: istream-multiplex returns 0 if a wrong channel is
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen being read from. This causes a panic with blocking istreams.
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen Work around this by assuming that the file istream isn't blocking. */
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen file_input->blocking = FALSE;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen channels[0] = i_stream_create_multiplex(file_input, IO_BLOCK_SIZE);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen i_stream_unref(&file_input);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen for (i = 1; i < channels_count; i++)
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen channels[i] = i_stream_multiplex_add_channel(channels[0], i);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen bool have_input;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen do {
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen have_input = FALSE;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen for (i = 0; i < channels_count; i++) {
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen if (i_stream_read_more(channels[i], &data, &size) > 0) {
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen printf("CHANNEL %u: %zu bytes:\n", i, size);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen fwrite(data, 1, size, stdout);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen printf("\n");
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen have_input = TRUE;
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen i_stream_skip(channels[i], size);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen }
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen }
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen } while (have_input);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen if (channels[0]->stream_errno != 0)
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen i_error("read() failed: %s", i_stream_get_error(channels[0]));
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen for (i = 0; i < channels_count; i++)
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen i_stream_unref(&channels[i]);
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen}
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainenstruct doveadm_cmd_dump doveadm_cmd_dump_multiplex = {
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen "multiplex",
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen NULL,
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen cmd_dump_multiplex
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen};
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainenstatic const struct doveadm_cmd_dump *dumps_builtin[] = {
f05f569c2ee0d1f5216614856ff0ae7bd60f27faTimo Sirainen &doveadm_cmd_dump_dbox,
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen &doveadm_cmd_dump_index,
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen &doveadm_cmd_dump_log,
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen &doveadm_cmd_dump_mailboxlog,
4605cab1123700c52c515a433a2802fcbc827c62Timo Sirainen &doveadm_cmd_dump_thread,
ceee39b0d2f8f5705b05cccb010c764e9771a9bcMartti Rannanjärvi &doveadm_cmd_dump_zlib,
35de0999ddf1b445ac56c19b72be6e0053049eaaMartti Rannanjärvi &doveadm_cmd_dump_dcrypt_file,
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen &doveadm_cmd_dump_dcrypt_key,
b712b80422b22103c222132b4db9e00811dadeaeTimo Sirainen &doveadm_cmd_dump_multiplex,
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen};
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volkvoid print_dump_types(void)
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk{
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk unsigned int i;
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk fprintf(stderr, "Available dump types: %s", dumps_builtin[0]->name);
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk for (i = 1; i < N_ELEMENTS(dumps_builtin); i++)
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk fprintf(stderr, " %s", dumps_builtin[i]->name);
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk fprintf(stderr, "\n");
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk}
4f77d2f0f0743ad09d2a34e18be8eacf8014b7e0Pascal Volk
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainenvoid doveadm_dump_init(void)
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen{
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen unsigned int i;
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen i_array_init(&dumps, N_ELEMENTS(dumps_builtin) + 8);
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen for (i = 0; i < N_ELEMENTS(dumps_builtin); i++)
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen doveadm_dump_register(dumps_builtin[i]);
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen}
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainenvoid doveadm_dump_deinit(void)
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen{
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen array_free(&dumps);
134582c78f038b4d9b9fde127399aefa50935a53Timo Sirainen}