doveadm-dsync.c revision cd611ca82b8b8a61736d21a8a0de58cfd53bc9b6
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void remote_error_input(struct dsync_cmd_context *ctx)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomirun_cmd(struct dsync_cmd_context *ctx, const char *const *args)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (pipe(fd_in) < 0 || pipe(fd_out) < 0 || pipe(fd_err) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi switch (fork()) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* child, which will execute the proxy server. stdin/stdout
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi goes to pipes which we'll pass to proxy client. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* parent */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ctx->io_err = io_add(ctx->fd_err, IO_READ, remote_error_input, ctx);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimirror_get_remote_cmd_line(const char *const *argv,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *const **cmd_args_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi unsigned int i;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *p;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we're executing dsync */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi p = "server";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we're executing doveadm */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi p = "dsync-server";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *const *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *host, const char *login, const char *mail_user)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi args = t_strsplit(doveadm_settings->dsync_remote_cmd, " ");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* some automation: if parameter's all %variables
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi expand to empty, but the %variable isn't the only
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi text in the parameter, skip it. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic bool mirror_get_remote_cmd(struct dsync_cmd_context *ctx,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *const **cmd_args_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *p, *host, *const *argv = ctx->ctx.args;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* more than one parameter, so it contains a full command
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (e.g. ssh host dsync) */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* if it begins with /[a-z0-9]+:/, it's a mail location
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (e.g. mdbox:~/mail) */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (*p == ':')
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strchr(argv[0], ' ') != NULL || strchr(argv[0], '/') != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* a) the whole command is in one string. this is mainly for
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi backwards compatibility.
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mirror_get_remote_cmd_line(t_strsplit(argv[0], " "),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* [user@]host */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we'll assume virtual users, so in user@host it really means not to
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi give ssh a username, but to give dsync -u user parameter. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *cmd_args_r = get_ssh_cmd_args(ctx, host, "", user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct dsync_worker *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomicmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_set_failure_prefix(t_strdup_printf("dsync(%s): ", user->username));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* update mail_location and create another user for the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi second location. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi set_line = t_strconcat("mail_location=", ctx->local_location, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (settings_parse_line(set_parser, set_line) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_storage_service_next(ctx->ctx.storage_service,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_namespaces_get_root_sep(user->namespaces) !=
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_namespaces_get_root_sep(user2->namespaces)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "virtual mailbox hierarchy separator "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "(specify separator for the default namespace)");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi path1 = mailbox_list_get_path(user->namespaces->list, NULL,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi path2 = mailbox_list_get_path(user2->namespaces->list, NULL,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_fatal("Both source and destination mail_location "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi worker2 = dsync_worker_init_local(user2, ctx->namespace_prefix,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct dsync_worker *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomicmd_dsync_run_remote(struct dsync_cmd_context *ctx, struct mail_user *user)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_set_failure_prefix(t_strdup_printf("dsync-local(%s): ",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return dsync_worker_init_proxy_client(ctx->fd_in, ctx->fd_out);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *const *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return get_ssh_cmd_args(ctx, host, login, username);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int dsync_lock(struct mail_user *user, unsigned int lock_timeout,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_user_get_home(user, &home)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi path = t_strconcat(home, "/"DSYNC_LOCK_FILENAME, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file_wait_lock(fd, path, F_WRLCK, FILE_LOCK_METHOD_FCNTL,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomicmd_dsync_start(struct dsync_cmd_context *ctx, struct dsync_worker *worker1,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* create and run the brain */
be5773cb4d6edae8a5d9f300c3c7375cdd33826eJosef 'Jeff' Sipek brain = dsync_brain_init(worker1, worker2, ctx->mailbox,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* deinit */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "You may want to run dsync again.");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomicmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
const char *lock_path;
return ret;
const char **error_r)
const char *const args[])
return FALSE;
return TRUE;
return _ctx;
const char *lock_path;
return ret;
return FALSE;
return TRUE;
const char *getopt_str;
if (flag_m) {
if (flag_u) {
if (flag_C) {
if (flag_f)
if (flag_R)