From: Timo Sirainen Date: Thu, 29 Dec 2011 12:43:45 +0000 (+0200) Subject: Merged dsync into "doveadm dsync". X-Git-Tag: 2.1.rc2~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=885a3c2287ae3e5827aa580ea06b231de38abb47;p=thirdparty%2Fdovecot%2Fcore.git Merged dsync into "doveadm dsync". dsync symlink is installed for backwards compatibility. --- diff --git a/.hgignore b/.hgignore index 77706904f5..71a9fe5ea2 100644 --- a/.hgignore +++ b/.hgignore @@ -66,7 +66,6 @@ src/director/director-test src/dns/dns-client src/doveadm/doveadm src/doveadm/doveadm-server -src/dsync/dsync src/imap-login/imap-login src/imap/imap src/indexer/indexer diff --git a/configure.in b/configure.in index aa01f2ad7f..0d0adbbf58 100644 --- a/configure.in +++ b/configure.in @@ -2750,7 +2750,7 @@ src/anvil/Makefile src/auth/Makefile src/config/Makefile src/doveadm/Makefile -src/dsync/Makefile +src/doveadm/dsync/Makefile src/lda/Makefile src/log/Makefile src/lmtp/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index c4f0a9a818..aff742660f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,7 +41,6 @@ SUBDIRS = \ director \ util \ doveadm \ - dsync \ ssl-params \ stats \ plugins diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 6e76048be2..e7e05d8013 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -1,6 +1,8 @@ doveadm_moduledir = $(moduledir)/doveadm pkglibexecdir = $(libexecdir)/dovecot +SUBDIRS = dsync + bin_PROGRAMS = doveadm pkglibexec_PROGRAMS = doveadm-server @@ -35,6 +37,7 @@ cmd_pw_libs = \ ../lib-otp/libotp.a libs = \ + dsync/libdsync.a \ $(LIBDOVECOT_STORAGE) \ $(unused_objects) @@ -122,3 +125,7 @@ noinst_HEADERS = \ doveadm-settings.h \ doveadm-util.h \ doveadm-who.h + +install-exec-local: + rm -f $(DESTDIR)$(bindir)/dsync + $(LN_S) doveadm $(DESTDIR)$(bindir)/dsync diff --git a/src/doveadm/client-connection.c b/src/doveadm/client-connection.c index b5b3cb3ee5..76b96027d0 100644 --- a/src/doveadm/client-connection.c +++ b/src/doveadm/client-connection.c @@ -41,9 +41,6 @@ doveadm_mail_cmd_server(const char *cmd_name, const struct mail_storage_service_input *input, int argc, char *argv[]) { - enum mail_storage_service_flags service_flags = - MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT | - MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; struct doveadm_mail_cmd_context *ctx; const struct doveadm_mail_cmd *cmd; const char *getopt_args; @@ -56,12 +53,15 @@ doveadm_mail_cmd_server(const char *cmd_name, return FALSE; } - if (doveadm_debug) - service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; - ctx = doveadm_mail_cmd_init(cmd, set); ctx->full_args = (const void *)(argv + 1); + ctx->service_flags |= + MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT | + MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; + if (doveadm_debug) + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; + getopt_args = t_strconcat("AS:u:", ctx->getopt_args, NULL); while ((c = getopt(argc, argv, getopt_args)) > 0) { switch (c) { @@ -106,7 +106,10 @@ doveadm_mail_cmd_server(const char *cmd_name, } ctx->args = (const void *)argv; - doveadm_mail_single_user(ctx, input, service_flags); + if (ctx->v.preinit != NULL) + ctx->v.preinit(ctx); + + doveadm_mail_single_user(ctx, input); doveadm_mail_server_flush(); ctx->v.deinit(ctx); doveadm_print_flush(); diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 00b8c15359..872fe8f10b 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -19,6 +19,7 @@ #include "doveadm.h" #include "doveadm-settings.h" #include "doveadm-print.h" +#include "dsync/doveadm-dsync.h" #include "doveadm-mail.h" #include @@ -186,7 +187,6 @@ doveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx, const struct mail_storage_service_input *input, const char **error_r) { - struct mail_storage_service_user *service_user; const char *error; int ret; @@ -199,7 +199,7 @@ doveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx, return ret; ret = mail_storage_service_lookup(ctx->storage_service, input, - &service_user, &error); + &ctx->cur_service_user, &error); if (ret <= 0) { if (ret < 0) { *error_r = t_strdup_printf("User lookup failed: %s", @@ -208,31 +208,32 @@ doveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx, return ret; } - ret = mail_storage_service_next(ctx->storage_service, service_user, + ret = mail_storage_service_next(ctx->storage_service, + ctx->cur_service_user, &ctx->cur_mail_user); if (ret < 0) { *error_r = "User init failed"; - mail_storage_service_user_free(&service_user); + mail_storage_service_user_free(&ctx->cur_service_user); return ret; } ctx->v.run(ctx, ctx->cur_mail_user); mail_user_unref(&ctx->cur_mail_user); - mail_storage_service_user_free(&service_user); + mail_storage_service_user_free(&ctx->cur_service_user); return 1; } void doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx, - const struct mail_storage_service_input *input, - enum mail_storage_service_flags service_flags) + const struct mail_storage_service_input *input) { const char *error; int ret; i_assert(input->username != NULL); + ctx->cur_username = input->username; ctx->storage_service = mail_storage_service_init(master_service, NULL, - service_flags); + ctx->service_flags); ctx->v.init(ctx, ctx->args); if (hook_doveadm_mail_init != NULL) hook_doveadm_mail_init(ctx); @@ -251,21 +252,20 @@ static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED) static void doveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx, char *argv[], - const char *wildcard_user, - enum mail_storage_service_flags service_flags) + const char *wildcard_user) { struct mail_storage_service_input input; unsigned int user_idx, user_count, interval, n; const char *user, *error; int ret; - service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; memset(&input, 0, sizeof(input)); input.service = "doveadm"; ctx->storage_service = mail_storage_service_init(master_service, NULL, - service_flags); + ctx->service_flags); lib_signals_set_handler(SIGINT, 0, sig_die, NULL); lib_signals_set_handler(SIGTERM, 0, sig_die, NULL); @@ -355,20 +355,19 @@ doveadm_mail_cmd_init(const struct doveadm_mail_cmd *cmd, static void doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) { - enum mail_storage_service_flags service_flags = - MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT; struct doveadm_mail_cmd_context *ctx; - const char *getopt_args, *username, *wildcard_user; + const char *getopt_args, *wildcard_user; int c; - if (doveadm_debug) - service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; - ctx = doveadm_mail_cmd_init(cmd, doveadm_settings); ctx->full_args = (const void *)(argv + 1); + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT; + if (doveadm_debug) + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; + getopt_args = t_strconcat("AS:u:", ctx->getopt_args, NULL); - username = getenv("USER"); + ctx->cur_username = getenv("USER"); wildcard_user = NULL; while ((c = getopt(argc, argv, getopt_args)) > 0) { switch (c) { @@ -381,12 +380,14 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) doveadm_settings->doveadm_worker_count = 1; break; case 'u': - service_flags |= + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; - username = optarg; - if (strchr(username, '*') != NULL || - strchr(username, '?') != NULL) - wildcard_user = username; + ctx->cur_username = optarg; + if (strchr(ctx->cur_username, '*') != NULL || + strchr(ctx->cur_username, '?') != NULL) { + wildcard_user = ctx->cur_username; + ctx->cur_username = NULL; + } break; default: if (ctx->v.parse_arg == NULL || @@ -400,6 +401,8 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) cmd->name, argv[0]); } ctx->args = (const void *)argv; + if (ctx->v.preinit != NULL) + ctx->v.preinit(ctx); ctx->iterate_single_user = !ctx->iterate_all_users && wildcard_user == NULL; @@ -412,16 +415,16 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) if (ctx->iterate_single_user) { struct mail_storage_service_input input; - if (username == NULL) + if (ctx->cur_username == NULL) i_fatal("USER environment is missing and -u option not used"); memset(&input, 0, sizeof(input)); input.service = "doveadm"; - input.username = username; - doveadm_mail_single_user(ctx, &input, service_flags); + input.username = ctx->cur_username; + doveadm_mail_single_user(ctx, &input); } else { - service_flags |= MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP; - doveadm_mail_all_users(ctx, argv, wildcard_user, service_flags); + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP; + doveadm_mail_all_users(ctx, argv, wildcard_user); } if (ctx->search_args != NULL) mail_search_args_unref(&ctx->search_args); @@ -432,6 +435,8 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) /* service deinit unloads mail plugins, so do it late */ mail_storage_service_deinit(&ctx->storage_service); + if (ctx->exit_code != 0) + exit(ctx->exit_code); if (ctx->failed) exit(FATAL_DEFAULT); pool_unref(&ctx->pool); @@ -579,7 +584,10 @@ static struct doveadm_mail_cmd *mail_commands[] = { &cmd_mailbox_rename, &cmd_mailbox_subscribe, &cmd_mailbox_unsubscribe, - &cmd_mailbox_status + &cmd_mailbox_status, + &cmd_dsync_backup, + &cmd_dsync_mirror, + &cmd_dsync_server }; void doveadm_mail_init(void) diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index aadea6a025..adca106678 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -4,17 +4,15 @@ #include #include "doveadm-util.h" #include "module-context.h" +#include "mail-storage-service.h" -enum mail_storage_service_flags; struct mailbox; struct mail_user; -struct mail_storage_service_ctx; -struct mail_storage_service_input; -struct mail_storage_service_user; struct doveadm_mail_cmd_context; struct doveadm_mail_cmd_vfuncs { bool (*parse_arg)(struct doveadm_mail_cmd_context *ctx,int c); + void (*preinit)(struct doveadm_mail_cmd_context *ctx); void (*init)(struct doveadm_mail_cmd_context *ctx, const char *const args[]); int (*get_next_user)(struct doveadm_mail_cmd_context *ctx, @@ -42,15 +40,21 @@ struct doveadm_mail_cmd_context { const char *getopt_args; const struct doveadm_settings *set; + enum mail_storage_service_flags service_flags; struct mail_storage_service_ctx *storage_service; /* search args aren't set for all mail commands */ struct mail_search_args *search_args; + const char *cur_username; + struct mail_storage_service_user *cur_service_user; struct mail_user *cur_mail_user; struct doveadm_mail_cmd_vfuncs v; ARRAY_DEFINE(module_contexts, union doveadm_mail_cmd_module_context *); + /* if non-zero, exit with this code */ + int exit_code; + /* We're handling only a single user */ unsigned int iterate_single_user:1; /* We're going through all users (not set for wildcard usernames) */ @@ -86,8 +90,7 @@ struct doveadm_mail_cmd_context * doveadm_mail_cmd_init(const struct doveadm_mail_cmd *cmd, const struct doveadm_settings *set); void doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx, - const struct mail_storage_service_input *input, - enum mail_storage_service_flags service_flags); + const struct mail_storage_service_input *input); int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx, const struct mail_storage_service_input *input, const char **error_r); diff --git a/src/doveadm/doveadm-settings.c b/src/doveadm/doveadm-settings.c index ed3f48040c..bcab8cd74e 100644 --- a/src/doveadm/doveadm-settings.c +++ b/src/doveadm/doveadm-settings.c @@ -60,6 +60,7 @@ static const struct setting_define doveadm_setting_defines[] = { DEF(SET_UINT, doveadm_proxy_port), DEF(SET_STR, doveadm_password), DEF(SET_STR, doveadm_allowed_commands), + DEF(SET_STR, dsync_alt_char), { SET_STRLIST, "plugin", offsetof(struct doveadm_settings, plugin_envs), NULL }, @@ -75,6 +76,7 @@ const struct doveadm_settings doveadm_default_settings = { .doveadm_proxy_port = 0, .doveadm_password = "", .doveadm_allowed_commands = "", + .dsync_alt_char = "_", .plugin_envs = ARRAY_INIT }; diff --git a/src/doveadm/doveadm-settings.h b/src/doveadm/doveadm-settings.h index bc9ef9033d..7843d96b36 100644 --- a/src/doveadm/doveadm-settings.h +++ b/src/doveadm/doveadm-settings.h @@ -10,6 +10,7 @@ struct doveadm_settings { unsigned int doveadm_proxy_port; const char *doveadm_password; const char *doveadm_allowed_commands; + const char *dsync_alt_char; ARRAY_DEFINE(plugin_envs, const char *); }; diff --git a/src/doveadm/doveadm.c b/src/doveadm/doveadm.c index 7344e4d472..4206cab038 100644 --- a/src/doveadm/doveadm.c +++ b/src/doveadm/doveadm.c @@ -12,6 +12,7 @@ #include "doveadm-dump.h" #include "doveadm-mail.h" #include "doveadm-settings.h" +#include "dsync/doveadm-dsync.h" #include "doveadm.h" #include @@ -274,6 +275,8 @@ int main(int argc, char *argv[]) bool quick_init = FALSE; int c; + doveadm_dsync_main(&argc, &argv); + /* "+" is GNU extension to stop at the first non-option. others just accept -+ option. */ master_service = master_service_init("doveadm", service_flags, diff --git a/src/dsync/Makefile.am b/src/doveadm/dsync/Makefile.am similarity index 81% rename from src/dsync/Makefile.am rename to src/doveadm/dsync/Makefile.am index 519c392f79..34589f706a 100644 --- a/src/dsync/Makefile.am +++ b/src/doveadm/dsync/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = dsync +noinst_LIBRARIES = libdsync.a AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ @@ -8,22 +8,14 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ - -I$(top_srcdir)/src/lib-storage - -if !BUILD_SHARED_LIBS -unused_objects = \ - ../lib/mountpoint.o \ - ../lib-storage/mail-search-parser-imap.o -endif + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/doveadm libs = \ - $(LIBDOVECOT_STORAGE) \ - $(unused_objects) + $(LIBDOVECOT_STORAGE) -dsync_LDADD = $(libs) $(LIBDOVECOT) $(MODULE_LIBS) -dsync_DEPENDENCIES = $(libs) $(LIBDOVECOT_DEPS) -dsync_SOURCES = \ - dsync.c \ +libdsync_a_SOURCES = \ + doveadm-dsync.c \ dsync-brain.c \ dsync-brain-msgs.c \ dsync-brain-msgs-new.c \ @@ -55,11 +47,11 @@ test_programs = \ noinst_PROGRAMS = $(test_programs) test_libs = \ - ../lib-test/libtest.la \ - ../lib-mail/libmail.la \ - ../lib-imap/libimap.la \ - ../lib-charset/libcharset.la \ - ../lib/liblib.la + ../../lib-test/libtest.la \ + ../../lib-mail/libmail.la \ + ../../lib-imap/libimap.la \ + ../../lib-charset/libcharset.la \ + ../../lib/liblib.la test_ldadd = \ $(test_libs) \ diff --git a/src/doveadm/dsync/doveadm-dsync.c b/src/doveadm/dsync/doveadm-dsync.c new file mode 100644 index 0000000000..8fa2fdb455 --- /dev/null +++ b/src/doveadm/dsync/doveadm-dsync.c @@ -0,0 +1,494 @@ +/* Copyright (c) 2009-2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "lib-signals.h" +#include "array.h" +#include "execv-const.h" +#include "settings-parser.h" +#include "master-service.h" +#include "mail-storage-service.h" +#include "mail-user.h" +#include "mail-namespace.h" +#include "doveadm-settings.h" +#include "doveadm-mail.h" +#include "dsync-brain.h" +#include "dsync-worker.h" +#include "dsync-proxy-server.h" +#include "doveadm-dsync.h" + +#include +#include +#include +#include + +struct dsync_cmd_context { + struct doveadm_mail_cmd_context ctx; + enum dsync_brain_flags brain_flags; + const char *mailbox; + + const char *const *remote_cmd_args; + const char *local_location; + + int fd_in, fd_out; + + unsigned int reverse_workers:1; +}; + +static const char *ssh_cmd = "ssh"; + +static void run_cmd(const char *const *args, int *fd_in_r, int *fd_out_r) +{ + int fd_in[2], fd_out[2]; + + if (pipe(fd_in) < 0 || pipe(fd_out) < 0) + i_fatal("pipe() failed: %m"); + + switch (fork()) { + case -1: + i_fatal("fork() failed: %m"); + break; + case 0: + /* child, which will execute the proxy server. stdin/stdout + goes to pipes which we'll pass to proxy client. */ + if (dup2(fd_in[0], STDIN_FILENO) < 0 || + dup2(fd_out[1], STDOUT_FILENO) < 0) + i_fatal("dup2() failed: %m"); + + (void)close(fd_in[0]); + (void)close(fd_in[1]); + (void)close(fd_out[0]); + (void)close(fd_out[1]); + + execvp_const(args[0], args); + break; + default: + /* parent */ + (void)close(fd_in[0]); + (void)close(fd_out[1]); + *fd_in_r = fd_out[0]; + *fd_out_r = fd_in[1]; + break; + } +} + +static void +mirror_get_remote_cmd_line(const char *const *argv, + const char *const **cmd_args_r) +{ + ARRAY_TYPE(const_string) cmd_args; + unsigned int i; + const char *p; + + t_array_init(&cmd_args, 16); + for (i = 0; argv[i] != NULL; i++) { + p = argv[i]; + array_append(&cmd_args, &p, 1); + } + + p = strchr(argv[0], '/'); + if (p == NULL) p = argv[0]; + if (strstr(p, "dsync") == NULL) { + /* we're executing doveadm (not dsync) */ + p = "dsync"; array_append(&cmd_args, &p, 1); + } + p = "server"; array_append(&cmd_args, &p, 1); + (void)array_append_space(&cmd_args); + *cmd_args_r = array_idx(&cmd_args, 0); +} + +static bool mirror_get_remote_cmd(const char *const *argv, const char *user, + const char *const **cmd_args_r) +{ + ARRAY_TYPE(const_string) cmd_args; + const char *p, *host; + + if (argv[1] != NULL) { + /* more than one parameter, so it contains a full command + (e.g. ssh host dsync) */ + mirror_get_remote_cmd_line(argv, cmd_args_r); + return TRUE; + } + + /* if it begins with /[a-z0-9]+:/, it's a mail location + (e.g. mdbox:~/mail) */ + for (p = argv[0]; *p != '\0'; p++) { + if (!i_isalnum(*p)) { + if (*p == ':') + return FALSE; + break; + } + } + + if (strchr(argv[0], ' ') != NULL || strchr(argv[0], '/') != NULL) { + /* a) the whole command is in one string. this is mainly for + backwards compatibility. + b) script/path */ + mirror_get_remote_cmd_line(t_strsplit(argv[0], " "), + cmd_args_r); + return TRUE; + } + + /* [user@]host */ + host = strchr(argv[0], '@'); + if (host != NULL) + user = t_strdup_until(argv[0], host++); + else + host = argv[0]; + + /* we'll assume virtual users, so in user@host it really means not to + give ssh a username, but to give dsync -u user parameter. */ + t_array_init(&cmd_args, 8); + array_append(&cmd_args, &ssh_cmd, 1); + array_append(&cmd_args, &host, 1); + p = "doveadm"; array_append(&cmd_args, &p, 1); + p = "dsync"; array_append(&cmd_args, &p, 1); + p = "server"; array_append(&cmd_args, &p, 1); + if (*user != '\0') { + p = "-u"; array_append(&cmd_args, &p, 1); + array_append(&cmd_args, &user, 1); + } + (void)array_append_space(&cmd_args); + *cmd_args_r = array_idx(&cmd_args, 0); + return TRUE; +} + +static struct dsync_worker * +cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user) +{ + struct mail_user *user2; + struct dsync_worker *worker2; + struct setting_parser_context *set_parser; + const char *set_line, *path1, *path2; + + i_assert(ctx->local_location != NULL); + + ctx->brain_flags |= DSYNC_BRAIN_FLAG_LOCAL; + i_set_failure_prefix(t_strdup_printf("dsync(%s): ", user->username)); + + /* update mail_location and create another user for the + second location. */ + set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user); + set_line = t_strconcat("mail_location=", ctx->local_location, NULL); + if (settings_parse_line(set_parser, set_line) < 0) + i_unreached(); + if (mail_storage_service_next(ctx->ctx.storage_service, + ctx->ctx.cur_service_user, &user2) < 0) + i_fatal("User init failed"); + user2->admin = TRUE; + + if (mail_namespaces_get_root_sep(user->namespaces) != + mail_namespaces_get_root_sep(user2->namespaces)) { + i_fatal("Mail locations must use the same " + "virtual mailbox hierarchy separator " + "(specify separator for the default namespace)"); + } + path1 = mailbox_list_get_path(user->namespaces->list, NULL, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + path2 = mailbox_list_get_path(user2->namespaces->list, NULL, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + if (path1 != NULL && path2 != NULL && + strcmp(path1, path2) == 0) { + i_fatal("Both source and destination mail_location " + "points to same directory: %s", path1); + } + + worker2 = dsync_worker_init_local(user2, *ctx->ctx.set->dsync_alt_char); + mail_user_unref(&user2); + return worker2; +} + +static struct dsync_worker * +cmd_dsync_run_remote(struct dsync_cmd_context *ctx, struct mail_user *user) +{ + i_set_failure_prefix(t_strdup_printf("dsync-local(%s): ", + user->username)); + return dsync_worker_init_proxy_client(ctx->fd_in, ctx->fd_out); +} + +static void +cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) +{ + struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; + struct dsync_worker *worker1, *worker2, *workertmp; + struct dsync_brain *brain; + + user->admin = TRUE; + + /* create workers */ + worker1 = dsync_worker_init_local(user, *_ctx->set->dsync_alt_char); + if (ctx->remote_cmd_args == NULL) + worker2 = cmd_dsync_run_local(ctx, user); + else + worker2 = cmd_dsync_run_remote(ctx, user); + if (ctx->reverse_workers) { + workertmp = worker1; + worker1 = worker2; + worker2 = workertmp; + } + + /* create and run the brain */ + brain = dsync_brain_init(worker1, worker2, ctx->mailbox, + ctx->brain_flags); + if (ctx->remote_cmd_args == NULL) + dsync_brain_sync_all(brain); + else { + dsync_brain_sync(brain); + if (!dsync_brain_has_failed(brain)) + io_loop_run(current_ioloop); + } + /* deinit */ + if (dsync_brain_has_unexpected_changes(brain)) { + i_warning("Mailbox changes caused a desync. " + "You may want to run dsync again."); + _ctx->exit_code = 2; + } + if (dsync_brain_deinit(&brain) < 0) + _ctx->exit_code = 1; + + dsync_worker_deinit(&worker1); + dsync_worker_deinit(&worker2); +} + +static void cmd_dsync_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; + const char *username = ""; + + if (args[0] == NULL) + doveadm_mail_help_name("dsync"); + + lib_signals_ignore(SIGHUP, TRUE); + + if (doveadm_debug || doveadm_verbose) + ctx->brain_flags |= DSYNC_BRAIN_FLAG_VERBOSE; + + /* if we're executing remotely, give -u parameter if we also + did a userdb lookup. this works only when we're handling a + single user */ + if ((_ctx->service_flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0 && + _ctx->cur_username != NULL) + username = _ctx->cur_username; + if (!mirror_get_remote_cmd(args, username, &ctx->remote_cmd_args)) { + /* it's a mail_location */ + if (args[1] != NULL) + doveadm_mail_help_name("dsync"); + ctx->local_location = args[0]; + } + + if (ctx->remote_cmd_args != NULL) { + /* do this before mail_storage_service_next() in case it + drops process privileges */ + run_cmd(ctx->remote_cmd_args, &ctx->fd_in, &ctx->fd_out); + } else { + ctx->fd_in = STDIN_FILENO; + ctx->fd_out = STDOUT_FILENO; + } +} + +static void cmd_dsync_preinit(struct doveadm_mail_cmd_context *ctx) +{ + if ((ctx->service_flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) + ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR; +} + +static bool +cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) +{ + struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; + + switch (c) { + case 'f': + ctx->brain_flags |= DSYNC_BRAIN_FLAG_FULL_SYNC; + break; + case 'm': + ctx->mailbox = optarg; + break; + case 'R': + ctx->reverse_workers = TRUE; + break; + default: + return FALSE; + } + return TRUE; +} + +static struct doveadm_mail_cmd_context *cmd_dsync_alloc(void) +{ + struct dsync_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct dsync_cmd_context); + ctx->ctx.getopt_args = "fRm:"; + ctx->ctx.v.parse_arg = cmd_mailbox_dsync_parse_arg; + ctx->ctx.v.preinit = cmd_dsync_preinit; + ctx->ctx.v.init = cmd_dsync_init; + ctx->ctx.v.run = cmd_dsync_run; + return &ctx->ctx; +} + +static struct doveadm_mail_cmd_context *cmd_dsync_backup_alloc(void) +{ + struct doveadm_mail_cmd_context *_ctx; + struct dsync_cmd_context *ctx; + + _ctx = cmd_dsync_alloc(); + ctx = (struct dsync_cmd_context *)_ctx; + ctx->brain_flags |= DSYNC_BRAIN_FLAG_BACKUP; + return _ctx; +} + +static void +cmd_dsync_server_run(struct doveadm_mail_cmd_context *ctx, + struct mail_user *user) +{ + struct dsync_proxy_server *server; + struct dsync_worker *worker; + + user->admin = TRUE; + + i_set_failure_prefix(t_strdup_printf("dsync-remote(%s): ", + user->username)); + worker = dsync_worker_init_local(user, *ctx->set->dsync_alt_char); + server = dsync_proxy_server_init(STDIN_FILENO, STDOUT_FILENO, worker); + + io_loop_run(current_ioloop); + + dsync_proxy_server_deinit(&server); + dsync_worker_deinit(&worker); +} + +static struct doveadm_mail_cmd_context *cmd_dsync_server_alloc(void) +{ + struct doveadm_mail_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context); + ctx->v.run = cmd_dsync_server_run; + return ctx; +} + +struct doveadm_mail_cmd cmd_dsync_mirror = { + cmd_dsync_alloc, "dsync mirror", "[-fR] [-m ] " +}; +struct doveadm_mail_cmd cmd_dsync_backup = { + cmd_dsync_backup_alloc, "dsync backup", + "[-fR] [-m ] " +}; +struct doveadm_mail_cmd cmd_dsync_server = { + cmd_dsync_server_alloc, "dsync server", NULL +}; + +void doveadm_dsync_main(int *_argc, char **_argv[]) +{ + int argc = *_argc; + const char *getopt_str; + char **argv = *_argv; + char **new_argv, *mailbox = NULL, *alt_char = NULL; + char *p, *dup, new_flags[5]; + int max_argc, src, dest, i, j; + bool flag_f = FALSE, flag_R = FALSE, flag_m, flag_C, has_arg; + + p = strrchr(argv[0], '/'); + if (p == NULL) p = argv[0]; + if (strstr(p, "dsync") == NULL) + return; + + /* @UNSAFE: this is called when the "doveadm" binary is called as + "dsync" (for backwards compatibility) */ + max_argc = argc + 5; + new_argv = calloc(sizeof(char *), max_argc); + new_argv[0] = argv[0]; + dest = 1; + getopt_str = master_service_getopt_string(); + + /* add global doveadm flags */ + for (src = 1; src < argc; src++) { + if (argv[src][0] != '-') + break; + + flag_m = FALSE; flag_C = FALSE; has_arg = FALSE; + dup = strdup(argv[src]); + for (i = j = 1; argv[src][i] != '\0'; i++) { + switch (argv[src][i]) { + case 'C': + flag_C = TRUE; + break; + case 'f': + flag_f = TRUE; + break; + case 'R': + flag_R = TRUE; + break; + case 'm': + flag_m = TRUE; + break; + default: + p = strchr(getopt_str, argv[src][i]); + if (p != NULL && p[1] == ':') + has_arg = TRUE; + dup[j++] = argv[src][i]; + break; + } + } + if (j > 1) { + dup[j++] = '\0'; + new_argv[dest++] = dup; + if (has_arg && src+1 < argc) + new_argv[dest++] = argv[++src]; + } + if (flag_m) { + if (src+1 == argc) + i_fatal("-m missing parameter"); + mailbox = argv[++src]; + } + if (flag_C) { + if (src+1 == argc) + i_fatal("-C missing parameter"); + alt_char = argv[++src]; + } + } + if (alt_char != NULL) { + new_argv[dest++] = "-o"; + new_argv[dest++] = + p_strconcat(pool_datastack_create(), + "dsync_alt_char=", alt_char, NULL); + } + + new_argv[dest++] = "dsync"; + if (src < argc) { + /* mirror|backup|server */ + if (strcmp(argv[src], "dsync") == 0) { + /* looks like we executed doveconf, which + re-executed ourself with new parameters. + no need to change them anymore. */ + return; + } + new_argv[dest++] = argv[src++]; + } + + /* dsync flags */ + new_flags[0] = '-'; i = 1; + if (flag_f) + new_flags[i++] = 'f'; + if (flag_R) + new_flags[i++] = 'R'; + if (mailbox != NULL) + new_flags[i++] = 'm'; + i_assert((unsigned int)i < sizeof(new_flags)); + new_flags[i] = '\0'; + + if (i > 1) { + new_argv[dest++] = strdup(new_flags); + if (mailbox != NULL) + new_argv[dest++] = mailbox; + } + + /* rest of the parameters */ + for (; src < argc; src++) + new_argv[dest++] = argv[src]; + i_assert(dest < max_argc); + new_argv[dest] = NULL; + + *_argc = dest; + *_argv = new_argv; + optind = 1; +} diff --git a/src/doveadm/dsync/doveadm-dsync.h b/src/doveadm/dsync/doveadm-dsync.h new file mode 100644 index 0000000000..9ebb3f266b --- /dev/null +++ b/src/doveadm/dsync/doveadm-dsync.h @@ -0,0 +1,10 @@ +#ifndef DOVEADM_DSYNC_H +#define DOVEADM_DSYNC_H + +extern struct doveadm_mail_cmd cmd_dsync_mirror; +extern struct doveadm_mail_cmd cmd_dsync_backup; +extern struct doveadm_mail_cmd cmd_dsync_server; + +void doveadm_dsync_main(int *_argc, char **_argv[]); + +#endif diff --git a/src/dsync/dsync-brain-msgs-new.c b/src/doveadm/dsync/dsync-brain-msgs-new.c similarity index 100% rename from src/dsync/dsync-brain-msgs-new.c rename to src/doveadm/dsync/dsync-brain-msgs-new.c diff --git a/src/dsync/dsync-brain-msgs.c b/src/doveadm/dsync/dsync-brain-msgs.c similarity index 100% rename from src/dsync/dsync-brain-msgs.c rename to src/doveadm/dsync/dsync-brain-msgs.c diff --git a/src/dsync/dsync-brain-private.h b/src/doveadm/dsync/dsync-brain-private.h similarity index 100% rename from src/dsync/dsync-brain-private.h rename to src/doveadm/dsync/dsync-brain-private.h diff --git a/src/dsync/dsync-brain.c b/src/doveadm/dsync/dsync-brain.c similarity index 99% rename from src/dsync/dsync-brain.c rename to src/doveadm/dsync/dsync-brain.c index 7ad27939f1..b6508d54f4 100644 --- a/src/dsync/dsync-brain.c +++ b/src/doveadm/dsync/dsync-brain.c @@ -3,7 +3,6 @@ #include "lib.h" #include "array.h" #include "hash.h" -#include "master-service.h" #include "dsync-worker.h" #include "dsync-brain-private.h" @@ -45,7 +44,7 @@ dsync_brain_init(struct dsync_worker *src_worker, void dsync_brain_fail(struct dsync_brain *brain) { brain->failed = TRUE; - master_service_stop(master_service); + io_loop_stop(current_ioloop); } int dsync_brain_deinit(struct dsync_brain **_brain) @@ -880,7 +879,7 @@ void dsync_brain_sync(struct dsync_brain *brain) case DSYNC_STATE_SYNC_FLUSH2: break; case DSYNC_STATE_SYNC_END: - master_service_stop(master_service); + io_loop_stop(current_ioloop); break; default: i_unreached(); diff --git a/src/dsync/dsync-brain.h b/src/doveadm/dsync/dsync-brain.h similarity index 100% rename from src/dsync/dsync-brain.h rename to src/doveadm/dsync/dsync-brain.h diff --git a/src/dsync/dsync-data.c b/src/doveadm/dsync/dsync-data.c similarity index 100% rename from src/dsync/dsync-data.c rename to src/doveadm/dsync/dsync-data.c diff --git a/src/dsync/dsync-data.h b/src/doveadm/dsync/dsync-data.h similarity index 100% rename from src/dsync/dsync-data.h rename to src/doveadm/dsync/dsync-data.h diff --git a/src/dsync/dsync-proxy-client.c b/src/doveadm/dsync/dsync-proxy-client.c similarity index 99% rename from src/dsync/dsync-proxy-client.c rename to src/doveadm/dsync/dsync-proxy-client.c index ae32b0a2bb..9f5c101055 100644 --- a/src/dsync/dsync-proxy-client.c +++ b/src/doveadm/dsync/dsync-proxy-client.c @@ -9,7 +9,6 @@ #include "ostream.h" #include "str.h" #include "strescape.h" -#include "master-service.h" #include "imap-util.h" #include "dsync-proxy.h" #include "dsync-worker-private.h" @@ -82,7 +81,7 @@ static void proxy_client_fail(struct proxy_client_dsync_worker *worker) { i_stream_close(worker->input); dsync_worker_set_failure(&worker->worker); - master_service_stop(master_service); + io_loop_stop(current_ioloop); } static int diff --git a/src/dsync/dsync-proxy-server-cmd.c b/src/doveadm/dsync/dsync-proxy-server-cmd.c similarity index 99% rename from src/dsync/dsync-proxy-server-cmd.c rename to src/doveadm/dsync/dsync-proxy-server-cmd.c index d090778796..ed09e7dc52 100644 --- a/src/dsync/dsync-proxy-server-cmd.c +++ b/src/doveadm/dsync/dsync-proxy-server-cmd.c @@ -9,7 +9,6 @@ #include "istream-dot.h" #include "ostream.h" #include "imap-util.h" -#include "master-service.h" #include "dsync-worker.h" #include "dsync-proxy.h" #include "dsync-proxy-server.h" diff --git a/src/dsync/dsync-proxy-server.c b/src/doveadm/dsync/dsync-proxy-server.c similarity index 94% rename from src/dsync/dsync-proxy-server.c rename to src/doveadm/dsync/dsync-proxy-server.c index 8ba8c1de61..df8cef859f 100644 --- a/src/dsync/dsync-proxy-server.c +++ b/src/doveadm/dsync/dsync-proxy-server.c @@ -5,7 +5,6 @@ #include "fd-set-nonblock.h" #include "istream.h" #include "ostream.h" -#include "master-service.h" #include "dsync-worker.h" #include "dsync-proxy.h" #include "dsync-proxy-server.h" @@ -21,13 +20,13 @@ proxy_server_read_line(struct dsync_proxy_server *server, if (server->input->stream_errno != 0) { errno = server->input->stream_errno; i_error("read() from proxy client failed: %m"); - master_service_stop(master_service); + io_loop_stop(current_ioloop); return -1; } if (server->input->eof) { if (!server->finished) i_error("read() from proxy client failed: EOF"); - master_service_stop(master_service); + io_loop_stop(current_ioloop); return -1; } } @@ -37,7 +36,7 @@ proxy_server_read_line(struct dsync_proxy_server *server, if (!server->handshake_received) { if (strcmp(*line_r, DSYNC_PROXY_CLIENT_GREETING_LINE) != 0) { i_error("Invalid client handshake: %s", *line_r); - master_service_stop(master_service); + io_loop_stop(current_ioloop); return -1; } server->handshake_received = TRUE; @@ -121,7 +120,7 @@ static void proxy_server_input(struct dsync_proxy_server *server) ret = -1; if (ret < 0) - master_service_stop(master_service); + io_loop_stop(current_ioloop); timeout_reset(server->to); } @@ -147,7 +146,7 @@ static int proxy_server_output(struct dsync_proxy_server *server) } } if (output->closed) - master_service_stop(master_service); + io_loop_stop(current_ioloop); timeout_reset(server->to); return ret; } @@ -155,7 +154,7 @@ static int proxy_server_output(struct dsync_proxy_server *server) static void dsync_proxy_server_timeout(void *context ATTR_UNUSED) { i_error("proxy server timed out"); - master_service_stop(master_service); + io_loop_stop(current_ioloop); } struct dsync_proxy_server * diff --git a/src/dsync/dsync-proxy-server.h b/src/doveadm/dsync/dsync-proxy-server.h similarity index 100% rename from src/dsync/dsync-proxy-server.h rename to src/doveadm/dsync/dsync-proxy-server.h diff --git a/src/dsync/dsync-proxy.c b/src/doveadm/dsync/dsync-proxy.c similarity index 100% rename from src/dsync/dsync-proxy.c rename to src/doveadm/dsync/dsync-proxy.c diff --git a/src/dsync/dsync-proxy.h b/src/doveadm/dsync/dsync-proxy.h similarity index 100% rename from src/dsync/dsync-proxy.h rename to src/doveadm/dsync/dsync-proxy.h diff --git a/src/dsync/dsync-worker-local.c b/src/doveadm/dsync/dsync-worker-local.c similarity index 99% rename from src/dsync/dsync-worker-local.c rename to src/doveadm/dsync/dsync-worker-local.c index 7c642f2dd6..b26689547d 100644 --- a/src/dsync/dsync-worker-local.c +++ b/src/doveadm/dsync/dsync-worker-local.c @@ -222,6 +222,8 @@ dsync_worker_init_local(struct mail_user *user, char alt_char) i_array_init(&worker->msg_get_queue, 32); p_array_init(&worker->subs_namespaces, pool, 8); dsync_drop_extra_namespaces(worker); + + mail_user_ref(worker->user); return &worker->worker; } @@ -238,6 +240,8 @@ static void local_worker_deinit(struct dsync_worker *_worker) local_worker_msg_box_close(worker); local_worker_mailbox_close(worker); + mail_user_unref(&worker->user); + hash_table_destroy(&worker->mailbox_hash); if (worker->mailbox_changes_hash != NULL) hash_table_destroy(&worker->mailbox_changes_hash); diff --git a/src/dsync/dsync-worker-private.h b/src/doveadm/dsync/dsync-worker-private.h similarity index 100% rename from src/dsync/dsync-worker-private.h rename to src/doveadm/dsync/dsync-worker-private.h diff --git a/src/dsync/dsync-worker.c b/src/doveadm/dsync/dsync-worker.c similarity index 100% rename from src/dsync/dsync-worker.c rename to src/doveadm/dsync/dsync-worker.c diff --git a/src/dsync/dsync-worker.h b/src/doveadm/dsync/dsync-worker.h similarity index 100% rename from src/dsync/dsync-worker.h rename to src/doveadm/dsync/dsync-worker.h diff --git a/src/dsync/test-dsync-brain-msgs.c b/src/doveadm/dsync/test-dsync-brain-msgs.c similarity index 100% rename from src/dsync/test-dsync-brain-msgs.c rename to src/doveadm/dsync/test-dsync-brain-msgs.c diff --git a/src/dsync/test-dsync-brain.c b/src/doveadm/dsync/test-dsync-brain.c similarity index 99% rename from src/dsync/test-dsync-brain.c rename to src/doveadm/dsync/test-dsync-brain.c index 06fbe579eb..e2db98a3c0 100644 --- a/src/dsync/test-dsync-brain.c +++ b/src/doveadm/dsync/test-dsync-brain.c @@ -2,7 +2,6 @@ #include "lib.h" #include "array.h" -#include "master-service.h" #include "dsync-brain-private.h" #include "test-dsync-worker.h" #include "test-dsync-common.h" @@ -10,10 +9,6 @@ struct master_service *master_service; static struct test_dsync_worker *src_test_worker, *dest_test_worker; -void master_service_stop(struct master_service *master_service ATTR_UNUSED) -{ -} - struct dsync_brain_mailbox_sync * dsync_brain_msg_sync_init(struct dsync_brain *brain, const ARRAY_TYPE(dsync_brain_mailbox) *mailboxes) diff --git a/src/dsync/test-dsync-common.c b/src/doveadm/dsync/test-dsync-common.c similarity index 100% rename from src/dsync/test-dsync-common.c rename to src/doveadm/dsync/test-dsync-common.c diff --git a/src/dsync/test-dsync-common.h b/src/doveadm/dsync/test-dsync-common.h similarity index 100% rename from src/dsync/test-dsync-common.h rename to src/doveadm/dsync/test-dsync-common.h diff --git a/src/dsync/test-dsync-proxy-server-cmd.c b/src/doveadm/dsync/test-dsync-proxy-server-cmd.c similarity index 99% rename from src/dsync/test-dsync-proxy-server-cmd.c rename to src/doveadm/dsync/test-dsync-proxy-server-cmd.c index 9812e66e0c..c010e57822 100644 --- a/src/dsync/test-dsync-proxy-server-cmd.c +++ b/src/doveadm/dsync/test-dsync-proxy-server-cmd.c @@ -6,7 +6,6 @@ #include "strescape.h" #include "istream.h" #include "ostream.h" -#include "master-service.h" #include "test-common.h" #include "dsync-proxy-server.h" #include "test-dsync-worker.h" @@ -21,8 +20,6 @@ static struct test_dsync_worker *test_worker; static struct dsync_proxy_server_command *cur_cmd; static const char *cur_cmd_args[20]; -void master_service_stop(struct master_service *service ATTR_UNUSED) {} - static void out_clear(void) { o_stream_seek(server->output, 0); diff --git a/src/dsync/test-dsync-proxy.c b/src/doveadm/dsync/test-dsync-proxy.c similarity index 100% rename from src/dsync/test-dsync-proxy.c rename to src/doveadm/dsync/test-dsync-proxy.c diff --git a/src/dsync/test-dsync-worker.c b/src/doveadm/dsync/test-dsync-worker.c similarity index 100% rename from src/dsync/test-dsync-worker.c rename to src/doveadm/dsync/test-dsync-worker.c diff --git a/src/dsync/test-dsync-worker.h b/src/doveadm/dsync/test-dsync-worker.h similarity index 100% rename from src/dsync/test-dsync-worker.h rename to src/doveadm/dsync/test-dsync-worker.h diff --git a/src/dsync/dsync.c b/src/dsync/dsync.c deleted file mode 100644 index fafa5bf56c..0000000000 --- a/src/dsync/dsync.c +++ /dev/null @@ -1,364 +0,0 @@ -/* Copyright (c) 2009-2011 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "lib-signals.h" -#include "array.h" -#include "execv-const.h" -#include "settings-parser.h" -#include "master-service.h" -#include "master-service-settings.h" -#include "mail-storage-service.h" -#include "mail-user.h" -#include "mail-namespace.h" -#include "dsync-brain.h" -#include "dsync-worker.h" -#include "dsync-proxy-server.h" - -#include -#include -#include -#include - -static const char *ssh_cmd = "ssh"; -static struct dsync_brain *brain; -static struct dsync_proxy_server *server; - -static void run_cmd(const char *const *args, int *fd_in_r, int *fd_out_r) -{ - int fd_in[2], fd_out[2]; - - if (pipe(fd_in) < 0 || pipe(fd_out) < 0) - i_fatal("pipe() failed: %m"); - - switch (fork()) { - case -1: - i_fatal("fork() failed: %m"); - break; - case 0: - /* child, which will execute the proxy server. stdin/stdout - goes to pipes which we'll pass to proxy client. */ - if (dup2(fd_in[0], STDIN_FILENO) < 0 || - dup2(fd_out[1], STDOUT_FILENO) < 0) - i_fatal("dup2() failed: %m"); - - (void)close(fd_in[0]); - (void)close(fd_in[1]); - (void)close(fd_out[0]); - (void)close(fd_out[1]); - - execvp_const(args[0], args); - break; - default: - /* parent */ - (void)close(fd_in[0]); - (void)close(fd_out[1]); - *fd_in_r = fd_out[0]; - *fd_out_r = fd_in[1]; - break; - } -} - -static void -mirror_get_remote_cmd_line(char **argv, const char *const **cmd_args_r) -{ - ARRAY_TYPE(const_string) cmd_args; - unsigned int i; - const char *p; - - t_array_init(&cmd_args, 16); - for (i = 0; argv[i] != NULL; i++) { - p = argv[i]; - array_append(&cmd_args, &p, 1); - } - - p = "server"; array_append(&cmd_args, &p, 1); - (void)array_append_space(&cmd_args); - *cmd_args_r = array_idx(&cmd_args, 0); -} - -static bool mirror_get_remote_cmd(char **argv, const char *const **cmd_args_r) -{ - ARRAY_TYPE(const_string) cmd_args; - const char *p, *user, *host; - - if (argv[1] != NULL) { - /* more than one parameter, so it contains a full command - (e.g. ssh host dsync) */ - mirror_get_remote_cmd_line(argv, cmd_args_r); - return TRUE; - } - - /* if it begins with /[a-z0-9]+:/, it's a mail location - (e.g. mdbox:~/mail) */ - for (p = argv[0]; *p != '\0'; p++) { - if (!i_isalnum(*p)) { - if (*p == ':') - return FALSE; - break; - } - } - - if (strchr(argv[0], ' ') != NULL || strchr(argv[0], '/') != NULL) { - /* a) the whole command is in one string. this is mainly for - backwards compatibility. - b) script/path */ - argv = p_strsplit(pool_datastack_create(), argv[0], " "); - mirror_get_remote_cmd_line(argv, cmd_args_r); - return TRUE; - } - - /* [user@]host */ - host = strchr(argv[0], '@'); - if (host != NULL) - user = t_strdup_until(argv[0], host++); - else { - user = ""; - host = argv[0]; - } - - /* we'll assume virtual users, so in user@host it really means not to - give ssh a username, but to give dsync -u user parameter. */ - t_array_init(&cmd_args, 8); - array_append(&cmd_args, &ssh_cmd, 1); - array_append(&cmd_args, &host, 1); - p = "dsync"; array_append(&cmd_args, &p, 1); - if (*user != '\0') { - p = "-u"; array_append(&cmd_args, &p, 1); - array_append(&cmd_args, &user, 1); - } - p = "server"; array_append(&cmd_args, &p, 1); - (void)array_append_space(&cmd_args); - *cmd_args_r = array_idx(&cmd_args, 0); - return TRUE; -} - -static void ATTR_NORETURN -usage(void) -{ - fprintf(stderr, -"usage: dsync [-C ] [-m ] [-u ] [-frRv]\n" -" mirror | [@] | \n" -); - exit(1); -} - -static void -dsync_connected(struct master_service_connection *conn ATTR_UNUSED) -{ - i_fatal("Running as service not supported currently"); -} - -int main(int argc, char *argv[]) -{ - enum mail_storage_service_flags ssflags = - MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR | - MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT; - enum dsync_brain_flags brain_flags = 0; - struct mail_storage_service_ctx *storage_service; - struct mail_storage_service_user *service_user; - struct mail_storage_service_input input; - struct mail_user *mail_user, *mail_user2 = NULL; - struct dsync_worker *worker1, *worker2, *workertmp; - const char *error, *username, *cmd_name, *mailbox = NULL; - const char *local_location = NULL, *const *remote_cmd_args = NULL; - const char *path1, *path2; - bool dsync_server = FALSE, unexpected_changes = FALSE; - bool dsync_debug = FALSE, reverse_workers = FALSE; - char alt_char = '_'; - int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO; - - master_service = master_service_init("dsync", - MASTER_SERVICE_FLAG_STANDALONE, - &argc, &argv, "+C:Dfm:Ru:v"); - - username = getenv("USER"); - while ((c = master_getopt(master_service)) > 0) { - if (c == '-') - break; - switch (c) { - case 'C': - alt_char = optarg[0]; - break; - case 'D': - dsync_debug = TRUE; - brain_flags |= DSYNC_BRAIN_FLAG_VERBOSE; - ssflags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; - break; - case 'm': - mailbox = optarg; - break; - case 'R': - reverse_workers = TRUE; - break; - case 'f': - brain_flags |= DSYNC_BRAIN_FLAG_FULL_SYNC; - break; - case 'u': - username = optarg; - ssflags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; - ssflags &= ~MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR; - break; - case 'v': - brain_flags |= DSYNC_BRAIN_FLAG_VERBOSE; - break; - default: - usage(); - } - } - if (optind == argc) - usage(); - if (username == NULL) - i_fatal("USER environment not set and -u parameter not given"); - cmd_name = argv[optind++]; - - if (strcmp(cmd_name, "mirror") == 0 || - strcmp(cmd_name, "convert") == 0 || - strcmp(cmd_name, "backup") == 0) { - if (optind == argc) - usage(); - - if (strcmp(cmd_name, "backup") == 0) - brain_flags |= DSYNC_BRAIN_FLAG_BACKUP; - if (!mirror_get_remote_cmd(argv+optind, &remote_cmd_args)) { - if (optind+1 != argc) - usage(); - local_location = argv[optind]; - } - optind++; - } else if (strcmp(cmd_name, "server") == 0) { - dsync_server = TRUE; - } else { - usage(); - } - master_service_init_finish(master_service); - lib_signals_ignore(SIGHUP, TRUE); - - if (!dsync_debug) { - /* disable debugging unless -D is given */ - i_set_debug_file("/dev/null"); - } - - memset(&input, 0, sizeof(input)); - input.module = "mail"; - input.service = "dsync"; - input.username = username; - - storage_service = mail_storage_service_init(master_service, NULL, - ssflags); - if (mail_storage_service_lookup(storage_service, &input, - &service_user, &error) <= 0) - i_fatal("User lookup failed: %s", error); - - if (remote_cmd_args != NULL) { - /* _service_lookup() may exec doveconf, so do our forking - after that. but do it before _service_next() in case it - drops process privileges */ - run_cmd(remote_cmd_args, &fd_in, &fd_out); - } - - if (mail_storage_service_next(storage_service, service_user, - &mail_user) < 0) - i_fatal("User init failed"); - mail_user->admin = TRUE; - - /* create the first local worker */ - worker1 = dsync_worker_init_local(mail_user, alt_char); - if (local_location != NULL) { - /* update mail_location and create another user for the - second location. */ - struct setting_parser_context *set_parser; - const char *set_line = - t_strconcat("mail_location=", local_location, NULL); - - set_parser = mail_storage_service_user_get_settings_parser(service_user); - if (settings_parse_line(set_parser, set_line) < 0) - i_unreached(); - if (mail_storage_service_next(storage_service, service_user, - &mail_user2) < 0) - i_fatal("User init failed"); - mail_user2->admin = TRUE; - - if (mail_namespaces_get_root_sep(mail_user->namespaces) != - mail_namespaces_get_root_sep(mail_user2->namespaces)) { - i_fatal("Mail locations must use the same " - "virtual mailbox hierarchy separator " - "(specify separator for the default namespace)"); - } - path1 = mailbox_list_get_path(mail_user->namespaces->list, NULL, - MAILBOX_LIST_PATH_TYPE_MAILBOX); - path2 = mailbox_list_get_path(mail_user2->namespaces->list, NULL, - MAILBOX_LIST_PATH_TYPE_MAILBOX); - if (path1 != NULL && path2 != NULL && - strcmp(path1, path2) == 0) { - i_fatal("Both source and destination mail_location " - "points to same directory: %s", path1); - } - - worker2 = dsync_worker_init_local(mail_user2, alt_char); - if (reverse_workers) { - workertmp = worker1; - worker1 = worker2; - worker2 = workertmp; - } - - i_set_failure_prefix(t_strdup_printf("dsync(%s): ", username)); - brain = dsync_brain_init(worker1, worker2, mailbox, - brain_flags | DSYNC_BRAIN_FLAG_LOCAL); - server = NULL; - dsync_brain_sync_all(brain); - } else if (dsync_server) { - i_set_failure_prefix(t_strdup_printf("dsync-remote(%s): ", - username)); - server = dsync_proxy_server_init(fd_in, fd_out, worker1); - worker2 = NULL; - - master_service_run(master_service, dsync_connected); - } else { - i_assert(remote_cmd_args != NULL); - i_set_failure_prefix(t_strdup_printf("dsync-local(%s): ", - username)); - - worker2 = dsync_worker_init_proxy_client(fd_in, fd_out); - if (reverse_workers) { - workertmp = worker1; - worker1 = worker2; - worker2 = workertmp; - } - - brain = dsync_brain_init(worker1, worker2, - mailbox, brain_flags); - server = NULL; - dsync_brain_sync(brain); - - if (!dsync_brain_has_failed(brain)) - master_service_run(master_service, dsync_connected); - } - - if (brain == NULL) - ret = 0; - else { - if (dsync_brain_has_unexpected_changes(brain)) - unexpected_changes = TRUE; - ret = dsync_brain_deinit(&brain); - } - if (server != NULL) - dsync_proxy_server_deinit(&server); - - dsync_worker_deinit(&worker1); - if (worker2 != NULL) - dsync_worker_deinit(&worker2); - - mail_user_unref(&mail_user); - if (mail_user2 != NULL) - mail_user_unref(&mail_user2); - mail_storage_service_user_free(&service_user); - - if (unexpected_changes) { - i_warning("Mailbox changes caused a desync. " - "You may want to run dsync again."); - } - - mail_storage_service_deinit(&storage_service); - master_service_deinit(&master_service); - return ret < 0 ? 1 : (unexpected_changes ? 2 : 0); -}