doveadm-dsync.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "array.h"
#include "execv-const.h"
#include "fd-set-nonblock.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-rawlog.h"
#include "write-full.h"
#include "str.h"
#include "var-expand.h"
#include "settings-parser.h"
#include "master-service.h"
#include "mail-storage-service.h"
#include "mail-user.h"
#include "mail-namespace.h"
#include "mailbox-list.h"
#include "doveadm-settings.h"
#include "doveadm-mail.h"
#include "doveadm-print.h"
#include "dsync-brain.h"
#include "dsync-ibc.h"
#include "doveadm-dsync.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
#define DSYNC_COMMON_GETOPT_ARGS "+adEfl:m:n:r:Rs:"
#define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
struct dsync_cmd_context {
struct doveadm_mail_cmd_context ctx;
const char *mailbox, *namespace_prefix;
const char *state_input, *rawlog_path;
const char *remote_name;
const char *local_location;
struct istream *err_stream;
unsigned int lock_timeout;
unsigned int lock:1;
unsigned int sync_all_namespaces:1;
unsigned int default_replica_location:1;
unsigned int backup:1;
unsigned int reverse_backup:1;
unsigned int remote:1;
unsigned int remote_user_prefix:1;
};
static bool legacy_dsync = FALSE;
{
const unsigned char *data;
const char *line;
case -2:
break;
case -1:
break;
default:
break;
}
}
static void
{
i_fatal("pipe() failed: %m");
switch (ctx->remote_pid) {
case -1:
i_fatal("fork() failed: %m");
case 0:
goes to pipes which we'll pass to proxy client. */
i_fatal("dup2() failed: %m");
i_close_fd(&fd_in[0]);
i_close_fd(&fd_out[0]);
i_close_fd(&fd_err[0]);
default:
/* parent */
break;
}
i_close_fd(&fd_in[0]);
if (ctx->remote_user_prefix) {
const char *prefix =
i_fatal("write(remote out) failed: %m");
}
}
static void
mirror_get_remote_cmd_line(const char *const *argv,
const char *const **cmd_args_r)
{
unsigned int i;
const char *p;
p = argv[i];
}
if (legacy_dsync) {
/* we're executing dsync */
p = "server";
} else {
/* we're executing doveadm */
p = "dsync-server";
}
}
static const char *const *
{
static struct var_expand_table static_tab[] = {
};
struct var_expand_table *tab;
else {
/* some automation: if parameter's all %variables
expand to empty, but the %variable isn't the only
text in the parameter, skip it. */
str_truncate(str, 0);
str_truncate(str2, 0);
continue;
}
}
}
const char *user,
const char *const **cmd_args_r)
{
/* more than one parameter, so it contains a full command
(e.g. ssh host dsync) */
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;
}
}
/* a) the whole command is in one string. this is mainly for
backwards compatibility.
return TRUE;
}
/* [user@]host */
else
/* 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. */
return TRUE;
}
static int
{
struct dsync_brain *brain2;
struct setting_parser_context *set_parser;
int ret;
/* update mail_location and create another user for the
second location. */
i_unreached();
if (ret < 0) {
return -1;
}
i_error("Mail locations must use the same "
"virtual mailbox hierarchy separator "
"(specify separator for the default namespace)");
return -1;
}
&path1) &&
&path2) &&
i_error("Both source and destination mail_location "
"points to same directory: %s", path1);
return -1;
}
while (brain1_running || brain2_running) {
if (dsync_brain_has_failed(brain) ||
break;
}
if (dsync_brain_deinit(&brain2) < 0) {
return -1;
}
return 0;
}
static void
{
int status;
/* wait for the remote command to finish to see any final errors.
don't wait very long though. */
i_error("wait() failed: %m");
else {
i_error("Remote command process isn't dying, killing it");
i_error("kill() failed: %m");
}
} else if (WIFSIGNALED(status))
}
static const char *const *
{
else {
login = "";
}
}
static struct dsync_ibc *
const char *name, const char *temp_prefix)
{
}
static int
{
struct dsync_brain *brain;
enum dsync_brain_flags brain_flags;
int ret = 0;
}
else {
str_c(temp_prefix));
}
if (ctx->sync_all_namespaces)
if (ctx->reverse_backup)
if (doveadm_debug)
ctx->state_input);
ret = -1;
} else {
}
}
if (dsync_brain_deinit(&brain) < 0)
}
}
return ret;
}
{
i_error("Couldn't look up user's home dir");
return -1;
}
if (ret == 0) {
i_error("User has no home directory");
return -1;
}
if (fd == -1) {
return -1;
}
lock_timeout, lock_r) <= 0) {
return -1;
}
return fd;
}
static int
{
const char *lock_path;
if (lock_fd == -1) {
return -1;
} else {
return ret;
}
}
struct mail_storage_service_user *service_user,
const char **error_r)
{
const char *const *remote_cmd_args = NULL;
const struct mail_user_settings *user_set;
const char *username = "";
if (ctx->default_replica_location) {
*error_r = "User has no mail_replica in userdb";
return -1;
}
} else {
/* if we're executing remotely, give -u parameter if we also
did a userdb lookup. */
/* it's a mail_location */
}
}
/* this is a remote (ssh) command */
/* this is a remote (ssh) command with a "user\n"
prefix sent before dsync actually starts */
} else {
}
_ctx->cur_username);
}
if (remote_cmd_args != NULL) {
/* do this before mail_storage_service_next() in case it
drops process privileges */
}
i_fatal("-a parameter requires syncing with remote host");
return 0;
}
const char *const args[])
{
if (ctx->default_replica_location) {
i_error("Don't give mail location with -d parameter");
} else {
}
}
{
}
static bool
{
switch (c) {
case 'a':
break;
case 'd':
break;
case 'E':
/* dsync wrapper detection flag */
legacy_dsync = TRUE;
break;
case 'f':
break;
case 'l':
break;
case 'm':
break;
case 'n':
break;
case 'r':
break;
case 'R':
return FALSE;
break;
case 's':
*optarg != '\0')
break;
default:
return FALSE;
}
return TRUE;
}
static struct doveadm_mail_cmd_context *cmd_dsync_alloc(void)
{
struct dsync_cmd_context *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();
return _ctx;
}
static int
{
struct dsync_brain *brain;
if (dsync_brain_deinit(&brain) < 0)
}
static bool
{
switch (c) {
case 'E':
/* dsync wrapper detection flag */
legacy_dsync = TRUE;
break;
case 'r':
break;
default:
return FALSE;
}
return TRUE;
}
static struct doveadm_mail_cmd_context *cmd_dsync_server_alloc(void)
{
struct dsync_cmd_context *ctx;
}
struct doveadm_mail_cmd cmd_dsync_mirror = {
cmd_dsync_alloc, "sync",
"[-dfR] [-l <secs>] [-m <mailbox>] [-n <namespace>] [-s <state>] <dest>"
};
struct doveadm_mail_cmd cmd_dsync_backup = {
cmd_dsync_backup_alloc, "backup",
"[-dfR] [-l <secs>] [-m <mailbox>] [-n <namespace>] [-s <state>] <dest>"
};
struct doveadm_mail_cmd cmd_dsync_server = {
};
{
const char *getopt_str;
bool dsync_server = FALSE;
return;
/* @UNSAFE: this is called when the "doveadm" binary is called as
"dsync" (for backwards compatibility) */
dest = 1;
/* add global doveadm flags */
break;
case 'C':
break;
case 'f':
break;
case 'R':
break;
case 'm':
break;
case 'u':
break;
default:
break;
}
}
if (j > 1) {
dup[j++] = '\0';
}
if (flag_m) {
i_fatal("-m missing parameter");
}
if (flag_u) {
i_fatal("-u missing parameter");
}
if (flag_C) {
i_fatal("-C missing parameter");
}
}
}
/* mirror|backup|server */
i_fatal("Missing mirror or backup parameter");
/* we're re-executing dsync due to doveconf.
"backup" re-exec detection is later. */
return;
}
dsync_server = TRUE;
} else
/* we're re-executing dsync due to doveconf */
return;
}
/* dsync flags */
new_flags[0] = '-';
if (!dsync_server) {
if (flag_f)
new_flags[i++] = 'f';
if (flag_R)
new_flags[i++] = 'R';
new_flags[i++] = 'm';
}
new_flags[i] = '\0';
if (i > 1) {
}
}
/* rest of the parameters */
legacy_dsync = TRUE;
optind = 1;
}