diff --git a/src/auth/userdb-dict.c b/src/auth/userdb-dict.c index 6ccd198bdc..90ddb400a4 100644 --- a/src/auth/userdb-dict.c +++ b/src/auth/userdb-dict.c @@ -141,11 +141,15 @@ static int userdb_dict_iterate_deinit(struct userdb_iterate_context *_ctx) { struct dict_userdb_iterate_context *ctx = (struct dict_userdb_iterate_context *)_ctx; + const char *error; int ret = _ctx->failed ? -1 : 0; if (ctx->iter != NULL) { - if (dict_iterate_deinit(&ctx->iter) < 0) + if (dict_iterate_deinit(&ctx->iter, &error) < 0) { + i_error("dict_iterate(%s) failed: %s", + ctx->key_prefix, error); ret = -1; + } } auth_request_unref(&ctx->ctx.auth_request); i_free(ctx); diff --git a/src/dict/dict-commands.c b/src/dict/dict-commands.c index 43e0d93102..712a73e320 100644 --- a/src/dict/dict-commands.c +++ b/src/dict/dict-commands.c @@ -33,8 +33,12 @@ static void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd); static void dict_connection_cmd_free(struct dict_connection_cmd *cmd) { - if (cmd->iter != NULL) - (void)dict_iterate_deinit(&cmd->iter); + const char *error; + + if (cmd->iter != NULL) { + if (dict_iterate_deinit(&cmd->iter, &error) < 0) + i_error("dict_iterate() failed: %s", error); + } i_free(cmd->reply); if (dict_connection_unref(cmd->conn)) @@ -106,7 +110,7 @@ static int cmd_lookup(struct dict_connection_cmd *cmd, const char *line) static int cmd_iterate_flush(struct dict_connection_cmd *cmd) { string_t *str; - const char *key, *value; + const char *key, *value, *error; str = t_str_new(256); o_stream_cork(cmd->conn->output); @@ -138,8 +142,10 @@ static int cmd_iterate_flush(struct dict_connection_cmd *cmd) } str_truncate(str, 0); - if (dict_iterate_deinit(&cmd->iter) < 0) - str_append_c(str, DICT_PROTOCOL_REPLY_FAIL); + if (dict_iterate_deinit(&cmd->iter, &error) < 0) { + i_error("dict_iterate() failed: %s", error); + str_printfa(str, "%c%s", DICT_PROTOCOL_REPLY_FAIL, error); + } str_append_c(str, '\n'); o_stream_uncork(cmd->conn->output); diff --git a/src/doveadm/doveadm-dict.c b/src/doveadm/doveadm-dict.c index e266ce9e21..29310568ac 100644 --- a/src/doveadm/doveadm-dict.c +++ b/src/doveadm/doveadm-dict.c @@ -186,7 +186,7 @@ static void cmd_dict_iter(int argc, char *argv[]) struct dict *dict; struct dict_iterate_context *iter; enum dict_iterate_flags iter_flags = 0; - const char *key, *value; + const char *key, *value, *error; if (cmd_dict_init_full(&argc, &argv, 1, 0, cmd_dict_iter, &iter_flags, &dict) < 0) return; @@ -202,8 +202,8 @@ static void cmd_dict_iter(int argc, char *argv[]) if ((iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) doveadm_print(value); } - if (dict_iterate_deinit(&iter) < 0) { - i_error("dict_iterate_deinit(%s) failed", argv[0]); + if (dict_iterate_deinit(&iter, &error) < 0) { + i_error("dict_iterate_deinit(%s) failed: %s", argv[0], error); doveadm_exit_code = EX_TEMPFAIL; } dict_deinit(&dict); diff --git a/src/lib-dict-extra/dict-fs.c b/src/lib-dict-extra/dict-fs.c index 91a40f92c8..82ea827308 100644 --- a/src/lib-dict-extra/dict-fs.c +++ b/src/lib-dict-extra/dict-fs.c @@ -21,7 +21,7 @@ struct fs_dict_iterate_context { enum dict_iterate_flags flags; pool_t value_pool; struct fs_iter *fs_iter; - bool failed; + char *error; }; static int @@ -153,10 +153,13 @@ static bool fs_dict_iterate(struct dict_iterate_context *ctx, const char *path, *error; int ret; + if (iter->error != NULL) + return FALSE; + *key_r = fs_iter_next(iter->fs_iter); if (*key_r == NULL) { if (fs_iter_deinit(&iter->fs_iter) < 0) { - iter->failed = TRUE; + iter->error = i_strdup(fs_last_error(dict->fs)); return FALSE; } if (iter->paths[++iter->path_idx] == NULL) @@ -173,8 +176,7 @@ static bool fs_dict_iterate(struct dict_iterate_context *ctx, path = t_strconcat(iter->paths[iter->path_idx], *key_r, NULL); if ((ret = fs_dict_lookup(ctx->dict, iter->value_pool, path, value_r, &error)) < 0) { /* I/O error */ - i_error("%s", error); - iter->failed = TRUE; + iter->error = i_strdup(error); return FALSE; } else if (ret == 0) { /* file was just deleted, just skip to next one */ @@ -183,20 +185,24 @@ static bool fs_dict_iterate(struct dict_iterate_context *ctx, return TRUE; } -static int fs_dict_iterate_deinit(struct dict_iterate_context *ctx) +static int fs_dict_iterate_deinit(struct dict_iterate_context *ctx, + const char **error_r) { struct fs_dict_iterate_context *iter = (struct fs_dict_iterate_context *)ctx; + struct fs_dict *dict = (struct fs_dict *)ctx->dict; int ret; if (iter->fs_iter != NULL) { - if (fs_iter_deinit(&iter->fs_iter) < 0) - iter->failed = TRUE; + if (fs_iter_deinit(&iter->fs_iter) < 0 && iter->error == NULL) + iter->error = i_strdup(fs_last_error(dict->fs)); } - ret = iter->failed ? -1 : 0; + ret = iter->error != NULL ? -1 : 0; + *error_r = t_strdup(iter->error); pool_unref(&iter->value_pool); i_free(iter->paths); + i_free(iter->error); i_free(iter); return ret; } diff --git a/src/lib-dict/dict-client.c b/src/lib-dict/dict-client.c index efdf32d1a4..40378c6016 100644 --- a/src/lib-dict/dict-client.c +++ b/src/lib-dict/dict-client.c @@ -55,9 +55,9 @@ struct client_dict { struct client_dict_iterate_context { struct dict_iterate_context ctx; + char *error; pool_t pool; - bool failed; bool finished; }; @@ -655,10 +655,8 @@ client_dict_iterate_init(struct dict *_dict, const char *const *paths, str_append(query, dict_client_escape(paths[i])); } str_append_c(query, '\n'); - if (client_dict_send_query(dict, str_c(query), &error) < 0) { - i_error("%s", error); - ctx->failed = TRUE; - } + if (client_dict_send_query(dict, str_c(query), &error) < 0) + ctx->error = i_strdup(error); return &ctx->ctx; } @@ -671,13 +669,12 @@ static bool client_dict_iterate(struct dict_iterate_context *_ctx, char *line, *key, *value; const char *error; - if (ctx->failed) + if (ctx->error != NULL) return FALSE; /* read next reply */ if (client_dict_read_line(dict, &line, &error) < 0) { - i_error("%s", error); - ctx->failed = TRUE; + ctx->error = i_strdup(error); return FALSE; } @@ -696,7 +693,7 @@ static bool client_dict_iterate(struct dict_iterate_context *_ctx, value = strchr(key, '\t'); break; case DICT_PROTOCOL_REPLY_FAIL: - ctx->failed = TRUE; + ctx->error = i_strdup_printf("dict-server returned failure: %s", line+1); return FALSE; default: key = NULL; @@ -705,8 +702,7 @@ static bool client_dict_iterate(struct dict_iterate_context *_ctx, } if (value == NULL) { /* broken protocol */ - i_error("dict client (%s) sent broken iterate reply: %s", dict->path, line); - ctx->failed = TRUE; + ctx->error = i_strdup_printf("dict client (%s) sent broken iterate reply: %s", dict->path, line); return FALSE; } *value++ = '\0'; @@ -716,17 +712,20 @@ static bool client_dict_iterate(struct dict_iterate_context *_ctx, return TRUE; } -static int client_dict_iterate_deinit(struct dict_iterate_context *_ctx) +static int client_dict_iterate_deinit(struct dict_iterate_context *_ctx, + const char **error_r) { struct client_dict *dict = (struct client_dict *)_ctx->dict; struct client_dict_iterate_context *ctx = (struct client_dict_iterate_context *)_ctx; - int ret = ctx->failed ? -1 : 0; + int ret = ctx->error != NULL ? -1 : 0; if (!ctx->finished) dict->iter_replies_skip++; + *error_r = t_strdup(ctx->error); pool_unref(&ctx->pool); + i_free(ctx->error); i_free(ctx); dict->in_iteration = FALSE; diff --git a/src/lib-dict/dict-file.c b/src/lib-dict/dict-file.c index ee735a4040..856453c625 100644 --- a/src/lib-dict/dict-file.c +++ b/src/lib-dict/dict-file.c @@ -46,7 +46,7 @@ struct file_dict_iterate_context { struct file_dict_iterate_path *paths; enum dict_iterate_flags flags; - unsigned int failed:1; + const char *error; }; static struct dotlock_settings file_dict_dotlock_settings = { @@ -232,10 +232,8 @@ file_dict_iterate_init(struct dict *_dict, const char *const *paths, ctx->flags = flags; ctx->iter = hash_table_iterate_init(dict->hash); - if (file_dict_refresh(dict, &error) < 0) { - i_error("%s", error); - ctx->failed = TRUE; - } + if (file_dict_refresh(dict, &error) < 0) + ctx->error = p_strdup(pool, error); return &ctx->ctx; } @@ -284,12 +282,14 @@ static bool file_dict_iterate(struct dict_iterate_context *_ctx, return FALSE; } -static int file_dict_iterate_deinit(struct dict_iterate_context *_ctx) +static int file_dict_iterate_deinit(struct dict_iterate_context *_ctx, + const char **error_r) { struct file_dict_iterate_context *ctx = (struct file_dict_iterate_context *)_ctx; - int ret = ctx->failed ? -1 : 0; + int ret = ctx->error != NULL ? -1 : 0; + *error_r = t_strdup(ctx->error); hash_table_iterate_deinit(&ctx->iter); pool_unref(&ctx->pool); return ret; diff --git a/src/lib-dict/dict-private.h b/src/lib-dict/dict-private.h index 3d1c89bbab..16893e8ac4 100644 --- a/src/lib-dict/dict-private.h +++ b/src/lib-dict/dict-private.h @@ -19,7 +19,8 @@ struct dict_vfuncs { enum dict_iterate_flags flags); bool (*iterate)(struct dict_iterate_context *ctx, const char **key_r, const char **value_r); - int (*iterate_deinit)(struct dict_iterate_context *ctx); + int (*iterate_deinit)(struct dict_iterate_context *ctx, + const char **error_r); struct dict_transaction_context *(*transaction_init)(struct dict *dict); int (*transaction_commit)(struct dict_transaction_context *ctx, diff --git a/src/lib-dict/dict-sql.c b/src/lib-dict/dict-sql.c index 58bae58a8c..dcaea55ee1 100644 --- a/src/lib-dict/dict-sql.c +++ b/src/lib-dict/dict-sql.c @@ -46,7 +46,7 @@ struct sql_dict_iterate_context { unsigned int key_prefix_len, pattern_prefix_len, next_map_idx; unsigned int path_idx, sql_fields_start_idx; bool synchronous_result; - bool failed; + const char *error; }; struct sql_dict_inc_row { @@ -653,10 +653,9 @@ sql_dict_iterate_init(struct dict *_dict, const char *const *paths, ctx->key = str_new(pool, 256); if (sql_dict_iterate_next_query(ctx, &error) <= 0) { - i_error("sql dict iterate failed for %s: %s", - paths[0], error); + ctx->error = p_strdup_printf(pool, + "sql dict iterate failed for %s: %s", paths[0], error); ctx->result = NULL; - ctx->failed = TRUE; return &ctx->ctx; } return &ctx->ctx; @@ -672,7 +671,7 @@ static bool sql_dict_iterate(struct dict_iterate_context *_ctx, int ret; _ctx->has_more = FALSE; - if (ctx->failed) + if (ctx->error != NULL) return FALSE; for (;;) { @@ -695,8 +694,8 @@ static bool sql_dict_iterate(struct dict_iterate_context *_ctx, return FALSE; } if (ret < 0) { - ctx->failed = TRUE; - i_error("dict sql iterate failed: %s", + ctx->error = p_strdup_printf(ctx->pool, + "dict sql iterate failed: %s", sql_result_get_error(ctx->result)); return FALSE; } @@ -733,12 +732,14 @@ static bool sql_dict_iterate(struct dict_iterate_context *_ctx, return TRUE; } -static int sql_dict_iterate_deinit(struct dict_iterate_context *_ctx) +static int sql_dict_iterate_deinit(struct dict_iterate_context *_ctx, + const char **error_r) { struct sql_dict_iterate_context *ctx = (struct sql_dict_iterate_context *)_ctx; - int ret = ctx->failed ? -1 : 0; + int ret = ctx->error != NULL ? -1 : 0; + *error_r = t_strdup(ctx->error); if (ctx->result != NULL) sql_result_unref(ctx->result); pool_unref(&ctx->pool); diff --git a/src/lib-dict/dict.c b/src/lib-dict/dict.c index 45fd8017b0..e8c4123650 100644 --- a/src/lib-dict/dict.c +++ b/src/lib-dict/dict.c @@ -144,7 +144,6 @@ dict_iterate_init_multiple(struct dict *dict, const char *const *paths, i_assert(dict_key_prefix_is_valid(paths[i])); if (dict->v.iterate_init == NULL) { /* not supported by backend */ - i_error("%s: dict iteration not supported", dict->name); return &dict_iter_unsupported; } return dict->v.iterate_init(dict, paths, flags); @@ -170,13 +169,17 @@ bool dict_iterate_has_more(struct dict_iterate_context *ctx) return ctx->has_more; } -int dict_iterate_deinit(struct dict_iterate_context **_ctx) +int dict_iterate_deinit(struct dict_iterate_context **_ctx, + const char **error_r) { struct dict_iterate_context *ctx = *_ctx; *_ctx = NULL; - return ctx == &dict_iter_unsupported ? -1 : - ctx->dict->v.iterate_deinit(ctx); + if (ctx == &dict_iter_unsupported) { + *error_r = "Dict doesn't support iteration"; + return -1; + } + return ctx->dict->v.iterate_deinit(ctx, error_r); } struct dict_transaction_context *dict_transaction_begin(struct dict *dict) diff --git a/src/lib-dict/dict.h b/src/lib-dict/dict.h index 7b674ca068..406f8209d7 100644 --- a/src/lib-dict/dict.h +++ b/src/lib-dict/dict.h @@ -96,7 +96,7 @@ bool dict_iterate_has_more(struct dict_iterate_context *ctx); bool dict_iterate(struct dict_iterate_context *ctx, const char **key_r, const char **value_r); /* Returns 0 = ok, -1 = iteration failed */ -int dict_iterate_deinit(struct dict_iterate_context **ctx); +int dict_iterate_deinit(struct dict_iterate_context **ctx, const char **error_r); /* Start a new dictionary transaction. */ struct dict_transaction_context *dict_transaction_begin(struct dict *dict); diff --git a/src/lib-fs/fs-dict.c b/src/lib-fs/fs-dict.c index 4c4653b5d5..9132fcaf85 100644 --- a/src/lib-fs/fs-dict.c +++ b/src/lib-fs/fs-dict.c @@ -282,11 +282,12 @@ static const char *fs_dict_iter_next(struct fs_iter *_iter) static int fs_dict_iter_deinit(struct fs_iter *_iter) { struct dict_fs_iter *iter = (struct dict_fs_iter *)_iter; + const char *error; int ret; - ret = dict_iterate_deinit(&iter->dict_iter); + ret = dict_iterate_deinit(&iter->dict_iter, &error); if (ret < 0) - fs_set_error(_iter->fs, "Dict iteration failed"); + fs_set_error(_iter->fs, "Dict iteration failed: %s", error); i_free(iter); return ret; } diff --git a/src/lib-storage/index/index-attribute.c b/src/lib-storage/index/index-attribute.c index cbba545a29..1c07a6cb3d 100644 --- a/src/lib-storage/index/index-attribute.c +++ b/src/lib-storage/index/index-attribute.c @@ -302,13 +302,17 @@ int index_storage_attribute_iter_deinit(struct mailbox_attribute_iter *_iter) { struct index_storage_attribute_iter *iter = (struct index_storage_attribute_iter *)_iter; + const char *error; int ret; if (iter->diter == NULL) { ret = iter->dict_disabled ? 0 : -1; } else { - if ((ret = dict_iterate_deinit(&iter->diter)) < 0) - mail_storage_set_internal_error(_iter->box->storage); + if ((ret = dict_iterate_deinit(&iter->diter, &error)) < 0) { + mail_storage_set_critical(_iter->box->storage, + "dict_iterate(%s) failed: %s", + iter->prefix, error); + } } i_free(iter->prefix); i_free(iter); diff --git a/src/plugins/acl/acl-lookup-dict.c b/src/plugins/acl/acl-lookup-dict.c index add5c0ffb2..34e415cd47 100644 --- a/src/plugins/acl/acl-lookup-dict.c +++ b/src/plugins/acl/acl-lookup-dict.c @@ -155,6 +155,7 @@ acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict, struct dict_iterate_context *iter; struct dict_transaction_context *dt; const char *prefix, *key, *value, *const *old_ids, *const *new_ids, *p; + const char *error; ARRAY_TYPE(const_string) old_ids_arr; unsigned int newi, oldi, old_count, new_count; string_t *path; @@ -179,8 +180,8 @@ acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict, array_append(&old_ids_arr, &key, 1); } } - if (dict_iterate_deinit(&iter) < 0) { - i_error("acl: dict iteration failed, can't update dict"); + if (dict_iterate_deinit(&iter, &error) < 0) { + i_error("acl: dict iteration failed: %s - can't update dict", error); return -1; } @@ -264,7 +265,7 @@ int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict) static void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter) { struct dict_iterate_context *dict_iter; - const char *const *idp, *prefix, *key, *value; + const char *const *idp, *prefix, *key, *value, *error; unsigned int prefix_len; idp = array_idx(&iter->iter_ids, iter->iter_idx); @@ -288,8 +289,10 @@ static void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter) key = p_strdup(iter->iter_value_pool, key + prefix_len); array_append(&iter->iter_values, &key, 1); } - if (dict_iterate_deinit(&dict_iter) < 0) + if (dict_iterate_deinit(&dict_iter, &error) < 0) { + i_error("%s", error); iter->failed = TRUE; + } } struct acl_lookup_dict_iter * diff --git a/src/plugins/expire/doveadm-expire.c b/src/plugins/expire/doveadm-expire.c index ea2e12d31a..51e0dd84b3 100644 --- a/src/plugins/expire/doveadm-expire.c +++ b/src/plugins/expire/doveadm-expire.c @@ -126,7 +126,7 @@ doveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx, { struct doveadm_expire_mail_cmd_context *ectx = DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const char *key, *value; + const char *key, *value, *error; unsigned long oldest_savedate; int ret; @@ -159,8 +159,8 @@ doveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx, } /* finished */ - if (dict_iterate_deinit(&ectx->iter) < 0) { - i_error("Dictionary iteration failed"); + if (dict_iterate_deinit(&ectx->iter, &error) < 0) { + i_error("Dictionary iteration failed: %s", error); return -1; } return 0; @@ -352,10 +352,11 @@ static void doveadm_expire_mail_cmd_deinit(struct doveadm_mail_cmd_context *ctx) { struct doveadm_expire_mail_cmd_context *ectx = DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); + const char *error; if (ectx->iter != NULL) { - if (dict_iterate_deinit(&ectx->iter) < 0) - i_error("expire: Dictionary iteration failed"); + if (dict_iterate_deinit(&ectx->iter, &error) < 0) + i_error("expire: Dictionary iteration failed: %s", error); } if (dict_transaction_commit(&ectx->trans) < 0) i_error("expire: Dictionary commit failed");