~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/doveadm/dsync/doveadm-dsync.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "lib-signals.h"
5
5
#include "array.h"
6
6
#include "execv-const.h"
 
7
#include "fd-set-nonblock.h"
 
8
#include "istream.h"
 
9
#include "ostream.h"
 
10
#include "iostream-ssl.h"
 
11
#include "iostream-rawlog.h"
 
12
#include "write-full.h"
7
13
#include "str.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"
20
32
 
21
33
#include <stdio.h>
22
34
#include <stdlib.h>
23
35
#include <unistd.h>
24
36
#include <ctype.h>
25
 
 
26
 
#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
 
37
#include <sys/wait.h>
 
38
 
 
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'
 
47
 
 
48
enum dsync_run_type {
 
49
        DSYNC_RUN_TYPE_LOCAL,
 
50
        DSYNC_RUN_TYPE_STREAM,
 
51
        DSYNC_RUN_TYPE_CMD
 
52
};
27
53
 
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;
32
61
 
 
62
        const char *remote_name;
33
63
        const char *local_location;
 
64
        pid_t remote_pid;
34
65
 
35
66
        int fd_in, fd_out, fd_err;
36
67
        struct io *io_err;
 
68
        struct istream *input, *err_stream;
 
69
        struct ostream *output;
 
70
 
 
71
        struct ssl_iostream_context *ssl_ctx;
 
72
        struct ssl_iostream *ssl_iostream;
 
73
 
 
74
        enum dsync_run_type run_type;
 
75
        struct server_connection *tcp_conn;
 
76
        const char *error;
37
77
 
38
78
        unsigned int lock_timeout;
39
79
 
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;
44
90
};
45
91
 
46
92
static bool legacy_dsync = FALSE;
47
93
 
48
94
static void remote_error_input(struct dsync_cmd_context *ctx)
49
95
{
50
 
        char buf[1024];
51
 
        ssize_t ret;
 
96
        const unsigned char *data;
 
97
        size_t size;
 
98
        const char *line;
52
99
 
53
 
        ret = read(ctx->fd_err, buf, sizeof(buf)-1);
54
 
        if (ret == -1) {
55
 
                io_remove(&ctx->io_err);
56
 
                return;
57
 
        }
58
 
        if (ret > 0) {
59
 
                buf[ret-1] = '\0';
60
 
                i_error("remote: %s", buf);
 
100
        switch (i_stream_read(ctx->err_stream)) {
 
101
        case -2:
 
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);
 
105
                break;
 
106
        case -1:
 
107
                if (ctx->io_err != NULL)
 
108
                        io_remove(&ctx->io_err);
 
109
                break;
 
110
        default:
 
111
                while ((line = i_stream_next_line(ctx->err_stream)) != NULL)
 
112
                        fprintf(stderr, "%s\n", line);
 
113
                break;
61
114
        }
62
115
}
63
116
 
69
122
        if (pipe(fd_in) < 0 || pipe(fd_out) < 0 || pipe(fd_err) < 0)
70
123
                i_fatal("pipe() failed: %m");
71
124
 
72
 
        switch (fork()) {
 
125
        ctx->remote_pid = fork();
 
126
        switch (ctx->remote_pid) {
73
127
        case -1:
74
128
                i_fatal("fork() failed: %m");
75
129
        case 0:
80
134
                    dup2(fd_err[1], STDERR_FILENO) < 0)
81
135
                        i_fatal("dup2() failed: %m");
82
136
 
83
 
                (void)close(fd_in[0]);
84
 
                (void)close(fd_in[1]);
85
 
                (void)close(fd_out[0]);
86
 
                (void)close(fd_out[1]);
87
 
                (void)close(fd_err[0]);
88
 
                (void)close(fd_err[1]);
 
137
                i_close_fd(&fd_in[0]);
 
138
                i_close_fd(&fd_in[1]);
 
139
                i_close_fd(&fd_out[0]);
 
140
                i_close_fd(&fd_out[1]);
 
141
                i_close_fd(&fd_err[0]);
 
142
                i_close_fd(&fd_err[1]);
89
143
 
90
144
                execvp_const(args[0], args);
91
145
        default:
93
147
                break;
94
148
        }
95
149
 
96
 
        (void)close(fd_in[0]);
97
 
        (void)close(fd_out[1]);
98
 
        (void)close(fd_err[1]);
 
150
        i_close_fd(&fd_in[0]);
 
151
        i_close_fd(&fd_out[1]);
 
152
        i_close_fd(&fd_err[1]);
99
153
        ctx->fd_in = fd_out[0];
100
154
        ctx->fd_out = fd_in[1];
101
155
        ctx->fd_err = fd_err[0];
102
 
        ctx->io_err = io_add(ctx->fd_err, IO_READ, remote_error_input, ctx);
 
156
 
 
157
        if (ctx->remote_user_prefix) {
 
158
                const char *prefix =
 
159
                        t_strdup_printf("%s\n", ctx->ctx.cur_username);
 
160
                if (write_full(ctx->fd_out, prefix, strlen(prefix)) < 0)
 
161
                        i_fatal("write(remote out) failed: %m");
 
162
        }
 
163
 
 
164
        fd_set_nonblock(ctx->fd_err, TRUE);
 
165
        ctx->err_stream = i_stream_create_fd(ctx->fd_err, IO_BLOCK_SIZE, FALSE);
 
166
        i_stream_set_return_partial_line(ctx->err_stream, TRUE);
103
167
}
104
168
 
105
169
static void
126
190
                p = "dsync-server";
127
191
        }
128
192
        array_append(&cmd_args, &p, 1);
129
 
        (void)array_append_space(&cmd_args);
 
193
        array_append_zero(&cmd_args);
130
194
        *cmd_args_r = array_idx(&cmd_args, 0);
131
195
}
132
196
 
133
197
static const char *const *
134
 
get_ssh_cmd_args(struct dsync_cmd_context *ctx,
135
 
                 const char *host, const char *login, const char *mail_user)
 
198
get_ssh_cmd_args(const char *host, const char *login, const char *mail_user)
136
199
{
137
200
        static struct var_expand_table static_tab[] = {
138
201
                { 'u', NULL, "user" },
139
202
                { '\0', NULL, "login" },
140
203
                { '\0', NULL, "host" },
141
 
                { '\0', NULL, "lock_timeout" },
142
 
                { '\0', NULL, "namespace" },
143
204
                { '\0', NULL, NULL }
144
205
        };
145
206
        struct var_expand_table *tab;
153
214
        tab[0].value = mail_user;
154
215
        tab[1].value = login;
155
216
        tab[2].value = host;
156
 
        tab[3].value = dec2str(ctx->lock_timeout);
157
 
        tab[4].value = ctx->namespace_prefix;
158
217
 
159
218
        t_array_init(&cmd_args, 8);
160
219
        str = t_str_new(128);
178
237
                }
179
238
                array_append(&cmd_args, &value, 1);
180
239
        }
181
 
        (void)array_append_space(&cmd_args);
 
240
        array_append_zero(&cmd_args);
182
241
        return array_idx(&cmd_args, 0);
183
242
}
184
243
 
223
282
 
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);
227
286
        return TRUE;
228
287
}
229
288
 
230
 
static struct dsync_worker *
231
 
cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user)
232
 
{
 
289
static void doveadm_user_init_dsync(struct mail_user *user)
 
290
{
 
291
        struct mail_namespace *ns;
 
292
 
 
293
        user->dsyncing = TRUE;
 
294
        for (ns = user->namespaces; ns != NULL; ns = ns->next)
 
295
                ns->list->set.broken_char = DSYNC_LIST_BROKEN_CHAR;
 
296
}
 
297
 
 
298
static bool paths_are_equal(struct mail_user *user1, struct mail_user *user2,
 
299
                            enum mailbox_list_path_type type)
 
300
{
 
301
        const char *path1, *path2;
 
302
 
 
303
        i_assert(user1->namespaces != NULL);
 
304
        i_assert(user2->namespaces != NULL);
 
305
 
 
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;
 
309
}
 
310
 
 
311
static int
 
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)
 
315
{
 
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;
237
 
 
238
 
        i_assert(ctx->local_location != NULL);
239
 
 
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;
 
321
        int ret;
 
322
 
 
323
        if (ctx->local_location_from_arg)
 
324
                location = ctx->ctx.args[0];
 
325
        else {
 
326
                i_assert(ctx->local_location != NULL);
 
327
                location = ctx->local_location;
 
328
        }
 
329
 
 
330
        i_set_failure_prefix("dsync(%s): ", user->username);
242
331
 
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)
248
337
                i_unreached();
249
 
        if (mail_storage_service_next(ctx->ctx.storage_service,
250
 
                                      ctx->ctx.cur_service_user, &user2) < 0)
251
 
                i_fatal("User init failed");
252
 
        user2->admin = TRUE;
 
338
        ret = mail_storage_service_next(ctx->ctx.storage_service,
 
339
                                        ctx->ctx.cur_service_user, &user2);
 
340
        if (ret < 0) {
 
341
                ctx->ctx.exit_code = ret == -1 ? EX_TEMPFAIL : EX_CONFIG;
 
342
                return -1;
 
343
        }
 
344
        doveadm_user_init_dsync(user2);
253
345
 
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)");
259
 
        }
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);
268
 
        }
269
 
 
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);
 
353
                return -1;
 
354
        }
 
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);
 
363
                return -1;
 
364
        }
 
365
 
 
366
        brain2 = dsync_brain_slave_init(user2, ibc2, TRUE);
 
367
 
 
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))
 
373
                        break;
 
374
 
 
375
                i_assert(changed1 || changed2);
 
376
                brain1_running = dsync_brain_run(brain, &changed1);
 
377
                brain2_running = dsync_brain_run(brain2, &changed2);
 
378
        }
272
379
        mail_user_unref(&user2);
273
 
        return worker2;
274
 
}
275
 
 
276
 
static struct dsync_worker *
277
 
cmd_dsync_run_remote(struct dsync_cmd_context *ctx, struct mail_user *user)
278
 
{
279
 
        i_set_failure_prefix(t_strdup_printf("dsync-local(%s): ",
280
 
                                             user->username));
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;
 
383
                return -1;
 
384
        }
 
385
        return 0;
 
386
}
 
387
 
 
388
static void cmd_dsync_wait_remote(struct dsync_cmd_context *ctx,
 
389
                                  int *status_r)
 
390
{
 
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);
 
398
                } else {
 
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);
 
403
                        }
 
404
                }
 
405
                *status_r = -1;
 
406
        }
 
407
}
 
408
 
 
409
static void cmd_dsync_log_remote_status(int status, bool remote_errors_logged)
 
410
{
 
411
        if (status == -1)
 
412
                ;
 
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));
 
422
        }
 
423
}
 
424
 
 
425
static void cmd_dsync_run_remote(struct mail_user *user)
 
426
{
 
427
        i_set_failure_prefix("dsync-local(%s): ", user->username);
 
428
        io_loop_run(current_ioloop);
282
429
}
283
430
 
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)
287
433
{
288
434
        const char *host, *login;
289
435
 
294
440
                host = location;
295
441
                login = "";
296
442
        }
297
 
        return get_ssh_cmd_args(ctx, host, login, username);
298
 
}
299
 
 
300
 
static int dsync_lock(struct mail_user *user, unsigned int lock_timeout,
301
 
                      const char **path_r, struct file_lock **lock_r)
302
 
{
303
 
        const char *home, *path;
304
 
        int ret, fd;
305
 
 
306
 
        if ((ret = mail_user_get_home(user, &home)) < 0) {
307
 
                i_error("Couldn't look up user's home dir");
308
 
                return -1;
309
 
        }
310
 
        if (ret == 0) {
311
 
                i_error("User has no home directory");
312
 
                return -1;
313
 
        }
314
 
 
315
 
        path = t_strconcat(home, "/"DSYNC_LOCK_FILENAME, NULL);
316
 
        fd = creat(path, 0600);
 
443
        return get_ssh_cmd_args(host, login, username);
 
444
}
 
445
 
 
446
static struct dsync_ibc *
 
447
cmd_dsync_icb_stream_init(struct dsync_cmd_context *ctx,
 
448
                          const char *name, const char *temp_prefix)
 
449
{
 
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);
 
455
        } else {
 
456
                i_stream_ref(ctx->input);
 
457
                o_stream_ref(ctx->output);
 
458
        }
 
459
        if (ctx->rawlog_path != NULL) {
 
460
                iostream_rawlog_create_path(ctx->rawlog_path,
 
461
                                            &ctx->input, &ctx->output);
 
462
        }
 
463
        return dsync_ibc_init_stream(ctx->input, ctx->output,
 
464
                                     name, temp_prefix);
 
465
}
 
466
 
 
467
static void
 
468
dsync_replicator_notify(struct dsync_cmd_context *ctx,
 
469
                        enum dsync_brain_sync_type sync_type,
 
470
                        const char *state_str)
 
471
{
 
472
#define REPLICATOR_HANDSHAKE "VERSION\treplicator-doveadm-client\t1\t0\n"
 
473
        const char *path;
 
474
        string_t *str;
 
475
        int fd;
 
476
 
 
477
        path = t_strdup_printf("%s/replicator-doveadm",
 
478
                               ctx->ctx.cur_mail_user->set->base_dir);
 
479
        fd = net_connect_unix(path);
317
480
        if (fd == -1) {
318
 
                i_error("Couldn't create lock %s: %m", path);
319
 
                return -1;
320
 
        }
321
 
 
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);
325
 
                (void)close(fd);
326
 
                return -1;
327
 
        }
328
 
        *path_r = path;
329
 
        return fd;
 
481
                if (errno == ECONNREFUSED || errno == ENOENT) {
 
482
                        /* replicator not running on this server. ignore. */
 
483
                        return;
 
484
                }
 
485
                i_error("net_connect_unix(%s) failed: %m", path);
 
486
                return;
 
487
        }
 
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. */
 
501
        if (close(fd) < 0)
 
502
                i_error("close(%s) failed: %m", path);
330
503
}
331
504
 
332
505
static int
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)
335
507
{
 
508
        struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
 
509
        struct dsync_ibc *ibc, *ibc2 = NULL;
336
510
        struct dsync_brain *brain;
337
 
 
338
 
        /* create and run the brain */
339
 
        brain = dsync_brain_init(worker1, worker2, ctx->mailbox,
340
 
                                 ctx->brain_flags);
341
 
        if (!ctx->remote)
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;
 
516
 
 
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);
 
525
        }
 
526
        doveadm_user_init_dsync(user);
 
527
 
 
528
        if (ctx->namespace_prefix != NULL) {
 
529
                set.sync_ns = mail_namespace_find(user->namespaces,
 
530
                                                  ctx->namespace_prefix);
 
531
        }
 
532
 
 
533
        if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL)
 
534
                dsync_ibc_init_pipe(&ibc, &ibc2);
343
535
        else {
344
 
                dsync_brain_sync(brain);
345
 
                if (!dsync_brain_has_failed(brain))
346
 
                        io_loop_run(current_ioloop);
347
 
        }
348
 
        /* deinit */
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,
 
539
                                                str_c(temp_prefix));
 
540
                if (ctx->fd_err != -1) {
 
541
                        ctx->io_err = io_add(ctx->fd_err, IO_READ,
 
542
                                             remote_error_input, ctx);
 
543
                }
 
544
        }
 
545
 
 
546
        brain_flags = DSYNC_BRAIN_FLAG_SEND_MAIL_REQUESTS;
 
547
        if (ctx->sync_visible_namespaces)
 
548
                brain_flags |= DSYNC_BRAIN_FLAG_SYNC_VISIBLE_NAMESPACES;
 
549
 
 
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;
 
554
 
 
555
        if (ctx->no_mail_sync)
 
556
                brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC;
 
557
        if (ctx->oneway)
 
558
                brain_flags |= DSYNC_BRAIN_FLAG_NO_BACKUP_OVERWRITE;
 
559
        if (doveadm_debug)
 
560
                brain_flags |= DSYNC_BRAIN_FLAG_DEBUG;
 
561
 
 
562
        brain = dsync_brain_master_init(user, ibc, ctx->sync_type,
 
563
                                        brain_flags, &set);
 
564
 
 
565
        if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) {
 
566
                if (cmd_dsync_run_local(ctx, user, brain, ibc2,
 
567
                                        &changes_during_sync) < 0)
 
568
                        ret = -1;
 
569
        } else {
 
570
                cmd_dsync_run_remote(user);
 
571
        }
 
572
 
 
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));
 
577
        }
 
578
 
 
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;
353
583
        }
354
584
        if (dsync_brain_deinit(&brain) < 0) {
355
585
                ctx->ctx.exit_code = EX_TEMPFAIL;
356
 
                return -1;
357
 
        }
358
 
        return 0;
359
 
}
360
 
 
361
 
static int
362
 
cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
363
 
{
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;
369
 
 
370
 
        user->admin = TRUE;
371
 
        user->dsyncing = TRUE;
372
 
 
373
 
        /* create workers */
374
 
        worker1 = dsync_worker_init_local(user, ctx->namespace_prefix,
375
 
                                          *_ctx->set->dsync_alt_char);
376
 
        if (!ctx->remote)
377
 
                worker2 = cmd_dsync_run_local(ctx, user);
378
 
        else
379
 
                worker2 = cmd_dsync_run_remote(ctx, user);
380
 
        if (ctx->reverse_workers) {
381
 
                workertmp = worker1;
382
 
                worker1 = worker2;
383
 
                worker2 = workertmp;
384
 
        }
385
 
 
386
 
        if (!ctx->lock)
387
 
                ret = cmd_dsync_start(ctx, worker1, worker2);
388
 
        else {
389
 
                lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
390
 
                if (lock_fd == -1) {
391
 
                        _ctx->exit_code = EX_TEMPFAIL;
392
 
                        ret = -1;
393
 
                } else {
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);
398
 
                }
399
 
        }
400
 
        dsync_worker_deinit(&worker1);
401
 
        dsync_worker_deinit(&worker2);
 
586
                ret = -1;
 
587
        }
 
588
        dsync_ibc_deinit(&ibc);
 
589
        if (ibc2 != NULL)
 
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);
 
599
        }
 
600
        if (ctx->run_type == DSYNC_RUN_TYPE_CMD)
 
601
                cmd_dsync_wait_remote(ctx, &status);
 
602
 
 
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);
 
611
        }
 
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);
406
 
                ctx->fd_err = -1;
407
 
        }
 
616
        if (ctx->fd_err != -1)
 
617
                i_close_fd(&ctx->fd_err);
 
618
        ctx->input = NULL;
 
619
        ctx->output = NULL;
 
620
 
408
621
        return ret;
409
622
}
410
623
 
 
624
static void dsync_connected_callback(int exit_code, void *context)
 
625
{
 
626
        struct dsync_cmd_context *ctx = context;
 
627
 
 
628
        ctx->ctx.exit_code = exit_code;
 
629
        switch (exit_code) {
 
630
        case 0:
 
631
                server_connection_extract(ctx->tcp_conn, &ctx->input,
 
632
                                          &ctx->output, &ctx->ssl_iostream);
 
633
                break;
 
634
        case SERVER_EXIT_CODE_DISCONNECTED:
 
635
                ctx->error = "Disconnected from remote";
 
636
                break;
 
637
        case EX_NOUSER:
 
638
                ctx->error = "Unknown user in remote";
 
639
                break;
 
640
        default:
 
641
                ctx->error = p_strdup_printf(ctx->ctx.pool,
 
642
                        "Failed to start dsync-server command: %u", exit_code);
 
643
                break;
 
644
        }
 
645
        io_loop_stop(current_ioloop);
 
646
}
 
647
 
 
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)
 
651
{
 
652
        struct ssl_iostream_settings ssl_set;
 
653
 
 
654
        if (ctx->ssl_ctx != NULL)
 
655
                return 0;
 
656
 
 
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;
 
662
 
 
663
        return ssl_iostream_context_init_client(&ssl_set, &ctx->ssl_ctx, error_r);
 
664
}
 
665
 
 
666
static int
 
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)
 
670
{
 
671
        struct doveadm_server *server;
 
672
        struct server_connection *conn;
 
673
        struct ioloop *ioloop;
 
674
        string_t *cmd;
 
675
        const char *error;
 
676
 
 
677
        server = p_new(ctx->ctx.pool, struct doveadm_server, 1);
 
678
        server->name = p_strdup(ctx->ctx.pool, target);
 
679
        if (ssl) {
 
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);
 
683
                        return -1;
 
684
                }
 
685
                server->ssl_ctx = ctx->ssl_ctx;
 
686
        }
 
687
        p_array_init(&server->connections, ctx->ctx.pool, 1);
 
688
        p_array_init(&server->queue, ctx->ctx.pool, 1);
 
689
 
 
690
        ioloop = io_loop_create();
 
691
 
 
692
        if (server_connection_create(server, &conn) < 0) {
 
693
                *error_r = "Couldn't create server connection";
 
694
                return -1;
 
695
        }
 
696
 
 
697
        /* <flags> <username> <command> [<args>] */
 
698
        cmd = t_str_new(256);
 
699
        if (doveadm_debug)
 
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');
 
708
 
 
709
        ctx->tcp_conn = conn;
 
710
        server_connection_cmd(conn, str_c(cmd),
 
711
                              dsync_connected_callback, ctx);
 
712
        io_loop_run(ioloop);
 
713
        ctx->tcp_conn = NULL;
 
714
 
 
715
        if (array_count(&server->connections) > 0)
 
716
                server_connection_destroy(&conn);
 
717
        io_loop_destroy(&ioloop);
 
718
 
 
719
        if (ctx->error != NULL) {
 
720
                *error_r = ctx->error;
 
721
                ctx->error = NULL;
 
722
                return -1;
 
723
        }
 
724
        ctx->run_type = DSYNC_RUN_TYPE_STREAM;
 
725
        return 0;
 
726
}
 
727
 
 
728
static int
 
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)
 
733
{
 
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,
 
738
                                         FALSE, error_r);
 
739
        }
 
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,
 
744
                                         TRUE, error_r);
 
745
        }
 
746
 
 
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;
 
755
        } else {
 
756
                /* local with e.g. maildir:path */
 
757
                ctx->remote_name = NULL;
 
758
                return 0;
 
759
        }
 
760
        *remote_cmd_args_r =
 
761
                parse_ssh_location(ctx->remote_name, ctx->ctx.cur_username);
 
762
        return 0;
 
763
}
 
764
 
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)
415
769
        struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
416
770
        const char *const *remote_cmd_args = NULL;
417
771
        const struct mail_user_settings *user_set;
 
772
        const struct mail_storage_settings *mail_set;
418
773
        const char *username = "";
419
774
 
420
775
        user_set = mail_storage_service_user_get_set(service_user)[0];
 
776
        mail_set = mail_storage_service_user_get_mail_set(service_user);
421
777
 
422
 
        ctx->fd_in = STDIN_FILENO;
423
 
        ctx->fd_out = STDOUT_FILENO;
 
778
        ctx->fd_in = -1;
 
779
        ctx->fd_out = -1;
424
780
        ctx->fd_err = -1;
425
 
        ctx->remote = FALSE;
 
781
        ctx->run_type = DSYNC_RUN_TYPE_LOCAL;
 
782
        ctx->remote_name = "remote";
426
783
 
427
784
        if (ctx->default_replica_location) {
428
785
                ctx->local_location =
444
801
                        if (_ctx->args[1] != NULL)
445
802
                                doveadm_mail_help_name(_ctx->cmd->name);
446
803
                        ctx->local_location = _ctx->args[0];
 
804
                        ctx->local_location_from_arg = TRUE;
447
805
                }
448
806
        }
449
807
 
450
 
        if (remote_cmd_args == NULL && ctx->local_location != NULL &&
451
 
            strncmp(ctx->local_location, "remote:", 7) == 0) {
452
 
                /* this is a remote (ssh) command */
453
 
                remote_cmd_args = parse_ssh_location(ctx, ctx->local_location+7,
454
 
                                                     _ctx->cur_username);
 
808
        if (remote_cmd_args == NULL && ctx->local_location != NULL) {
 
809
                if (parse_location(ctx, mail_set, ctx->local_location,
 
810
                                   &remote_cmd_args, error_r) < 0)
 
811
                        return -1;
455
812
        }
456
813
 
457
814
        if (remote_cmd_args != NULL) {
458
815
                /* do this before mail_storage_service_next() in case it
459
816
                   drops process privileges */
460
817
                run_cmd(ctx, remote_cmd_args);
461
 
                ctx->remote = TRUE;
 
818
                ctx->run_type = DSYNC_RUN_TYPE_CMD;
462
819
        }
 
820
 
 
821
        if (ctx->sync_visible_namespaces &&
 
822
            ctx->run_type == DSYNC_RUN_TYPE_LOCAL)
 
823
                i_fatal("-N parameter requires syncing with remote host");
463
824
        return 0;
464
825
}
465
826
 
475
836
                if (args[0] == NULL)
476
837
                        doveadm_mail_help_name(_ctx->cmd->name);
477
838
        }
 
839
        if (array_count(&ctx->exclude_mailboxes) > 0)
 
840
                array_append_zero(&ctx->exclude_mailboxes);
478
841
 
479
842
        lib_signals_ignore(SIGHUP, TRUE);
480
 
 
481
 
        if (doveadm_debug || doveadm_verbose)
482
 
                ctx->brain_flags |= DSYNC_BRAIN_FLAG_VERBOSE;
483
843
}
484
844
 
485
845
static void cmd_dsync_preinit(struct doveadm_mail_cmd_context *ctx)
492
852
cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
493
853
{
494
854
        struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
 
855
        const char *str;
495
856
 
496
857
        switch (c) {
 
858
        case '1':
 
859
                ctx->oneway = TRUE;
 
860
                ctx->backup = TRUE;
 
861
                break;
497
862
        case 'd':
498
863
                ctx->default_replica_location = TRUE;
499
864
                break;
502
867
                legacy_dsync = TRUE;
503
868
                break;
504
869
        case 'f':
505
 
                ctx->brain_flags |= DSYNC_BRAIN_FLAG_FULL_SYNC;
 
870
                ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL;
 
871
                break;
 
872
        case 'g':
 
873
                if (optarg[0] == '\0')
 
874
                        ctx->no_mail_sync = TRUE;
 
875
                else if (guid_128_from_string(optarg, ctx->mailbox_guid) < 0 ||
 
876
                         guid_128_is_empty(ctx->mailbox_guid))
 
877
                        i_fatal("Invalid -g parameter: %s", optarg);
506
878
                break;
507
879
        case 'l':
508
880
                ctx->lock = TRUE;
509
881
                if (str_to_uint(optarg, &ctx->lock_timeout) < 0)
510
 
                        i_error("Invalid -l parameter: %s", optarg);
 
882
                        i_fatal("Invalid -l parameter: %s", optarg);
511
883
                break;
512
884
        case 'm':
513
 
                ctx->mailbox = optarg;
 
885
                if (optarg[0] == '\0')
 
886
                        ctx->no_mail_sync = TRUE;
 
887
                else
 
888
                        ctx->mailbox = optarg;
 
889
                break;
 
890
        case 'x':
 
891
                str = optarg;
 
892
                array_append(&ctx->exclude_mailboxes, &str, 1);
514
893
                break;
515
894
        case 'n':
516
895
                ctx->namespace_prefix = optarg;
517
896
                break;
 
897
        case 'N':
 
898
                ctx->sync_visible_namespaces = TRUE;
 
899
                break;
 
900
        case 'r':
 
901
                ctx->rawlog_path = optarg;
 
902
                break;
518
903
        case 'R':
519
 
                ctx->reverse_workers = TRUE;
 
904
                ctx->reverse_backup = TRUE;
 
905
                break;
 
906
        case 's':
 
907
                if (ctx->sync_type != DSYNC_BRAIN_SYNC_TYPE_FULL &&
 
908
                    *optarg != '\0')
 
909
                        ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_STATE;
 
910
                ctx->state_input = optarg;
 
911
                break;
 
912
        case 'U':
 
913
                ctx->replicator_notify = TRUE;
520
914
                break;
521
915
        default:
522
916
                return FALSE;
529
923
        struct dsync_cmd_context *ctx;
530
924
 
531
925
        ctx = doveadm_mail_cmd_alloc(struct dsync_cmd_context);
532
 
        ctx->ctx.getopt_args = "+dEfl:m:n:R";
 
926
        ctx->ctx.getopt_args = DSYNC_COMMON_GETOPT_ARGS;
533
927
        ctx->ctx.v.parse_arg = cmd_mailbox_dsync_parse_arg;
534
928
        ctx->ctx.v.preinit = cmd_dsync_preinit;
535
929
        ctx->ctx.v.init = cmd_dsync_init;
536
930
        ctx->ctx.v.prerun = cmd_dsync_prerun;
537
931
        ctx->ctx.v.run = cmd_dsync_run;
 
932
        ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_CHANGED;
 
933
        doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW);
 
934
        doveadm_print_header("state", "state",
 
935
                             DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
 
936
        p_array_init(&ctx->exclude_mailboxes, ctx->ctx.pool, 4);
538
937
        return &ctx->ctx;
539
938
}
540
939
 
544
943
        struct dsync_cmd_context *ctx;
545
944
 
546
945
        _ctx = cmd_dsync_alloc();
 
946
        _ctx->getopt_args = DSYNC_COMMON_GETOPT_ARGS"R";
547
947
        ctx = (struct dsync_cmd_context *)_ctx;
548
 
        ctx->brain_flags |= DSYNC_BRAIN_FLAG_BACKUP;
 
948
        ctx->backup = TRUE;
549
949
        return _ctx;
550
950
}
551
951
 
554
954
                     struct mail_user *user)
555
955
{
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;
562
 
 
563
 
        user->admin = TRUE;
564
 
        user->dsyncing = TRUE;
565
 
 
566
 
        i_set_failure_prefix(t_strdup_printf("dsync-remote(%s): ",
567
 
                                             user->username));
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);
571
 
 
572
 
        if (!ctx->lock)
573
 
                io_loop_run(current_ioloop);
574
 
        else {
575
 
                lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
576
 
                if (lock_fd == -1) {
577
 
                        _ctx->exit_code = EX_TEMPFAIL;
578
 
                        ret = -1;
579
 
                } else {
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);
584
 
                }
585
 
        }
586
 
 
587
 
        dsync_proxy_server_deinit(&server);
588
 
        dsync_worker_deinit(&worker);
589
 
        return ret;
 
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;
 
961
 
 
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);
 
969
        }
 
970
        doveadm_user_init_dsync(user);
 
971
 
 
972
        i_set_failure_prefix("dsync-remote(%s): ", user->username);
 
973
 
 
974
        temp_prefix = t_str_new(64);
 
975
        mail_user_set_get_temp_prefix(temp_prefix, user->set);
 
976
 
 
977
        ibc = cmd_dsync_icb_stream_init(ctx, "local", str_c(temp_prefix));
 
978
        brain = dsync_brain_slave_init(user, ibc, FALSE);
 
979
 
 
980
        io_loop_run(current_ioloop);
 
981
 
 
982
        if (ctx->replicator_notify) {
 
983
                state_str = t_str_new(128);
 
984
                dsync_brain_get_state(brain, state_str);
 
985
        }
 
986
        sync_type = dsync_brain_get_sync_type(brain);
 
987
 
 
988
        if (dsync_brain_deinit(&brain) < 0)
 
989
                _ctx->exit_code = EX_TEMPFAIL;
 
990
        dsync_ibc_deinit(&ibc);
 
991
 
 
992
        if (_ctx->conn != NULL) {
 
993
                /* make sure nothing more is written by the generic doveadm
 
994
                   connection code */
 
995
                o_stream_close(_ctx->conn->output);
 
996
        }
 
997
 
 
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;
590
1001
}
591
1002
 
592
1003
static bool
599
1010
                /* dsync wrapper detection flag */
600
1011
                legacy_dsync = TRUE;
601
1012
                break;
602
 
        case 'l':
603
 
                ctx->lock = TRUE;
604
 
                if (str_to_uint(optarg, &ctx->lock_timeout) < 0)
605
 
                        i_error("Invalid -l parameter: %s", optarg);
 
1013
        case 'r':
 
1014
                ctx->rawlog_path = optarg;
606
1015
                break;
607
 
        case 'n':
608
 
                ctx->namespace_prefix = optarg;
 
1016
        case 'U':
 
1017
                ctx->replicator_notify = TRUE;
609
1018
                break;
610
1019
        default:
611
1020
                return FALSE;
618
1027
        struct dsync_cmd_context *ctx;
619
1028
 
620
1029
        ctx = doveadm_mail_cmd_alloc(struct dsync_cmd_context);
621
 
        ctx->ctx.getopt_args = "El:n:";
 
1030
        ctx->ctx.getopt_args = "Er:U";
622
1031
        ctx->ctx.v.parse_arg = cmd_mailbox_dsync_server_parse_arg;
623
1032
        ctx->ctx.v.run = cmd_dsync_server_run;
 
1033
        ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_CHANGED;
 
1034
        ctx->fd_in = STDIN_FILENO;
 
1035
        ctx->fd_out = STDOUT_FILENO;
624
1036
        return &ctx->ctx;
625
1037
}
626
1038
 
627
1039
struct doveadm_mail_cmd cmd_dsync_mirror = {
628
1040
        cmd_dsync_alloc, "sync",
629
 
        "[-dfR] [-l <secs>] [-m <mailbox>] [-n <namespace>] <dest>"
 
1041
        "[-1dfR] [-l <secs>] [-r <rawlog path>] [-m <mailbox>] [-n <namespace> | -N] [-x <exclude>] [-s <state>] <dest>"
630
1042
};
631
1043
struct doveadm_mail_cmd cmd_dsync_backup = {
632
1044
        cmd_dsync_backup_alloc, "backup",
633
 
        "[-dfR] [-l <secs>] [-m <mailbox>] [-n <namespace>] <dest>"
 
1045
        "[-dfR] [-l <secs>] [-r <rawlog path>] [-m <mailbox>] [-n <namespace> | -N] [-x <exclude>] [-s <state>] <dest>"
634
1046
};
635
1047
struct doveadm_mail_cmd cmd_dsync_server = {
636
1048
        cmd_dsync_server_alloc, "dsync-server", &doveadm_mail_cmd_hide