From: Timo Sirainen Date: Mon, 7 Aug 2023 08:17:34 +0000 (+0300) Subject: doveadm: Add "mail fs" commands X-Git-Tag: 2.4.1~1381 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=563055826e69a246c2271cabd4a5be4cf241ab6d;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Add "mail fs" commands These are similar to "doveadm fs" commands, but they're run in the mail user context. This way all user-specific settings are applied and process uid/gid is also set properly. --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 71d8f65a81..98339cfc96 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -93,6 +93,7 @@ doveadm_common_mail_cmds = \ doveadm-mail-expunge.c \ doveadm-mail-fetch.c \ doveadm-mail-flags.c \ + doveadm-mail-fs.c \ doveadm-mail-import.c \ doveadm-mail-index.c \ doveadm-mail-iter.c \ diff --git a/src/doveadm/doveadm-mail-fs.c b/src/doveadm/doveadm-mail-fs.c new file mode 100644 index 0000000000..f62dc00cd9 --- /dev/null +++ b/src/doveadm/doveadm-mail-fs.c @@ -0,0 +1,372 @@ +/* Copyright (c) 2023 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hex-binary.h" +#include "fs-api.h" +#include "doveadm.h" +#include "doveadm-fs.h" +#include "doveadm-mail.h" +#include "doveadm-print.h" + +struct mail_fs_cmd_context { + struct doveadm_mail_cmd_context ctx; + const char *path, *src_path, *dest_path; + const char *const *paths; + buffer_t *hash; + + enum fs_iter_flags iter_flags; + bool recursive; + int64_t async_count; +}; + +static void cmd_mail_fs_get_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "path", &cctx->path)) + doveadm_mail_help_name("mail fs get"); + doveadm_print_header("content", "content", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); +} + +static int cmd_mail_fs_get_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_get(_cctx->cctx, cctx->path); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_get_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_get_init; + ctx->ctx.v.run = cmd_mail_fs_get_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_PAGER); + return &ctx->ctx; +} + +static void cmd_mail_fs_put_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + const char *hash_str; + + if (!doveadm_cmd_param_str(_cctx->cctx, "input-path", &cctx->src_path) || + !doveadm_cmd_param_str(_cctx->cctx, "path", &cctx->dest_path)) + doveadm_mail_help_name("mail fs put"); + if (doveadm_cmd_param_str(_cctx->cctx, "hash", &hash_str)) { + cctx->hash = t_buffer_create(32); + if (hex_to_binary(optarg, cctx->hash) < 0) + i_fatal("Invalid -h parameter: Hash not in hex"); + } +} + +static int cmd_mail_fs_put_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_put(_cctx->cctx, cctx->src_path, + cctx->dest_path, cctx->hash); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_put_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_put_init; + ctx->ctx.v.run = cmd_mail_fs_put_run; + return &ctx->ctx; +} + +static void cmd_mail_fs_copy_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "source-path", &cctx->src_path) || + !doveadm_cmd_param_str(_cctx->cctx, "destination-path", &cctx->dest_path)) + doveadm_mail_help_name("mail fs copy"); +} + +static int cmd_mail_fs_copy_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_copy(_cctx->cctx, cctx->src_path, cctx->dest_path); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_copy_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_copy_init; + ctx->ctx.v.run = cmd_mail_fs_copy_run; + return &ctx->ctx; +} + +static void cmd_mail_fs_stat_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "path", &cctx->path)) + doveadm_mail_help_name("mail fs stat"); + + doveadm_print_header_simple("path"); + doveadm_print_header("size", "size", DOVEADM_PRINT_HEADER_FLAG_NUMBER); +} + +static int cmd_mail_fs_stat_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_stat(_cctx->cctx, cctx->path); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_stat_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_stat_init; + ctx->ctx.v.run = cmd_mail_fs_stat_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED); + doveadm_print_formatted_set_format("%{path} size=%{size}"); + return &ctx->ctx; +} + +static void cmd_mail_fs_metadata_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "path", &cctx->path)) + doveadm_mail_help_name("mail fs metadata"); + + doveadm_print_header_simple("key"); + doveadm_print_header_simple("value"); +} + +static int cmd_mail_fs_metadata_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_metadata(_cctx->cctx, cctx->path); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_metadata_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_metadata_init; + ctx->ctx.v.run = cmd_mail_fs_metadata_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED); + doveadm_print_formatted_set_format("%{key}=%{value}\n"); + return &ctx->ctx; +} + +static void cmd_mail_fs_delete_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (!doveadm_cmd_param_array(_cctx->cctx, "path", &cctx->paths)) + doveadm_mail_help_name("mail fs delete"); + + (void)doveadm_cmd_param_bool(_cctx->cctx, "recursive", &cctx->recursive); + (void)doveadm_cmd_param_int64(_cctx->cctx, "max-parallel", &cctx->async_count); +} + +static int cmd_mail_fs_delete_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + if (cctx->recursive) { + doveadm_fs_delete_recursive(_cctx->cctx, cctx->paths, + cctx->async_count); + } else { + doveadm_fs_delete_paths(_cctx->cctx, cctx->paths, + cctx->async_count); + } + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_delete_alloc(void) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_delete_init; + ctx->ctx.v.run = cmd_mail_fs_delete_run; + return &ctx->ctx; +} + +static void cmd_mail_fs_iter_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + bool b; + + if (!doveadm_cmd_param_str(_cctx->cctx, "path", &cctx->path)) { + doveadm_mail_help_name((cctx->iter_flags & FS_ITER_FLAG_DIRS) != 0 ? + "mail fs iter-dirs" : "mail fs iter"); + } + + if (doveadm_cmd_param_bool(_cctx->cctx, "no-cache", &b) && b) + cctx->iter_flags |= FS_ITER_FLAG_NOCACHE; + if (doveadm_cmd_param_bool(_cctx->cctx, "object-ids", &b) && b) + cctx->iter_flags |= FS_ITER_FLAG_OBJECTIDS; + + doveadm_print_header_simple("path"); +} + +static int cmd_mail_fs_iter_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_fs_cmd_context *cctx = + container_of(_cctx, struct mail_fs_cmd_context, ctx); + + doveadm_fs_iter(_cctx->cctx, cctx->iter_flags, cctx->path); + return 0; +} + +static struct doveadm_mail_cmd_context * +cmd_mail_fs_iter_alloc_full(enum fs_iter_flags iter_flags) +{ + struct mail_fs_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_fs_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_fs_iter_init; + ctx->ctx.v.run = cmd_mail_fs_iter_run; + ctx->iter_flags = iter_flags; + doveadm_print_init(DOVEADM_PRINT_TYPE_FORMATTED); + doveadm_print_formatted_set_format("%{path}\n"); + return &ctx->ctx; +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_iter_alloc(void) +{ + return cmd_mail_fs_iter_alloc_full(0); +} + +static struct doveadm_mail_cmd_context *cmd_mail_fs_iter_dirs_alloc(void) +{ + return cmd_mail_fs_iter_alloc_full(FS_ITER_FLAG_DIRS); +} + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_get = { + .name = "mail fs get", + .mail_cmd = cmd_mail_fs_get_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_put = { + .name = "mail fs put", + .mail_cmd = cmd_mail_fs_put_alloc, + .usage = "[-h ] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('h', "hash", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "input-path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_copy = { + .name = "mail fs copy", + .mail_cmd = cmd_mail_fs_copy_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "source-path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "destination-path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_stat = { + .name = "mail fs stat", + .mail_cmd = cmd_mail_fs_stat_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_metadata = { + .name = "mail fs metadata", + .mail_cmd = cmd_mail_fs_metadata_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_delete = { + .name = "mail fs delete", + .mail_cmd = cmd_mail_fs_delete_alloc, + .usage = "[-R] [-n ] [ ...]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('R', "recursive", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('n', "max-parallel", CMD_PARAM_INT64, CMD_PARAM_FLAG_UNSIGNED) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter = { + .name = "mail fs iter", + .mail_cmd = cmd_mail_fs_iter_alloc, + .usage = "[--no-cache] [--object-ids] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('C', "no-cache", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('O', "object-ids", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter_dirs = { + .name = "mail fs iter-dirs", + .mail_cmd = cmd_mail_fs_iter_dirs_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "path", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 57f314cb5c..81a7afa62a 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -818,6 +818,14 @@ static struct doveadm_cmd_ver2 *mail_commands_ver2[] = { &doveadm_cmd_mailbox_cache_remove, &doveadm_cmd_mailbox_cache_purge, &doveadm_cmd_rebuild_attachments, + &doveadm_cmd_mail_fs_get, + &doveadm_cmd_mail_fs_put, + &doveadm_cmd_mail_fs_copy, + &doveadm_cmd_mail_fs_stat, + &doveadm_cmd_mail_fs_metadata, + &doveadm_cmd_mail_fs_delete, + &doveadm_cmd_mail_fs_iter, + &doveadm_cmd_mail_fs_iter_dirs, }; void doveadm_mail_init(void) diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index c922ac43ad..85e0e87c20 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -210,6 +210,14 @@ extern struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_decision; extern struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_remove; extern struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_purge; extern struct doveadm_cmd_ver2 doveadm_cmd_rebuild_attachments; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_get; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_put; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_copy; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_stat; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_metadata; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_delete; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter_dirs; #define DOVEADM_CMD_MAIL_COMMON \ DOVEADM_CMD_PARAM('A', "all-users", CMD_PARAM_BOOL, 0) \