1
/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
4
4
#include "lib-signals.h"
6
6
#include "execv-const.h"
7
#include "fd-set-nonblock.h"
10
#include "iostream-ssl.h"
11
#include "iostream-rawlog.h"
12
#include "write-full.h"
14
#include "strescape.h"
8
15
#include "var-expand.h"
9
16
#include "settings-parser.h"
10
17
#include "master-service.h"
18
#include "master-service-ssl-settings.h"
11
19
#include "mail-storage-service.h"
12
20
#include "mail-user.h"
13
21
#include "mail-namespace.h"
22
#include "mailbox-list-private.h"
14
23
#include "doveadm-settings.h"
15
24
#include "doveadm-mail.h"
25
#include "doveadm-print.h"
26
#include "doveadm-server.h"
27
#include "client-connection.h"
28
#include "server-connection.h"
16
29
#include "dsync-brain.h"
17
#include "dsync-worker.h"
18
#include "dsync-proxy-server.h"
30
#include "dsync-ibc.h"
19
31
#include "doveadm-dsync.h"
22
34
#include <stdlib.h>
23
35
#include <unistd.h>
26
#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
39
#define DSYNC_COMMON_GETOPT_ARGS "+1dEfg:l:m:n:Nr:Rs:Ux:"
40
#define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
41
/* The broken_char is mainly set to get a proper error message when trying to
42
convert a mailbox with a name that can't be used properly translated between
43
vname/storage_name and would otherwise be mixed up with a normal "mailbox
44
doesn't exist" error message. This could be any control character, since
45
none of them are allowed to be created in regular mailbox names. */
46
#define DSYNC_LIST_BROKEN_CHAR '\003'
50
DSYNC_RUN_TYPE_STREAM,
28
54
struct dsync_cmd_context {
29
55
struct doveadm_mail_cmd_context ctx;
30
enum dsync_brain_flags brain_flags;
56
enum dsync_brain_sync_type sync_type;
31
57
const char *mailbox, *namespace_prefix;
58
guid_128_t mailbox_guid;
59
const char *state_input, *rawlog_path;
60
ARRAY_TYPE(const_string) exclude_mailboxes;
62
const char *remote_name;
33
63
const char *local_location;
35
66
int fd_in, fd_out, fd_err;
68
struct istream *input, *err_stream;
69
struct ostream *output;
71
struct ssl_iostream_context *ssl_ctx;
72
struct ssl_iostream *ssl_iostream;
74
enum dsync_run_type run_type;
75
struct server_connection *tcp_conn;
38
78
unsigned int lock_timeout;
40
80
unsigned int lock:1;
81
unsigned int sync_visible_namespaces:1;
41
82
unsigned int default_replica_location:1;
42
unsigned int reverse_workers:1;
43
unsigned int remote:1;
83
unsigned int oneway:1;
84
unsigned int backup:1;
85
unsigned int reverse_backup:1;
86
unsigned int remote_user_prefix:1;
87
unsigned int no_mail_sync:1;
88
unsigned int local_location_from_arg:1;
89
unsigned int replicator_notify:1;
46
92
static bool legacy_dsync = FALSE;
48
94
static void remote_error_input(struct dsync_cmd_context *ctx)
96
const unsigned char *data;
53
ret = read(ctx->fd_err, buf, sizeof(buf)-1);
55
io_remove(&ctx->io_err);
60
i_error("remote: %s", buf);
100
switch (i_stream_read(ctx->err_stream)) {
102
data = i_stream_get_data(ctx->err_stream, &size);
103
fprintf(stderr, "%.*s", (int)size, data);
104
i_stream_skip(ctx->err_stream, size);
107
if (ctx->io_err != NULL)
108
io_remove(&ctx->io_err);
111
while ((line = i_stream_next_line(ctx->err_stream)) != NULL)
112
fprintf(stderr, "%s\n", line);
224
283
/* we'll assume virtual users, so in user@host it really means not to
225
284
give ssh a username, but to give dsync -u user parameter. */
226
*cmd_args_r = get_ssh_cmd_args(ctx, host, "", user);
285
*cmd_args_r = get_ssh_cmd_args(host, "", user);
230
static struct dsync_worker *
231
cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user)
289
static void doveadm_user_init_dsync(struct mail_user *user)
291
struct mail_namespace *ns;
293
user->dsyncing = TRUE;
294
for (ns = user->namespaces; ns != NULL; ns = ns->next)
295
ns->list->set.broken_char = DSYNC_LIST_BROKEN_CHAR;
298
static bool paths_are_equal(struct mail_user *user1, struct mail_user *user2,
299
enum mailbox_list_path_type type)
301
const char *path1, *path2;
303
i_assert(user1->namespaces != NULL);
304
i_assert(user2->namespaces != NULL);
306
return mailbox_list_get_root_path(user1->namespaces->list, type, &path1) &&
307
mailbox_list_get_root_path(user2->namespaces->list, type, &path2) &&
308
strcmp(path1, path2) == 0;
312
cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user,
313
struct dsync_brain *brain, struct dsync_ibc *ibc2,
314
bool *changes_during_sync_r)
316
struct dsync_brain *brain2;
233
317
struct mail_user *user2;
234
struct dsync_worker *worker2;
235
318
struct setting_parser_context *set_parser;
236
const char *set_line, *path1, *path2;
238
i_assert(ctx->local_location != NULL);
240
ctx->brain_flags |= DSYNC_BRAIN_FLAG_LOCAL;
241
i_set_failure_prefix(t_strdup_printf("dsync(%s): ", user->username));
319
const char *set_line, *location;
320
bool brain1_running, brain2_running, changed1, changed2;
323
if (ctx->local_location_from_arg)
324
location = ctx->ctx.args[0];
326
i_assert(ctx->local_location != NULL);
327
location = ctx->local_location;
330
i_set_failure_prefix("dsync(%s): ", user->username);
243
332
/* update mail_location and create another user for the
244
333
second location. */
245
334
set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user);
246
set_line = t_strconcat("mail_location=", ctx->local_location, NULL);
335
set_line = t_strconcat("mail_location=", location, NULL);
247
336
if (settings_parse_line(set_parser, set_line) < 0)
249
if (mail_storage_service_next(ctx->ctx.storage_service,
250
ctx->ctx.cur_service_user, &user2) < 0)
251
i_fatal("User init failed");
338
ret = mail_storage_service_next(ctx->ctx.storage_service,
339
ctx->ctx.cur_service_user, &user2);
341
ctx->ctx.exit_code = ret == -1 ? EX_TEMPFAIL : EX_CONFIG;
344
doveadm_user_init_dsync(user2);
254
346
if (mail_namespaces_get_root_sep(user->namespaces) !=
255
347
mail_namespaces_get_root_sep(user2->namespaces)) {
256
i_fatal("Mail locations must use the same "
348
i_error("Mail locations must use the same "
257
349
"virtual mailbox hierarchy separator "
258
350
"(specify separator for the default namespace)");
260
path1 = mailbox_list_get_path(user->namespaces->list, NULL,
261
MAILBOX_LIST_PATH_TYPE_MAILBOX);
262
path2 = mailbox_list_get_path(user2->namespaces->list, NULL,
263
MAILBOX_LIST_PATH_TYPE_MAILBOX);
264
if (path1 != NULL && path2 != NULL &&
265
strcmp(path1, path2) == 0) {
266
i_fatal("Both source and destination mail_location "
267
"points to same directory: %s", path1);
270
worker2 = dsync_worker_init_local(user2, ctx->namespace_prefix,
271
*ctx->ctx.set->dsync_alt_char);
351
ctx->ctx.exit_code = EX_CONFIG;
352
mail_user_unref(&user2);
355
if (paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_MAILBOX) &&
356
paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_INDEX)) {
357
i_error("Both source and destination mail_location "
358
"points to same directory: %s",
359
mailbox_list_get_root_forced(user->namespaces->list,
360
MAILBOX_LIST_PATH_TYPE_MAILBOX));
361
ctx->ctx.exit_code = EX_CONFIG;
362
mail_user_unref(&user2);
366
brain2 = dsync_brain_slave_init(user2, ibc2, TRUE);
368
brain1_running = brain2_running = TRUE;
369
changed1 = changed2 = TRUE;
370
while (brain1_running || brain2_running) {
371
if (dsync_brain_has_failed(brain) ||
372
dsync_brain_has_failed(brain2))
375
i_assert(changed1 || changed2);
376
brain1_running = dsync_brain_run(brain, &changed1);
377
brain2_running = dsync_brain_run(brain2, &changed2);
272
379
mail_user_unref(&user2);
276
static struct dsync_worker *
277
cmd_dsync_run_remote(struct dsync_cmd_context *ctx, struct mail_user *user)
279
i_set_failure_prefix(t_strdup_printf("dsync-local(%s): ",
281
return dsync_worker_init_proxy_client(ctx->fd_in, ctx->fd_out);
380
*changes_during_sync_r = dsync_brain_has_unexpected_changes(brain2);
381
if (dsync_brain_deinit(&brain2) < 0) {
382
ctx->ctx.exit_code = EX_TEMPFAIL;
388
static void cmd_dsync_wait_remote(struct dsync_cmd_context *ctx,
391
/* wait for the remote command to finish to see any final errors.
392
don't wait very long though. */
393
alarm(DSYNC_REMOTE_CMD_EXIT_WAIT_SECS);
394
if (waitpid(ctx->remote_pid, status_r, 0) == -1) {
395
if (errno != EINTR) {
396
i_error("waitpid(%ld) failed: %m",
397
(long)ctx->remote_pid);
399
i_error("Remote command process isn't dying, killing it");
400
if (kill(ctx->remote_pid, SIGKILL) < 0 && errno != ESRCH) {
401
i_error("kill(%ld, SIGKILL) failed: %m",
402
(long)ctx->remote_pid);
409
static void cmd_dsync_log_remote_status(int status, bool remote_errors_logged)
413
else if (WIFSIGNALED(status))
414
i_error("Remote command died with signal %d", WTERMSIG(status));
415
else if (!WIFEXITED(status))
416
i_error("Remote command failed with status %d", status);
417
else if (WEXITSTATUS(status) == EX_TEMPFAIL && remote_errors_logged) {
418
/* remote most likely already logged the error.
419
don't bother logging another line about it */
420
} else if (WEXITSTATUS(status) != 0) {
421
i_error("Remote command returned error %d", WEXITSTATUS(status));
425
static void cmd_dsync_run_remote(struct mail_user *user)
427
i_set_failure_prefix("dsync-local(%s): ", user->username);
428
io_loop_run(current_ioloop);
284
431
static const char *const *
285
parse_ssh_location(struct dsync_cmd_context *ctx,
286
const char *location, const char *username)
432
parse_ssh_location(const char *location, const char *username)
288
434
const char *host, *login;
297
return get_ssh_cmd_args(ctx, host, login, username);
300
static int dsync_lock(struct mail_user *user, unsigned int lock_timeout,
301
const char **path_r, struct file_lock **lock_r)
303
const char *home, *path;
306
if ((ret = mail_user_get_home(user, &home)) < 0) {
307
i_error("Couldn't look up user's home dir");
311
i_error("User has no home directory");
315
path = t_strconcat(home, "/"DSYNC_LOCK_FILENAME, NULL);
316
fd = creat(path, 0600);
443
return get_ssh_cmd_args(host, login, username);
446
static struct dsync_ibc *
447
cmd_dsync_icb_stream_init(struct dsync_cmd_context *ctx,
448
const char *name, const char *temp_prefix)
450
if (ctx->input == NULL) {
451
fd_set_nonblock(ctx->fd_in, TRUE);
452
fd_set_nonblock(ctx->fd_out, TRUE);
453
ctx->input = i_stream_create_fd(ctx->fd_in, (size_t)-1, FALSE);
454
ctx->output = o_stream_create_fd(ctx->fd_out, (size_t)-1, FALSE);
456
i_stream_ref(ctx->input);
457
o_stream_ref(ctx->output);
459
if (ctx->rawlog_path != NULL) {
460
iostream_rawlog_create_path(ctx->rawlog_path,
461
&ctx->input, &ctx->output);
463
return dsync_ibc_init_stream(ctx->input, ctx->output,
468
dsync_replicator_notify(struct dsync_cmd_context *ctx,
469
enum dsync_brain_sync_type sync_type,
470
const char *state_str)
472
#define REPLICATOR_HANDSHAKE "VERSION\treplicator-doveadm-client\t1\t0\n"
477
path = t_strdup_printf("%s/replicator-doveadm",
478
ctx->ctx.cur_mail_user->set->base_dir);
479
fd = net_connect_unix(path);
318
i_error("Couldn't create lock %s: %m", path);
322
if (file_wait_lock(fd, path, F_WRLCK, FILE_LOCK_METHOD_FCNTL,
323
lock_timeout, lock_r) <= 0) {
324
i_error("Couldn't lock %s: %m", path);
481
if (errno == ECONNREFUSED || errno == ENOENT) {
482
/* replicator not running on this server. ignore. */
485
i_error("net_connect_unix(%s) failed: %m", path);
488
str = t_str_new(128);
489
str_append(str, REPLICATOR_HANDSHAKE"NOTIFY\t");
490
str_append_tabescaped(str, ctx->ctx.cur_mail_user->username);
491
str_append_c(str, '\t');
492
if (sync_type == DSYNC_BRAIN_SYNC_TYPE_FULL)
493
str_append_c(str, 'f');
494
str_append_c(str, '\t');
495
str_append_tabescaped(str, state_str);
496
str_append_c(str, '\n');
497
if (write_full(fd, str_data(str), str_len(str)) < 0)
498
i_error("write(%s) failed: %m", path);
499
/* we only wanted to notify replicator. we don't care enough about the
500
answer to wait for it. */
502
i_error("close(%s) failed: %m", path);
333
cmd_dsync_start(struct dsync_cmd_context *ctx, struct dsync_worker *worker1,
334
struct dsync_worker *worker2)
506
cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
508
struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
509
struct dsync_ibc *ibc, *ibc2 = NULL;
336
510
struct dsync_brain *brain;
338
/* create and run the brain */
339
brain = dsync_brain_init(worker1, worker2, ctx->mailbox,
342
dsync_brain_sync_all(brain);
511
struct dsync_brain_settings set;
512
enum dsync_brain_flags brain_flags;
513
bool remote_errors_logged = FALSE;
514
bool changes_during_sync = FALSE;
515
int status = 0, ret = 0;
517
memset(&set, 0, sizeof(set));
518
set.sync_box = ctx->mailbox;
519
memcpy(set.sync_box_guid, ctx->mailbox_guid, sizeof(set.sync_box_guid));
520
set.lock_timeout_secs = ctx->lock_timeout;
521
set.state = ctx->state_input;
522
if (array_count(&ctx->exclude_mailboxes) > 0) {
523
/* array is NULL-terminated in init() */
524
set.exclude_mailboxes = array_idx(&ctx->exclude_mailboxes, 0);
526
doveadm_user_init_dsync(user);
528
if (ctx->namespace_prefix != NULL) {
529
set.sync_ns = mail_namespace_find(user->namespaces,
530
ctx->namespace_prefix);
533
if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL)
534
dsync_ibc_init_pipe(&ibc, &ibc2);
344
dsync_brain_sync(brain);
345
if (!dsync_brain_has_failed(brain))
346
io_loop_run(current_ioloop);
349
if (dsync_brain_has_unexpected_changes(brain)) {
536
string_t *temp_prefix = t_str_new(64);
537
mail_user_set_get_temp_prefix(temp_prefix, user->set);
538
ibc = cmd_dsync_icb_stream_init(ctx, ctx->remote_name,
540
if (ctx->fd_err != -1) {
541
ctx->io_err = io_add(ctx->fd_err, IO_READ,
542
remote_error_input, ctx);
546
brain_flags = DSYNC_BRAIN_FLAG_SEND_MAIL_REQUESTS;
547
if (ctx->sync_visible_namespaces)
548
brain_flags |= DSYNC_BRAIN_FLAG_SYNC_VISIBLE_NAMESPACES;
550
if (ctx->reverse_backup)
551
brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_RECV;
552
else if (ctx->backup)
553
brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_SEND;
555
if (ctx->no_mail_sync)
556
brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC;
558
brain_flags |= DSYNC_BRAIN_FLAG_NO_BACKUP_OVERWRITE;
560
brain_flags |= DSYNC_BRAIN_FLAG_DEBUG;
562
brain = dsync_brain_master_init(user, ibc, ctx->sync_type,
565
if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) {
566
if (cmd_dsync_run_local(ctx, user, brain, ibc2,
567
&changes_during_sync) < 0)
570
cmd_dsync_run_remote(user);
573
if (ctx->state_input != NULL) {
574
string_t *state_str = t_str_new(128);
575
dsync_brain_get_state(brain, state_str);
576
doveadm_print(str_c(state_str));
579
if (dsync_brain_has_unexpected_changes(brain) || changes_during_sync) {
350
580
i_warning("Mailbox changes caused a desync. "
351
581
"You may want to run dsync again.");
352
582
ctx->ctx.exit_code = 2;
354
584
if (dsync_brain_deinit(&brain) < 0) {
355
585
ctx->ctx.exit_code = EX_TEMPFAIL;
362
cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
364
struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
365
struct dsync_worker *worker1, *worker2, *workertmp;
366
const char *lock_path;
367
struct file_lock *lock;
368
int lock_fd, ret = 0;
371
user->dsyncing = TRUE;
374
worker1 = dsync_worker_init_local(user, ctx->namespace_prefix,
375
*_ctx->set->dsync_alt_char);
377
worker2 = cmd_dsync_run_local(ctx, user);
379
worker2 = cmd_dsync_run_remote(ctx, user);
380
if (ctx->reverse_workers) {
387
ret = cmd_dsync_start(ctx, worker1, worker2);
389
lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
391
_ctx->exit_code = EX_TEMPFAIL;
394
ret = cmd_dsync_start(ctx, worker1, worker2);
395
file_lock_free(&lock);
396
if (close(lock_fd) < 0)
397
i_error("close(%s) failed: %m", lock_path);
400
dsync_worker_deinit(&worker1);
401
dsync_worker_deinit(&worker2);
588
dsync_ibc_deinit(&ibc);
590
dsync_ibc_deinit(&ibc2);
591
if (ctx->ssl_iostream != NULL)
592
ssl_iostream_destroy(&ctx->ssl_iostream);
593
if (ctx->ssl_ctx != NULL)
594
ssl_iostream_context_deinit(&ctx->ssl_ctx);
595
if (ctx->fd_in != -1) {
596
if (ctx->fd_out != ctx->fd_in)
597
i_close_fd(&ctx->fd_out);
598
i_close_fd(&ctx->fd_in);
600
if (ctx->run_type == DSYNC_RUN_TYPE_CMD)
601
cmd_dsync_wait_remote(ctx, &status);
603
/* print any final errors after the process has died. not closing
604
stdin/stdout before wait() may cause the process to hang, but stderr
605
shouldn't (at least with ssh) and we need stderr to be open to be
606
able to print the final errors */
607
if (ctx->err_stream != NULL) {
608
remote_error_input(ctx);
609
remote_errors_logged = ctx->err_stream->v_offset > 0;
610
i_stream_destroy(&ctx->err_stream);
612
if (ctx->run_type == DSYNC_RUN_TYPE_CMD)
613
cmd_dsync_log_remote_status(status, remote_errors_logged);
402
614
if (ctx->io_err != NULL)
403
615
io_remove(&ctx->io_err);
404
if (ctx->fd_err != -1) {
405
(void)close(ctx->fd_err);
616
if (ctx->fd_err != -1)
617
i_close_fd(&ctx->fd_err);
624
static void dsync_connected_callback(int exit_code, void *context)
626
struct dsync_cmd_context *ctx = context;
628
ctx->ctx.exit_code = exit_code;
631
server_connection_extract(ctx->tcp_conn, &ctx->input,
632
&ctx->output, &ctx->ssl_iostream);
634
case SERVER_EXIT_CODE_DISCONNECTED:
635
ctx->error = "Disconnected from remote";
638
ctx->error = "Unknown user in remote";
641
ctx->error = p_strdup_printf(ctx->ctx.pool,
642
"Failed to start dsync-server command: %u", exit_code);
645
io_loop_stop(current_ioloop);
648
static int dsync_init_ssl_ctx(struct dsync_cmd_context *ctx,
649
const struct mail_storage_settings *mail_set,
650
const char **error_r)
652
struct ssl_iostream_settings ssl_set;
654
if (ctx->ssl_ctx != NULL)
657
memset(&ssl_set, 0, sizeof(ssl_set));
658
ssl_set.ca_dir = mail_set->ssl_client_ca_dir;
659
ssl_set.ca_file = mail_set->ssl_client_ca_file;
660
ssl_set.verify_remote_cert = TRUE;
661
ssl_set.crypto_device = mail_set->ssl_crypto_device;
663
return ssl_iostream_context_init_client(&ssl_set, &ctx->ssl_ctx, error_r);
667
dsync_connect_tcp(struct dsync_cmd_context *ctx,
668
const struct mail_storage_settings *mail_set,
669
const char *target, bool ssl, const char **error_r)
671
struct doveadm_server *server;
672
struct server_connection *conn;
673
struct ioloop *ioloop;
677
server = p_new(ctx->ctx.pool, struct doveadm_server, 1);
678
server->name = p_strdup(ctx->ctx.pool, target);
680
if (dsync_init_ssl_ctx(ctx, mail_set, &error) < 0) {
681
*error_r = t_strdup_printf(
682
"Couldn't initialize SSL context: %s", error);
685
server->ssl_ctx = ctx->ssl_ctx;
687
p_array_init(&server->connections, ctx->ctx.pool, 1);
688
p_array_init(&server->queue, ctx->ctx.pool, 1);
690
ioloop = io_loop_create();
692
if (server_connection_create(server, &conn) < 0) {
693
*error_r = "Couldn't create server connection";
697
/* <flags> <username> <command> [<args>] */
698
cmd = t_str_new(256);
700
str_append_c(cmd, 'D');
701
str_append_c(cmd, '\t');
702
str_append_tabescaped(cmd, ctx->ctx.cur_username);
703
str_append(cmd, "\tdsync-server\t-u");
704
str_append_tabescaped(cmd, ctx->ctx.cur_username);
705
if (ctx->replicator_notify)
706
str_append(cmd, "\t-U");
707
str_append_c(cmd, '\n');
709
ctx->tcp_conn = conn;
710
server_connection_cmd(conn, str_c(cmd),
711
dsync_connected_callback, ctx);
713
ctx->tcp_conn = NULL;
715
if (array_count(&server->connections) > 0)
716
server_connection_destroy(&conn);
717
io_loop_destroy(&ioloop);
719
if (ctx->error != NULL) {
720
*error_r = ctx->error;
724
ctx->run_type = DSYNC_RUN_TYPE_STREAM;
729
parse_location(struct dsync_cmd_context *ctx,
730
const struct mail_storage_settings *mail_set,
731
const char *location,
732
const char *const **remote_cmd_args_r, const char **error_r)
734
if (strncmp(location, "tcp:", 4) == 0) {
735
/* TCP connection to remote dsync */
736
ctx->remote_name = location+4;
737
return dsync_connect_tcp(ctx, mail_set, ctx->remote_name,
740
if (strncmp(location, "tcps:", 5) == 0) {
741
/* TCP+SSL connection to remote dsync */
742
ctx->remote_name = location+5;
743
return dsync_connect_tcp(ctx, mail_set, ctx->remote_name,
747
if (strncmp(location, "remote:", 7) == 0) {
748
/* this is a remote (ssh) command */
749
ctx->remote_name = location+7;
750
} else if (strncmp(location, "remoteprefix:", 13) == 0) {
751
/* this is a remote (ssh) command with a "user\n"
752
prefix sent before dsync actually starts */
753
ctx->remote_name = location+13;
754
ctx->remote_user_prefix = TRUE;
756
/* local with e.g. maildir:path */
757
ctx->remote_name = NULL;
761
parse_ssh_location(ctx->remote_name, ctx->ctx.cur_username);
411
765
static int cmd_dsync_prerun(struct doveadm_mail_cmd_context *_ctx,
412
766
struct mail_storage_service_user *service_user,
413
767
const char **error_r)
554
954
struct mail_user *user)
556
956
struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
557
struct dsync_proxy_server *server;
558
struct dsync_worker *worker;
559
struct file_lock *lock;
560
const char *lock_path;
561
int lock_fd, ret = 0;
564
user->dsyncing = TRUE;
566
i_set_failure_prefix(t_strdup_printf("dsync-remote(%s): ",
568
worker = dsync_worker_init_local(user, ctx->namespace_prefix,
569
*_ctx->set->dsync_alt_char);
570
server = dsync_proxy_server_init(STDIN_FILENO, STDOUT_FILENO, worker);
573
io_loop_run(current_ioloop);
575
lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
577
_ctx->exit_code = EX_TEMPFAIL;
580
io_loop_run(current_ioloop);
581
file_lock_free(&lock);
582
if (close(lock_fd) < 0)
583
i_error("close(%s) failed: %m", lock_path);
587
dsync_proxy_server_deinit(&server);
588
dsync_worker_deinit(&worker);
957
struct dsync_ibc *ibc;
958
struct dsync_brain *brain;
959
string_t *temp_prefix, *state_str = NULL;
960
enum dsync_brain_sync_type sync_type;
962
if (_ctx->conn != NULL) {
963
/* doveadm-server connection. start with a success reply.
964
after that follows the regular dsync protocol. */
965
ctx->fd_in = ctx->fd_out = -1;
966
ctx->input = _ctx->conn->input;
967
ctx->output = _ctx->conn->output;
968
o_stream_nsend(ctx->output, "\n+\n", 3);
970
doveadm_user_init_dsync(user);
972
i_set_failure_prefix("dsync-remote(%s): ", user->username);
974
temp_prefix = t_str_new(64);
975
mail_user_set_get_temp_prefix(temp_prefix, user->set);
977
ibc = cmd_dsync_icb_stream_init(ctx, "local", str_c(temp_prefix));
978
brain = dsync_brain_slave_init(user, ibc, FALSE);
980
io_loop_run(current_ioloop);
982
if (ctx->replicator_notify) {
983
state_str = t_str_new(128);
984
dsync_brain_get_state(brain, state_str);
986
sync_type = dsync_brain_get_sync_type(brain);
988
if (dsync_brain_deinit(&brain) < 0)
989
_ctx->exit_code = EX_TEMPFAIL;
990
dsync_ibc_deinit(&ibc);
992
if (_ctx->conn != NULL) {
993
/* make sure nothing more is written by the generic doveadm
995
o_stream_close(_ctx->conn->output);
998
if (ctx->replicator_notify && _ctx->exit_code == 0)
999
dsync_replicator_notify(ctx, sync_type, str_c(state_str));
1000
return _ctx->exit_code == 0 ? 0 : -1;