Mercurial > dovecot > core-2.2
changeset 18371:b900b50085fc
dsync: Use storage's mail_error to choose the doveadm exit code.
Instead of always assuming that all errors are EX_TEMPFAIL.
line wrap: on
line diff
--- a/src/doveadm/doveadm-dsync.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/doveadm-dsync.c Thu Mar 19 00:41:19 2015 +0200 @@ -322,7 +322,7 @@ static int cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user, struct dsync_brain *brain, struct dsync_ibc *ibc2, - bool *changes_during_sync_r) + bool *changes_during_sync_r, enum mail_error *mail_error_r) { struct dsync_brain *brain2; struct mail_user *user2; @@ -331,6 +331,8 @@ bool brain1_running, brain2_running, changed1, changed2; int ret; + *mail_error_r = 0; + if (ctx->local_location_from_arg) location = ctx->ctx.args[0]; else { @@ -389,11 +391,7 @@ brain2_running = dsync_brain_run(brain2, &changed2); } *changes_during_sync_r = dsync_brain_has_unexpected_changes(brain2); - if (dsync_brain_deinit(&brain2) < 0) { - ctx->ctx.exit_code = EX_TEMPFAIL; - return -1; - } - return 0; + return dsync_brain_deinit(&brain2, mail_error_r); } static void cmd_dsync_wait_remote(struct dsync_cmd_context *ctx, @@ -534,6 +532,7 @@ struct mail_namespace *ns; const char *const *strp; enum dsync_brain_flags brain_flags; + enum mail_error mail_error = 0, mail_error2; bool remote_errors_logged = FALSE; bool changes_during_sync = FALSE; int status = 0, ret = 0; @@ -605,7 +604,7 @@ if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) { if (cmd_dsync_run_local(ctx, user, brain, ibc2, - &changes_during_sync) < 0) + &changes_during_sync, &mail_error) < 0) ret = -1; } else { cmd_dsync_run_remote(user); @@ -626,9 +625,15 @@ } ctx->ctx.exit_code = 2; } - if (dsync_brain_deinit(&brain) < 0) { - ctx->ctx.exit_code = EX_TEMPFAIL; + if (dsync_brain_deinit(&brain, &mail_error2) < 0) ret = -1; + if (ret < 0) { + /* tempfail is the default error. prefer to use a non-tempfail + if that exists. */ + if (mail_error2 != 0 && + (mail_error == 0 || mail_error == MAIL_ERROR_TEMP)) + mail_error = mail_error2; + doveadm_mail_failed_error(&ctx->ctx, mail_error); } dsync_ibc_deinit(&ibc); if (ibc2 != NULL) @@ -1039,6 +1044,7 @@ string_t *temp_prefix, *state_str = NULL; enum dsync_brain_sync_type sync_type; const char *name, *process_title_prefix = ""; + enum mail_error mail_error; if (_ctx->conn != NULL) { /* doveadm-server connection. start with a success reply. @@ -1078,8 +1084,8 @@ } sync_type = dsync_brain_get_sync_type(brain); - if (dsync_brain_deinit(&brain) < 0) - _ctx->exit_code = EX_TEMPFAIL; + if (dsync_brain_deinit(&brain, &mail_error) < 0) + doveadm_mail_failed_error(_ctx, mail_error); dsync_ibc_deinit(&ibc); if (_ctx->conn != NULL) {
--- a/src/doveadm/dsync/dsync-brain-mailbox-tree-sync.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree-sync.c Thu Mar 19 00:41:19 2015 +0200 @@ -8,7 +8,8 @@ static int sync_create_box(struct dsync_brain *brain, struct mailbox *box, - const guid_128_t mailbox_guid, uint32_t uid_validity) + const guid_128_t mailbox_guid, uint32_t uid_validity, + enum mail_error *error_r) { struct mailbox_metadata metadata; struct mailbox_update update; @@ -25,6 +26,7 @@ if (error != MAIL_ERROR_EXISTS) { i_error("Can't create mailbox %s: %s", mailbox_get_vname(box), errstr); + *error_r = error; return -1; } } @@ -37,7 +39,7 @@ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Can't sync mailbox %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, error_r)); return -1; } @@ -50,7 +52,7 @@ if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { i_error("Can't get mailbox GUID %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, error_r)); return -1; } @@ -69,7 +71,7 @@ if (mailbox_update(box, &update) < 0) { i_error("Can't update mailbox GUID %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, error_r)); return -1; } /* verify that the update worked */ @@ -77,13 +79,14 @@ &metadata) < 0) { i_error("Can't get mailbox GUID %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, error_r)); return -1; } if (memcmp(mailbox_guid, metadata.guid, sizeof(metadata.guid)) != 0) { i_error("Backend didn't update mailbox %s GUID", mailbox_get_vname(box)); + *error_r = MAIL_ERROR_TEMP; return -1; } } else if (ret < 0) { @@ -100,7 +103,8 @@ } int dsync_brain_mailbox_tree_sync_change(struct dsync_brain *brain, - const struct dsync_mailbox_tree_sync_change *change) + const struct dsync_mailbox_tree_sync_change *change, + enum mail_error *error_r) { struct mailbox *box = NULL, *destbox; const char *errstr, *func_name = NULL, *storage_name; @@ -116,7 +120,7 @@ case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_BOX: /* make sure we're deleting the correct mailbox */ ret = dsync_brain_mailbox_alloc(brain, change->mailbox_guid, - &box, &errstr); + &box, &errstr, error_r); if (ret < 0) { i_error("Mailbox sync: Couldn't allocate mailbox GUID %s: %s", guid_128_to_string(change->mailbox_guid), errstr); @@ -130,7 +134,7 @@ guid_128_to_string(change->mailbox_guid), errstr); } brain->changes_during_sync = TRUE; - return ret; + return 0; } break; case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_DIR: @@ -153,6 +157,7 @@ } else { i_error("Mailbox sync: mailbox_list_delete_dir failed: %s", errstr); + *error_r = error; return -1; } default: @@ -162,7 +167,7 @@ switch (change->type) { case DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_BOX: ret = sync_create_box(brain, box, change->mailbox_guid, - change->uid_validity); + change->uid_validity, error_r); mailbox_free(&box); return ret; case DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_DIR: @@ -218,6 +223,7 @@ } else { i_error("Mailbox %s sync: %s failed: %s", mailbox_get_vname(box), func_name, errstr); + *error_r = error; } } mailbox_free(&box);
--- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c Thu Mar 19 00:41:19 2015 +0200 @@ -58,8 +58,11 @@ if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, ns, brain->sync_box, brain->sync_box_guid, - brain->exclude_mailboxes) < 0) + brain->exclude_mailboxes, + &brain->mail_error) < 0) { brain->failed = TRUE; + break; + } } brain->local_tree_iter = @@ -300,8 +303,11 @@ brain->remote_mailbox_tree, sync_type, sync_flags); while ((change = dsync_mailbox_trees_sync_next(ctx)) != NULL) { - if (dsync_brain_mailbox_tree_sync_change(brain, change) < 0) + if (dsync_brain_mailbox_tree_sync_change(brain, change, + &brain->mail_error) < 0) { brain->failed = TRUE; + break; + } } dsync_mailbox_trees_sync_deinit(&ctx); }
--- a/src/doveadm/dsync/dsync-brain-mailbox.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain-mailbox.c Thu Mar 19 00:41:19 2015 +0200 @@ -16,12 +16,11 @@ static int ns_mailbox_try_alloc(struct dsync_brain *brain, struct mail_namespace *ns, const guid_128_t guid, struct mailbox **box_r, - const char **error_r) + const char **errstr_r, enum mail_error *error_r) { enum mailbox_flags flags = 0; struct mailbox *box; enum mailbox_existence existence; - enum mail_error err; int ret; if (brain->backup_send) { @@ -32,13 +31,13 @@ box = mailbox_alloc_guid(ns->list, guid, flags); ret = mailbox_exists(box, FALSE, &existence); if (ret < 0) { - *error_r = mailbox_get_last_error(box, &err); + *errstr_r = mailbox_get_last_error(box, error_r); mailbox_free(&box); return -1; } if (existence != MAILBOX_EXISTENCE_SELECT) { mailbox_free(&box); - *error_r = existence == MAILBOX_EXISTENCE_NONE ? + *errstr_r = existence == MAILBOX_EXISTENCE_NONE ? "Mailbox was already deleted" : "Mailbox is no longer selectable"; return 0; @@ -48,7 +47,8 @@ } int dsync_brain_mailbox_alloc(struct dsync_brain *brain, const guid_128_t guid, - struct mailbox **box_r, const char **error_r) + struct mailbox **box_r, const char **errstr_r, + enum mail_error *error_r) { struct mail_namespace *ns; int ret; @@ -58,11 +58,9 @@ for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) { if (!dsync_brain_want_namespace(brain, ns)) continue; - if ((ret = ns_mailbox_try_alloc(brain, ns, guid, box_r, error_r)) != 0) { - if (ret < 0) - brain->failed = TRUE; + if ((ret = ns_mailbox_try_alloc(brain, ns, guid, box_r, + errstr_r, error_r)) != 0) return ret; - } } return 0; } @@ -329,6 +327,8 @@ void dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain) { + enum mail_error error; + i_assert(brain->box != NULL); if (brain->require_full_resync) { @@ -337,11 +337,13 @@ } array_append(&brain->remote_mailbox_states, &brain->mailbox_state, 1); if (brain->box_exporter != NULL) { - const char *error; + const char *errstr; i_assert(brain->failed || brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_CHANGED); - (void)dsync_mailbox_export_deinit(&brain->box_exporter, &error); + if (dsync_mailbox_export_deinit(&brain->box_exporter, + &errstr, &error) < 0) + i_error("Mailbox export failed: %s", errstr); } if (brain->box_importer != NULL) { uint32_t last_common_uid, last_messages_count; @@ -355,7 +357,8 @@ &last_common_modseq, &last_common_pvt_modseq, &last_messages_count, - &changes_during_sync); + &changes_during_sync, + &brain->mail_error); } if (brain->log_scan != NULL) dsync_transaction_log_scan_deinit(&brain->log_scan); @@ -364,7 +367,8 @@ brain->state = brain->pre_box_state; } -static int dsync_box_get(struct mailbox *box, struct dsync_mailbox *dsync_box_r) +static int dsync_box_get(struct mailbox *box, struct dsync_mailbox *dsync_box_r, + enum mail_error *error_r) { const enum mailbox_status_items status_items = STATUS_UIDVALIDITY | STATUS_UIDNEXT | STATUS_MESSAGES | @@ -391,6 +395,7 @@ } i_error("Failed to access mailbox %s: %s", mailbox_get_vname(box), errstr); + *error_r = error; return -1; } @@ -441,6 +446,7 @@ struct mailbox *box; struct dsync_mailbox_node *node; const char *vname = NULL; + enum mail_error error; bool synced = FALSE; int ret; @@ -464,9 +470,11 @@ } box = mailbox_alloc(node->ns->list, vname, flags); for (;;) { - if ((ret = dsync_box_get(box, &dsync_box)) <= 0) { - if (ret < 0) + if ((ret = dsync_box_get(box, &dsync_box, &error)) <= 0) { + if (ret < 0) { + brain->mail_error = error; brain->failed = TRUE; + } mailbox_free(&box); return ret; } @@ -498,7 +506,7 @@ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Can't sync mailbox %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &brain->mail_error)); brain->failed = TRUE; mailbox_free(&box); return -1; @@ -682,7 +690,7 @@ if (mailbox_update(box, &update) < 0) { i_error("Couldn't update mailbox %s metadata: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &brain->mail_error)); brain->failed = TRUE; } return ret; @@ -712,7 +720,8 @@ const struct dsync_mailbox *dsync_box; struct dsync_mailbox local_dsync_box; struct mailbox *box; - const char *error; + const char *errstr; + enum mail_error error; int ret; bool resync; @@ -727,10 +736,11 @@ } if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid, - &box, &error) < 0) { + &box, &errstr, &error) < 0) { i_error("Couldn't allocate mailbox GUID %s: %s", - guid_128_to_string(dsync_box->mailbox_guid), error); - i_assert(brain->failed); + guid_128_to_string(dsync_box->mailbox_guid), errstr); + brain->mail_error = error; + brain->failed = TRUE; return TRUE; } if (box == NULL) { @@ -759,15 +769,16 @@ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Can't sync mailbox %s: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &brain->mail_error)); mailbox_free(&box); brain->failed = TRUE; return TRUE; } - if ((ret = dsync_box_get(box, &local_dsync_box)) <= 0) { + if ((ret = dsync_box_get(box, &local_dsync_box, &error)) <= 0) { mailbox_free(&box); if (ret < 0) { + brain->mail_error = error; brain->failed = TRUE; return TRUE; }
--- a/src/doveadm/dsync/dsync-brain-mails.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain-mails.c Thu Mar 19 00:41:19 2015 +0200 @@ -183,7 +183,8 @@ static void dsync_brain_sync_half_finished(struct dsync_brain *brain) { struct dsync_mailbox_state state; - const char *error; + const char *errstr; + enum mail_error error; if (brain->box_recv_state < DSYNC_BOX_STATE_RECV_LAST_COMMON || brain->box_send_state < DSYNC_BOX_STATE_RECV_LAST_COMMON) @@ -192,9 +193,10 @@ /* finished with this mailbox */ if (brain->box_exporter != NULL) { if (dsync_mailbox_export_deinit(&brain->box_exporter, - &error) < 0) { + &errstr, &error) < 0) { i_error("Exporting mailbox %s failed: %s", - mailbox_get_vname(brain->box), error); + mailbox_get_vname(brain->box), errstr); + brain->mail_error = error; brain->failed = TRUE; return; } @@ -219,7 +221,8 @@ &state.last_common_modseq, &state.last_common_pvt_modseq, &state.last_messages_count, - &state.changes_during_sync) < 0) { + &state.changes_during_sync, + &brain->mail_error) < 0) { brain->failed = TRUE; return; }
--- a/src/doveadm/dsync/dsync-brain-private.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain-private.h Thu Mar 19 00:41:19 2015 +0200 @@ -95,6 +95,8 @@ /* new states for synced mailboxes */ ARRAY_TYPE(dsync_mailbox_state) remote_mailbox_states; + enum mail_error mail_error; + unsigned int master_brain:1; unsigned int mail_requests:1; unsigned int backup_send:1; @@ -119,11 +121,13 @@ bool dsync_brain_recv_mailbox_tree(struct dsync_brain *brain); bool dsync_brain_recv_mailbox_tree_deletes(struct dsync_brain *brain); int dsync_brain_mailbox_tree_sync_change(struct dsync_brain *brain, - const struct dsync_mailbox_tree_sync_change *change); + const struct dsync_mailbox_tree_sync_change *change, + enum mail_error *error_r); void dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain); int dsync_brain_mailbox_alloc(struct dsync_brain *brain, const guid_128_t guid, - struct mailbox **box_r, const char **error_r); + struct mailbox **box_r, const char **errstr_r, + enum mail_error *error_r); bool dsync_brain_mailbox_update_pre(struct dsync_brain *brain, struct mailbox *box, const struct dsync_mailbox *local_box,
--- a/src/doveadm/dsync/dsync-brain.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain.c Thu Mar 19 00:41:19 2015 +0200 @@ -288,7 +288,7 @@ } } -int dsync_brain_deinit(struct dsync_brain **_brain) +int dsync_brain_deinit(struct dsync_brain **_brain, enum mail_error *error_r) { struct dsync_brain *brain = *_brain; int ret; @@ -338,6 +338,9 @@ ret = brain->failed ? -1 : 0; mail_user_unref(&brain->user); + + *error_r = !brain->failed ? 0 : + (brain->mail_error == 0 ? MAIL_ERROR_TEMP : brain->mail_error); pool_unref(&brain->pool); return ret; } @@ -558,18 +561,25 @@ static bool dsync_brain_finish(struct dsync_brain *brain) { const char *error; + enum mail_error mail_error; + enum dsync_ibc_recv_ret ret; if (!brain->master_brain) { dsync_ibc_send_finish(brain->ibc, - brain->failed ? "dsync failed" : NULL); + brain->failed ? "dsync failed" : NULL, + brain->mail_error); brain->state = DSYNC_STATE_DONE; return TRUE; } - if (dsync_ibc_recv_finish(brain->ibc, &error) == DSYNC_IBC_RECV_RET_TRYAGAIN) + ret = dsync_ibc_recv_finish(brain->ibc, &error, &mail_error); + if (ret == DSYNC_IBC_RECV_RET_TRYAGAIN) return FALSE; if (error != NULL) { i_error("Remote dsync failed: %s", error); brain->failed = TRUE; + if (mail_error != 0 && + (brain->mail_error == 0 || brain->mail_error == MAIL_ERROR_TEMP)) + brain->mail_error = mail_error; } brain->state = DSYNC_STATE_DONE; return TRUE;
--- a/src/doveadm/dsync/dsync-brain.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-brain.h Thu Mar 19 00:41:19 2015 +0200 @@ -2,6 +2,7 @@ #define DSYNC_BRAIN_H #include "guid.h" +#include "mail-error.h" struct mail_namespace; struct mail_user; @@ -80,7 +81,7 @@ dsync_brain_slave_init(struct mail_user *user, struct dsync_ibc *ibc, bool local, const char *process_title_prefix); /* Returns 0 if everything was successful, -1 if syncing failed in some way */ -int dsync_brain_deinit(struct dsync_brain **brain); +int dsync_brain_deinit(struct dsync_brain **brain, enum mail_error *error_r); /* Returns TRUE if brain needs to run more, FALSE if it's finished. changed_r is TRUE if anything happened during this run. */
--- a/src/doveadm/dsync/dsync-ibc-pipe.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-ibc-pipe.c Thu Mar 19 00:41:19 2015 +0200 @@ -42,7 +42,10 @@ unsigned int count; char hierarchy_sep; } mailbox_delete; - const char *finish_error; + struct { + const char *error; + enum mail_error mail_error; + } finish; } u; }; @@ -487,17 +490,20 @@ } static void -dsync_ibc_pipe_send_finish(struct dsync_ibc *ibc, const char *error) +dsync_ibc_pipe_send_finish(struct dsync_ibc *ibc, const char *error, + enum mail_error mail_error) { struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc; struct item *item; item = dsync_ibc_pipe_push_item(pipe->remote, ITEM_FINISH); - item->u.finish_error = p_strdup(item->pool, error); + item->u.finish.error = p_strdup(item->pool, error); + item->u.finish.mail_error = mail_error; } static enum dsync_ibc_recv_ret -dsync_ibc_pipe_recv_finish(struct dsync_ibc *ibc, const char **error_r) +dsync_ibc_pipe_recv_finish(struct dsync_ibc *ibc, const char **error_r, + enum mail_error *mail_error_r) { struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc; struct item *item; @@ -506,7 +512,8 @@ if (item == NULL) return DSYNC_IBC_RECV_RET_TRYAGAIN; - *error_r = item->u.finish_error; + *error_r = item->u.finish.error; + *mail_error_r = item->u.finish.mail_error; return DSYNC_IBC_RECV_RET_OK; }
--- a/src/doveadm/dsync/dsync-ibc-private.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-ibc-private.h Thu Mar 19 00:41:19 2015 +0200 @@ -68,9 +68,11 @@ (*recv_mail)(struct dsync_ibc *ibc, struct dsync_mail **mail_r); - void (*send_finish)(struct dsync_ibc *ibc, const char *error); + void (*send_finish)(struct dsync_ibc *ibc, const char *error, + enum mail_error mail_error); enum dsync_ibc_recv_ret - (*recv_finish)(struct dsync_ibc *ibc, const char **error_r); + (*recv_finish)(struct dsync_ibc *ibc, const char **error_r, + enum mail_error *mail_error_r); void (*close_mail_streams)(struct dsync_ibc *ibc); bool (*is_send_queue_full)(struct dsync_ibc *ibc);
--- a/src/doveadm/dsync/dsync-ibc-stream.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-ibc-stream.c Thu Mar 19 00:41:19 2015 +0200 @@ -126,7 +126,7 @@ }, { .name = "finish", .chr = 'F', - .optional_keys = "error" + .optional_keys = "error mail_error" }, { .name = "mailbox_cache_field", .chr = 'c', @@ -1827,7 +1827,8 @@ } static void -dsync_ibc_stream_send_finish(struct dsync_ibc *_ibc, const char *error) +dsync_ibc_stream_send_finish(struct dsync_ibc *_ibc, const char *error, + enum mail_error mail_error) { struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc; struct dsync_serializer_encoder *encoder; @@ -1837,19 +1838,27 @@ encoder = dsync_serializer_encode_begin(ibc->serializers[ITEM_FINISH]); if (error != NULL) dsync_serializer_encode_add(encoder, "error", error); + if (mail_error != 0) { + dsync_serializer_encode_add(encoder, "mail_error", + dec2str(mail_error)); + } dsync_serializer_encode_finish(&encoder, str); dsync_ibc_stream_send_string(ibc, str); } static enum dsync_ibc_recv_ret -dsync_ibc_stream_recv_finish(struct dsync_ibc *_ibc, const char **error_r) +dsync_ibc_stream_recv_finish(struct dsync_ibc *_ibc, const char **error_r, + enum mail_error *mail_error_r) { struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc; struct dsync_deserializer_decoder *decoder; const char *value; enum dsync_ibc_recv_ret ret; + int i; *error_r = NULL; + *mail_error_r = 0; + p_clear(ibc->ret_pool); if (ibc->minor_version < DSYNC_PROTOCOL_MINOR_HAVE_FINISH) @@ -1861,6 +1870,12 @@ if (dsync_deserializer_decode_try(decoder, "error", &value)) *error_r = p_strdup(ibc->ret_pool, value); + if (dsync_deserializer_decode_try(decoder, "mail_error", &value) && + str_to_int(value, &i) < 0) { + dsync_ibc_input_error(ibc, decoder, "Invalid mail_error"); + return DSYNC_IBC_RECV_RET_TRYAGAIN; + } + *mail_error_r = i; return DSYNC_IBC_RECV_RET_OK; }
--- a/src/doveadm/dsync/dsync-ibc.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-ibc.c Thu Mar 19 00:41:19 2015 +0200 @@ -195,15 +195,17 @@ return ibc->v.recv_mail(ibc, mail_r); } -void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error) +void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error, + enum mail_error mail_error) { - ibc->v.send_finish(ibc, error); + ibc->v.send_finish(ibc, error, mail_error); } enum dsync_ibc_recv_ret -dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r) +dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r, + enum mail_error *mail_error_r) { - return ibc->v.recv_finish(ibc, error_r); + return ibc->v.recv_finish(ibc, error_r, mail_error_r); } void dsync_ibc_close_mail_streams(struct dsync_ibc *ibc)
--- a/src/doveadm/dsync/dsync-ibc.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-ibc.h Thu Mar 19 00:41:19 2015 +0200 @@ -5,6 +5,7 @@ #include "ioloop.h" #include "guid.h" +#include "mail-error.h" #include "dsync-brain.h" struct dsync_mailbox; @@ -144,9 +145,11 @@ enum dsync_ibc_recv_ret dsync_ibc_recv_mail(struct dsync_ibc *ibc, struct dsync_mail **mail_r); -void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error); +void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error, + enum mail_error mail_error); enum dsync_ibc_recv_ret -dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r); +dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r, + enum mail_error *mail_error_r); /* Close any mail input streams that are kept open. This needs to be called before the mail is attempted to be freed (usually on error conditions). */
--- a/src/doveadm/dsync/dsync-mailbox-export.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-export.c Thu Mar 19 00:41:19 2015 +0200 @@ -54,6 +54,8 @@ struct dsync_mail dsync_mail; const char *error; + enum mail_error mail_error; + unsigned int body_search_initialized:1; unsigned int auto_export_mails:1; unsigned int mails_have_guids:1; @@ -72,6 +74,7 @@ if (error == MAIL_ERROR_EXPUNGED) return 0; + exporter->mail_error = error; exporter->error = p_strdup_printf(exporter->pool, "Can't lookup %s for UID=%u: %s", field, mail->uid, errstr); @@ -163,6 +166,7 @@ return dsync_mail_error(exporter, mail, "hdr-stream"); return 1; } else if (**guid_r == '\0') { + exporter->mail_error = MAIL_ERROR_TEMP; exporter->error = "Backend doesn't support GUIDs, " "sync with header hashes instead"; return -1; @@ -403,7 +407,8 @@ exporter->error == NULL) { exporter->error = p_strdup_printf(exporter->pool, "Mail search failed: %s", - mailbox_get_last_error(exporter->box, NULL)); + mailbox_get_last_error(exporter->box, + &exporter->mail_error)); } } @@ -534,7 +539,8 @@ attr->key, &value) < 0) { exporter->error = p_strdup_printf(exporter->pool, "Mailbox attribute %s lookup failed: %s", attr->key, - mailbox_get_last_error(exporter->box, NULL)); + mailbox_get_last_error(exporter->box, + &exporter->mail_error)); break; } if ((value.flags & MAIL_ATTRIBUTE_VALUE_FLAG_READONLY) != 0) { @@ -586,7 +592,8 @@ &value) < 0) { exporter->error = p_strdup_printf(exporter->pool, "Mailbox attribute %s lookup failed: %s", key, - mailbox_get_last_error(exporter->box, NULL)); + mailbox_get_last_error(exporter->box, + &exporter->mail_error)); return -1; } if ((value.flags & MAIL_ATTRIBUTE_VALUE_FLAG_READONLY) != 0) { @@ -624,7 +631,8 @@ if (mailbox_attribute_iter_deinit(&exporter->attr_iter) < 0) { exporter->error = p_strdup_printf(exporter->pool, "Mailbox attribute iteration failed: %s", - mailbox_get_last_error(exporter->box, NULL)); + mailbox_get_last_error(exporter->box, + &exporter->mail_error)); return -1; } if (exporter->attr_type == MAIL_ATTRIBUTE_TYPE_PRIVATE) { @@ -762,7 +770,8 @@ exporter->error == NULL) { exporter->error = p_strdup_printf(exporter->pool, "Mail search failed: %s", - mailbox_get_last_error(exporter->box, NULL)); + mailbox_get_last_error(exporter->box, + &exporter->mail_error)); } } @@ -784,6 +793,7 @@ } else if (exporter->dsync_mail.uid != 0) { /* mail requested by UID */ } else { + exporter->mail_error = MAIL_ERROR_TEMP; exporter->error = p_strdup_printf(exporter->pool, "GUID unexpectedly changed for UID=%u GUID=%s", mail->uid, exporter->dsync_mail.guid); @@ -816,6 +826,7 @@ instances = hash_table_lookup(exporter->export_guids, request->guid); if (instances == NULL) { + exporter->mail_error = MAIL_ERROR_TEMP; exporter->error = p_strdup_printf(exporter->pool, "Remote requested unexpected GUID %s", request->guid); return; @@ -878,7 +889,7 @@ } int dsync_mailbox_export_deinit(struct dsync_mailbox_exporter **_exporter, - const char **error_r) + const char **errstr_r, enum mail_error *error_r) { struct dsync_mailbox_exporter *exporter = *_exporter; @@ -894,9 +905,12 @@ hash_table_destroy(&exporter->export_guids); hash_table_destroy(&exporter->changes); - *error_r = t_strdup(exporter->error); + i_assert((exporter->error != NULL) == (exporter->mail_error != 0)); + + *error_r = exporter->mail_error; + *errstr_r = t_strdup(exporter->error); pool_unref(&exporter->pool); - return *error_r != NULL ? -1 : 0; + return *errstr_r != NULL ? -1 : 0; } const char *dsync_mailbox_export_get_proctitle(struct dsync_mailbox_exporter *exporter)
--- a/src/doveadm/dsync/dsync-mailbox-export.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-export.h Thu Mar 19 00:41:19 2015 +0200 @@ -23,7 +23,7 @@ const struct dsync_mail * dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter); int dsync_mailbox_export_deinit(struct dsync_mailbox_exporter **exporter, - const char **error_r); + const char **errstr_r, enum mail_error *error_r); const char *dsync_mailbox_export_get_proctitle(struct dsync_mailbox_exporter *exporter);
--- a/src/doveadm/dsync/dsync-mailbox-import.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-import.c Thu Mar 19 00:41:19 2015 +0200 @@ -103,6 +103,8 @@ uint64_t local_initial_highestmodseq, local_initial_highestpvtmodseq; unsigned int import_pos, import_count; + enum mail_error mail_error; + unsigned int failed:1; unsigned int debug:1; unsigned int stateful_import:1; @@ -277,7 +279,7 @@ if (mailbox_attribute_get_stream(importer->trans, type, key, &value) < 0) { i_error("Mailbox %s: Failed to get attribute %s: %s", mailbox_get_vname(importer->box), key, - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, &importer->mail_error)); importer->failed = TRUE; return -1; } @@ -448,6 +450,7 @@ they are the same, fallback to just picking one based on the value. */ if (dsync_attributes_cmp(attr, local_attr, &cmp) < 0) { + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; return -1; } @@ -485,7 +488,7 @@ attr->key, &value) < 0) { i_error("Mailbox %s: Failed to set attribute %s: %s", mailbox_get_vname(importer->box), attr->key, - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, &importer->mail_error)); /* the attributes aren't vital, don't fail everything just because of them. */ } @@ -518,6 +521,7 @@ i_error("Mailbox %s: Can't lookup %s for UID=%u: %s", mailbox_get_vname(mail->box), field, mail->uid, errstr); + importer->mail_error = error; importer->failed = TRUE; } @@ -833,6 +837,7 @@ dsync_import_unexpected_state(importer, t_strdup_printf( "Unexpected GUID mismatch for UID=%u: %s != %s", change->uid, guid, cmp_guid)); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; return FALSE; } @@ -852,6 +857,7 @@ dsync_import_unexpected_state(importer, t_strdup_printf( "Unexpected GUID mismatch (2) for UID=%u: %s != %s", change->uid, importer->cur_guid, cmp_guid)); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; return FALSE; } @@ -1466,6 +1472,7 @@ i_error("Mailbox %s: GUIDs not supported, " "sync with header hashes instead", mailbox_get_vname(importer->box)); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; *result_r = "Error, invalid parameters"; return -1; @@ -1543,6 +1550,7 @@ mailbox_get_vname(importer->box), change->uid, change->guid); importer->delete_mailbox = TRUE; + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; } @@ -1754,6 +1762,8 @@ if (!mail_set_uid(mail, uid)) return 0; + /* NOTE: Errors are logged, but they don't cause the entire import + to fail. */ if (dsync_mail_fill(mail, TRUE, dmail_r, &error_field) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_EXPUNGED) @@ -2086,7 +2096,8 @@ if (mailbox_search_deinit(&importer->search_ctx) < 0) { i_error("Mailbox %s: Search failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; } } @@ -2267,7 +2278,8 @@ i_error("Mailbox %s: Failed to read mail %s uid=%u: %s", mailbox_get_vname(importer->box), error_field, mail->uid, - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; mailbox_save_cancel(&save_ctx); return TRUE; @@ -2288,7 +2300,8 @@ if (mailbox_save_begin(&save_ctx, input) < 0) { i_error("Mailbox %s: Saving failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; return TRUE; } @@ -2306,11 +2319,13 @@ mailbox_get_vname(importer->box), i_stream_get_error(input)); mailbox_save_cancel(&save_ctx); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; } else if (save_failed) { i_error("Mailbox %s: Saving failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); mailbox_save_cancel(&save_ctx); importer->failed = TRUE; } else { @@ -2318,7 +2333,8 @@ if (mailbox_save_finish(&save_ctx) < 0) { i_error("Mailbox %s: Saving failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; } else { dsync_mailbox_import_saved_uid(importer, @@ -2434,7 +2450,7 @@ if (mailbox_move(&save_ctx, mail) < 0) { i_error("Mailbox %s: Couldn't move mail within mailbox: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &importer->mail_error)); ret = -1; } else if (ret > 0) { ret = 0; @@ -2444,14 +2460,14 @@ if (mailbox_search_deinit(&search_ctx) < 0) { i_error("Mailbox %s: mail search failed: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &importer->mail_error)); ret = -1; } if (mailbox_transaction_commit(&trans) < 0) { i_error("Mailbox %s: UID reassign commit failed: %s", mailbox_get_vname(box), - mailbox_get_last_error(box, NULL)); + mailbox_get_last_error(box, &importer->mail_error)); ret = -1; } if (ret == 0) { @@ -2534,7 +2550,7 @@ &changes) < 0) { i_error("Mailbox %s: Save commit failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, &importer->mail_error)); /* removed wanted_uids that weren't actually saved */ array_delete(&importer->wanted_uids, array_count(&importer->saved_uids), @@ -2558,7 +2574,8 @@ if (mailbox_transaction_commit(&importer->trans) < 0) { i_error("Mailbox %s: Commit failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); ret = -1; } } @@ -2597,7 +2614,8 @@ if (mailbox_update(importer->box, &update) < 0) { i_error("Mailbox %s: Update failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); ret = -1; } } @@ -2606,7 +2624,8 @@ if (mailbox_sync(importer->box, 0) < 0) { i_error("Mailbox %s: Sync failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); ret = -1; } if (ret == 0) { @@ -2634,6 +2653,7 @@ i_error("Mailbox %s: Remote didn't send mail GUID=%s (UID=%u)", mailbox_get_vname(importer->box), mail->guid, mail->remote_uid); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; } } @@ -2656,6 +2676,7 @@ i_error("Mailbox %s: Remote didn't send mail UID=%u", mailbox_get_vname(importer->box), mail->remote_uid); + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; } } @@ -2668,7 +2689,8 @@ uint64_t *last_common_modseq_r, uint64_t *last_common_pvt_modseq_r, uint32_t *last_messages_count_r, - bool *changes_during_sync_r) + bool *changes_during_sync_r, + enum mail_error *error_r) { struct dsync_mailbox_importer *importer = *_importer; struct mailbox_status status; @@ -2677,8 +2699,10 @@ *_importer = NULL; *changes_during_sync_r = FALSE; - if (!success) + if (!success && !importer->failed) { + importer->mail_error = MAIL_ERROR_TEMP; importer->failed = TRUE; + } if (!importer->new_uids_assigned && !importer->failed) dsync_mailbox_import_assign_new_uids(importer); @@ -2692,7 +2716,8 @@ if (mailbox_search_deinit(&importer->search_ctx) < 0) { i_error("Mailbox %s: Search failed: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; } } @@ -2730,7 +2755,8 @@ if (mailbox_delete(importer->box) < 0) { i_error("Couldn't delete mailbox %s: %s", mailbox_get_vname(importer->box), - mailbox_get_last_error(importer->box, NULL)); + mailbox_get_last_error(importer->box, + &importer->mail_error)); importer->failed = TRUE; } *last_messages_count_r = 0; @@ -2739,7 +2765,9 @@ *last_messages_count_r = status.messages; } + i_assert(importer->failed == (importer->mail_error != 0)); ret = importer->failed ? -1 : 0; + *error_r = importer->mail_error; pool_unref(&importer->pool); return ret; }
--- a/src/doveadm/dsync/dsync-mailbox-import.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-import.h Thu Mar 19 00:41:19 2015 +0200 @@ -1,6 +1,8 @@ #ifndef DSYNC_MAILBOX_IMPORT_H #define DSYNC_MAILBOX_IMPORT_H +#include "mail-error.h" + enum dsync_mailbox_import_flags { DSYNC_MAILBOX_IMPORT_FLAG_MASTER_BRAIN = 0x01, DSYNC_MAILBOX_IMPORT_FLAG_WANT_MAIL_REQUESTS = 0x02, @@ -44,7 +46,8 @@ uint64_t *last_common_modseq_r, uint64_t *last_common_pvt_modseq_r, uint32_t *last_messages_count_r, - bool *changes_during_sync_r); + bool *changes_during_sync_r, + enum mail_error *error_r); const char *dsync_mailbox_import_get_proctitle(struct dsync_mailbox_importer *importer);
--- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c Thu Mar 19 00:41:19 2015 +0200 @@ -37,10 +37,13 @@ static int dsync_mailbox_tree_add_exists_node(struct dsync_mailbox_tree *tree, const struct mailbox_info *info, - struct dsync_mailbox_node **node_r) + struct dsync_mailbox_node **node_r, + enum mail_error *error_r) { - if (dsync_mailbox_tree_add_node(tree, info, node_r) < 0) + if (dsync_mailbox_tree_add_node(tree, info, node_r) < 0) { + *error_r = MAIL_ERROR_TEMP; return -1; + } (*node_r)->existence = DSYNC_MAILBOX_NODE_EXISTS; return 0; } @@ -71,7 +74,8 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, const struct mailbox_info *info, - const guid_128_t box_guid) + const guid_128_t box_guid, + enum mail_error *error_r) { struct dsync_mailbox_node *node; struct mailbox *box; @@ -85,7 +89,7 @@ return 0; if ((info->flags & MAILBOX_NOSELECT) != 0) { return !guid_128_is_empty(box_guid) ? 0 : - dsync_mailbox_tree_add_exists_node(tree, info, &node); + dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r); } /* get GUID and UIDVALIDITY for selectable mailbox */ @@ -102,6 +106,7 @@ default: i_error("Failed to access mailbox %s: %s", info->vname, errstr); + *error_r = error; ret = -1; } mailbox_free(&box); @@ -114,7 +119,7 @@ /* unwanted mailbox */ return 0; } - if (dsync_mailbox_tree_add_exists_node(tree, info, &node) < 0) + if (dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r) < 0) return -1; memcpy(node->mailbox_guid, metadata.guid, sizeof(node->mailbox_guid)); @@ -313,7 +318,8 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, struct mail_namespace *ns, const char *box_name, const guid_128_t box_guid, - const char *const *exclude_mailboxes) + const char *const *exclude_mailboxes, + enum mail_error *error_r) { const enum mailbox_list_iter_flags list_flags = /* FIXME: we'll skip symlinks, because we can't handle them @@ -348,25 +354,29 @@ while ((info = mailbox_list_iter_next(iter)) != NULL) T_BEGIN { if (dsync_mailbox_info_is_wanted(info, box_name, exclude_mailboxes)) { - if (dsync_mailbox_tree_add(tree, info, box_guid) < 0) + if (dsync_mailbox_tree_add(tree, info, box_guid, error_r) < 0) ret = -1; } } T_END; if (mailbox_list_iter_deinit(&iter) < 0) { - i_error("Mailbox listing for namespace '%s' failed", ns->prefix); + i_error("Mailbox listing for namespace '%s' failed: %s", + ns->prefix, mailbox_list_get_last_error(ns->list, error_r)); ret = -1; } /* add subscriptions */ iter = mailbox_list_iter_init(ns->list, list_pattern, subs_list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) { - if (dsync_mailbox_tree_add_node(tree, info, &node) < 0) + if (dsync_mailbox_tree_add_node(tree, info, &node) == 0) + node->subscribed = TRUE; + else { + *error_r = MAIL_ERROR_TEMP; ret = -1; - else - node->subscribed = TRUE; + } } if (mailbox_list_iter_deinit(&iter) < 0) { - i_error("Mailbox listing for namespace '%s' failed", ns->prefix); + i_error("Mailbox listing for namespace '%s' failed: %s", + ns->prefix, mailbox_list_get_last_error(ns->list, error_r)); ret = -1; } if (ret < 0)
--- a/src/doveadm/dsync/dsync-mailbox-tree.h Thu Mar 19 00:38:01 2015 +0200 +++ b/src/doveadm/dsync/dsync-mailbox-tree.h Thu Mar 19 00:41:19 2015 +0200 @@ -2,6 +2,7 @@ #define DSYNC_MAILBOX_TREE_H #include "guid.h" +#include "mail-error.h" struct mail_namespace; struct dsync_brain; @@ -141,7 +142,8 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, struct mail_namespace *ns, const char *box_name, const guid_128_t box_guid, - const char *const *exclude_mailboxes); + const char *const *exclude_mailboxes, + enum mail_error *error_r); /* Return all known deleted mailboxes and directories. */ const struct dsync_mailbox_delete *