view src/util/doveadm.c @ 9869:464c01ae9f0c HEAD

lmtp, expire-tool, doveadm: Set service for config lookups.
author Timo Sirainen <tss@iki.fi>
date Fri, 04 Sep 2009 14:30:29 -0400
parents 653183a81b6c
children
line wrap: on
line source

/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "lib-signals.h"
#include "ioloop.h"
#include "env-util.h"
#include "master-service.h"
#include "mail-user.h"
#include "mail-namespace.h"
#include "mail-storage.h"
#include "mail-storage-settings.h"
#include "mail-storage-service.h"

#include <stdio.h>
#include <stdlib.h>

static struct mail_user *mail_user;
static int killed_signo = 0;

static void ATTR_NORETURN
usage(void)
{
	i_fatal(
"usage: doveadm \n"
"  purge <user>\n"
"  force-resync <user> <mailbox>\n"
);
}

static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
{
	killed_signo = si->si_signo;
}

static void cmd_purge(struct mail_user *user)
{
	struct mail_namespace *ns;

	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
		if (ns->type != NAMESPACE_PRIVATE || ns->alias_for != NULL)
			continue;

		if (mail_storage_purge(ns->storage) < 0) {
			i_error("Purging namespace '%s' failed: %s", ns->prefix,
				mail_storage_get_last_error(ns->storage, NULL));
		}
	}
}

static struct mailbox *
mailbox_find_and_open(struct mail_user *user, const char *mailbox)
{
	struct mail_namespace *ns;
	struct mailbox *box;
	const char *orig_mailbox = mailbox;

	ns = mail_namespace_find(user->namespaces, &mailbox);
	if (ns == NULL)
		i_fatal("Can't find namespace for mailbox %s", mailbox);

	box = mailbox_alloc(ns->list, mailbox, NULL, MAILBOX_FLAG_KEEP_RECENT |
			    MAILBOX_FLAG_IGNORE_ACLS);
	if (mailbox_open(box) < 0) {
		i_fatal("Opening mailbox %s failed: %s", orig_mailbox,
			mail_storage_get_last_error(mailbox_get_storage(box),
						    NULL));
	}
	return box;
}

static void cmd_force_resync(struct mail_user *user, const char *mailbox)
{
	struct mail_storage *storage;
	struct mailbox *box;

	if (mailbox == NULL)
		usage();

	box = mailbox_find_and_open(user, mailbox);
	storage = mailbox_get_storage(box);
	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FORCE_RESYNC |
			 MAILBOX_SYNC_FLAG_FIX_INCONSISTENT, 0, NULL) < 0) {
		i_fatal("Forcing a resync on mailbox %s failed: %s", mailbox,
			mail_storage_get_last_error(storage, NULL));
	}
	mailbox_close(&box);
}

static void handle_command(struct mail_user *mail_user, const char *cmd,
			   char *args[])
{
	if (strcmp(cmd, "purge") == 0)
		cmd_purge(mail_user);
	else if (strcmp(cmd, "force-resync") == 0)
		cmd_force_resync(mail_user, args[0]);
	else
		usage();
}

static void
handle_single_user(struct master_service *service, const char *username,
		   enum mail_storage_service_flags service_flags, char *argv[])
{
	struct mail_storage_service_input input;

	if (username == NULL)
		i_fatal("USER environment is missing and -u option not used");

	memset(&input, 0, sizeof(input));
	input.username = username;
	mail_user = mail_storage_service_init_user(service, &input, NULL,
						   service_flags);
	handle_command(mail_user, argv[0], argv+1);
	mail_user_unref(&mail_user);
	mail_storage_service_deinit_user();
}

static int
handle_next_user(struct mail_storage_service_multi_ctx *multi,
		 const struct mail_storage_service_input *input,
		 pool_t pool, char *argv[])
{
	struct mail_storage_service_multi_user *multi_user;
	const char *error;
	int ret;

	i_set_failure_prefix(t_strdup_printf("doveadm(%s): ", input->username));
	ret = mail_storage_service_multi_lookup(multi, input, pool,
						&multi_user, &error);
	if (ret <= 0) {
		if (ret == 0) {
			i_info("User no longer exists, skipping");
			return 0;
		} else {
			i_error("User lookup failed: %s", error);
			return -1;
		}
	}
	if (mail_storage_service_multi_next(multi, multi_user,
					    &mail_user, &error) < 0) {
		i_error("User init failed: %s", error);
		mail_storage_service_multi_user_free(multi_user);
		return -1;
	}
	mail_storage_service_multi_user_free(multi_user);
	handle_command(mail_user, argv[0], argv+1);
	mail_user_unref(&mail_user);
	return 0;
}

static void
handle_all_users(struct master_service *service,
		 enum mail_storage_service_flags service_flags, char *argv[])
{
	struct mail_storage_service_input input;
	struct mail_storage_service_multi_ctx *multi;
	unsigned int user_idx, user_count, interval, n;
	const char *user;
	pool_t pool;
	int ret;

	service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;

	memset(&input, 0, sizeof(input));
	input.service = "doveadm";

	multi = mail_storage_service_multi_init(service, NULL, service_flags);
	pool = pool_alloconly_create("multi user", 8192);

        lib_signals_set_handler(SIGINT, FALSE, sig_die, NULL);
	lib_signals_set_handler(SIGTERM, FALSE, sig_die, NULL);

	user_count = mail_storage_service_multi_all_init(multi);
	n = user_count / 10000;
	for (interval = 10; n > 0 && interval < 1000; interval *= 10)
		n /= 10;
	
	user_idx = 0;
	while ((ret = mail_storage_service_multi_all_next(multi, &user)) > 0) {
		p_clear(pool);
		input.username = user;
		T_BEGIN {
			ret = handle_next_user(multi, &input, pool, argv);
		} T_END;
		if (ret < 0)
			break;
		if ((service_flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0) {
			if (++user_idx % interval == 0) {
				printf("\r%d / %d", user_idx, user_count);
				fflush(stdout);
			}
		}
		if (killed_signo != 0) {
			i_warning("Killed with signal %d", killed_signo);
			ret = -1;
			break;
		}
	}
	if ((service_flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0)
		printf("\n");
	i_set_failure_prefix("doveadm: ");
	if (ret < 0)
		i_error("Failed to iterate through some users");
	mail_storage_service_multi_deinit(&multi);
	pool_unref(&pool);
}

int main(int argc, char *argv[])
{
	enum mail_storage_service_flags service_flags = 0;
	const char *getopt_str, *username;
	bool all_users = FALSE;
	int c;

	master_service = master_service_init("doveadm",
					     MASTER_SERVICE_FLAG_STANDALONE,
					     argc, argv);

	username = getenv("USER");
	getopt_str = t_strconcat("au:v", master_service_getopt_string(), NULL);
	while ((c = getopt(argc, argv, getopt_str)) > 0) {
		switch (c) {
		case 'a':
			all_users = TRUE;
			break;
		case 'u':
			username = optarg;
			service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
			break;
		case 'v':
			service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
			break;
		default:
			if (!master_service_parse_option(master_service,
							 c, optarg))
				usage();
		}
	}
	if (optind == argc)
		usage();

	if (!all_users) {
		handle_single_user(master_service, username, service_flags,
				   argv + optind);
	} else {
		handle_all_users(master_service, service_flags, argv + optind);
	}
	master_service_deinit(&master_service);
	return 0;
}