doveadm-fs.c revision 95c13a27352739261c53ecd23fe2f0c3d61aa06f
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2013-2015 Dovecot authors, see the included COPYING file */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "lib.h"
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen#include "array.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "md5.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "sha2.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "hash-method.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "hex-binary.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "istream.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "ostream.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "iostream-ssl.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "fs-api.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "doveadm.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <stdio.h>
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen#include <unistd.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void fs_cmd_help(doveadm_command_t *cmd);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainenstatic void cmd_fs_delete(int argc, char *argv[]);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic struct fs *
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainencmd_fs_init(int *argc, char **argv[], int own_arg_count, doveadm_command_t *cmd)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct ssl_iostream_settings ssl_set;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_settings fs_set;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *error;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (*argc != 3 + own_arg_count)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_cmd_help(cmd);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen memset(&ssl_set, 0, sizeof(ssl_set));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ssl_set.ca_dir = doveadm_settings->ssl_client_ca_dir;
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen ssl_set.ca_file = doveadm_settings->ssl_client_ca_file;
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen ssl_set.verbose = doveadm_debug;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen memset(&fs_set, 0, sizeof(fs_set));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_set.ssl_client_set = &ssl_set;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_set.temp_dir = "/tmp";
6766440ffdd8d3ff99a1f732eef212813089bb81Timo Sirainen fs_set.base_dir = doveadm_settings->base_dir;
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen fs_set.debug = doveadm_debug;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_init((*argv)[1], (*argv)[2], &fs_set, &fs, &error) < 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_fatal("fs_init() failed: %s", error);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen *argc += 3;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen *argv += 3;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_get(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_file *file;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct istream *input;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const unsigned char *data;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen size_t size;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ssize_t ret;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_get);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen input = fs_read_stream(file, IO_BLOCK_SIZE);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fwrite(data, 1, size, stdout);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_stream_skip(input, size);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_assert(ret == -1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (input->stream_errno == ENOENT) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else if (input->stream_errno != 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("read(%s) failed: %m", fs_file_path(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_stream_unref(&input);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_put(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen enum fs_properties props;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *src_path, *dest_path;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_file *file;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct istream *input;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct ostream *output;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen buffer_t *hash = NULL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen off_t ret;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen int c;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen while ((c = getopt(argc, argv, "h:")) > 0) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen switch (c) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen case 'h':
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen hash = buffer_create_dynamic(pool_datastack_create(), 32);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if (hex_to_binary(optarg, hash) < 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen i_fatal("Invalid -h parameter: Hash not in hex");
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen break;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen default:
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen fs_cmd_help(cmd_fs_put);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen }
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen }
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen argc -= optind-1; argv += optind-1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_put);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen src_path = argv[0];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen dest_path = argv[1];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen props = fs_get_properties(fs);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if (hash == NULL)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen ;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (hash->used == hash_method_md5.digest_size) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if ((props & FS_PROPERTY_WRITE_HASH_MD5) == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen i_fatal("fs backend doesn't support MD5 hashes");
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen fs_write_set_hash(file,
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen hash_method_lookup(hash_method_md5.name), hash->data);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen } else if (hash->used == hash_method_sha256.digest_size) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if ((props & FS_PROPERTY_WRITE_HASH_SHA256) == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen i_fatal("fs backend doesn't support SHA256 hashes");
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen fs_write_set_hash(file,
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen hash_method_lookup(hash_method_sha256.name), hash->data);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen }
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen output = fs_write_stream(file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen input = i_stream_create_file(src_path, IO_BLOCK_SIZE);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if ((ret = o_stream_send_istream(output, input)) < 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (output->stream_errno != 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("write(%s) failed: %m", dest_path);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("read(%s) failed: %m", src_path);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_stream_destroy(&input);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_write_stream_finish(file, &output) < 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("fs_write_stream_finish() failed: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_last_error(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_copy(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_file *src_file, *dest_file;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *src_path, *dest_path;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_copy);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen src_path = argv[0];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen dest_path = argv[1];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen src_file = fs_file_init(fs, src_path, FS_OPEN_MODE_READONLY);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen dest_file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_copy(src_file, dest_file) == 0) ;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (errno == ENOENT) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("%s doesn't exist", src_path);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("fs_copy(%s, %s) failed: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen src_path, dest_path, fs_last_error(fs));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&src_file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&dest_file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_stat(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_file *file;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct stat st;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_stat);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_stat(file, &st) == 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen printf("%s size=%lld\n", fs_file_path(file),
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen (long long)st.st_size);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else if (errno == ENOENT) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("fs_stat(%s) failed: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_path(file), fs_file_last_error(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainenstatic void cmd_fs_metadata(int argc, char *argv[])
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen{
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen struct fs *fs;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen struct fs_file *file;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen const struct fs_metadata *m;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen const ARRAY_TYPE(fs_metadata) *metadata;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_metadata);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen if (fs_get_metadata(file, &metadata) == 0) {
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen array_foreach(metadata, m)
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen printf("%s=%s\n", m->key, m->value);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen } else if (errno == ENOENT) {
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen i_error("%s doesn't exist", fs_file_path(file));
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen } else {
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen i_error("fs_stat(%s) failed: %s",
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen fs_file_path(file), fs_file_last_error(file));
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen }
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen fs_file_deinit(&file);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen fs_deinit(&fs);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen}
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenstruct fs_delete_ctx {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen unsigned int files_count;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen struct fs_file **files;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen};
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenstatic bool cmd_fs_delete_ctx_run(struct fs_delete_ctx *ctx)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen{
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen unsigned int i;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen bool ret = FALSE;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen for (i = 0; i < ctx->files_count; i++) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (ctx->files[i] == NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen else if (fs_delete(ctx->files[i]) == 0)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fs_file_deinit(&ctx->files[i]);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen else if (errno == EAGAIN)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ret = TRUE;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen else {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_error("fs_delete(%s) failed: %s",
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fs_file_path(ctx->files[i]),
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fs_file_last_error(ctx->files[i]));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return ret;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen}
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenstatic void
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainencmd_fs_delete_dir_recursive(struct fs *fs, unsigned int async_count,
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const char *path)
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen{
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen struct fs_iter *iter;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ARRAY_TYPE(const_string) fnames;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen struct fs_delete_ctx ctx;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen const char *fname, *const *fnamep;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen unsigned int i;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen memset(&ctx, 0, sizeof(ctx));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ctx.files_count = I_MAX(async_count, 1);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ctx.files = t_new(struct fs_file *, ctx.files_count);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen /* delete subdirs first. all fs backends can't handle recursive
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen lookups, so save the list first. */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen t_array_init(&fnames, 8);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
aab0e25f23db4be9c50bfd1cd271f691839c2deeTimo Sirainen fname = t_strconcat(fname, "/", NULL);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen array_append(&fnames, &fname, 1);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen if (fs_iter_deinit(&iter) < 0) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen path, fs_last_error(fs));
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen array_foreach(&fnames, fnamep) T_BEGIN {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen cmd_fs_delete_dir_recursive(fs, async_count,
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen t_strdup_printf("%s/%s", path, *fnamep));
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen } T_END;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen /* delete files. again because we're doing this asynchronously finish
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen the iteration first. */
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen if ((fs_get_properties(fs) & FS_PROPERTY_DIRECTORIES) != 0) {
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen /* we need to explicitly delete also the directories */
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen } else {
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen array_clear(&fnames);
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen iter = fs_iter_init(fs, path, 0);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fname = t_strdup(fname);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen array_append(&fnames, &fname, 1);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen if (fs_iter_deinit(&iter) < 0) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen path, fs_last_error(fs));
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen array_foreach(&fnames, fnamep) T_BEGIN {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fname = *fnamep;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen retry:
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen for (i = 0; i < ctx.files_count; i++) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (ctx.files[i] != NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen continue;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen ctx.files[i] = fs_file_init(fs,
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen t_strdup_printf("%s/%s", path, fname),
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen FS_OPEN_MODE_READONLY | FS_OPEN_FLAG_ASYNC |
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen FS_OPEN_FLAG_ASYNC_NOQUEUE);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fname = NULL;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen break;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen cmd_fs_delete_ctx_run(&ctx);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (fname != NULL) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (fs_wait_async(fs) < 0) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen break;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen goto retry;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen } T_END;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen while (doveadm_exit_code == 0 && cmd_fs_delete_ctx_run(&ctx)) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (fs_wait_async(fs) < 0) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen break;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen for (i = 0; i < ctx.files_count; i++) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (ctx.files[i] != NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fs_file_deinit(&ctx.files[i]);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen}
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenstatic void
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainencmd_fs_delete_recursive(int argc, char *argv[], unsigned int async_count)
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen{
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen struct fs *fs;
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen struct fs_file *file;
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen const char *path;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen path = argv[0];
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen cmd_fs_delete_dir_recursive(fs, async_count, path);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen if ((fs_get_properties(fs) & FS_PROPERTY_DIRECTORIES) != 0) {
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen /* delete the root itself */
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen if (fs_delete(file) < 0) {
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen i_error("fs_delete(%s) failed: %s",
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen fs_file_path(file), fs_file_last_error(file));
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen }
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen fs_file_deinit(&file);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen fs_deinit(&fs);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen}
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_delete(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_file *file;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen bool recursive = FALSE;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen unsigned int async_count = 0;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen int c;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen while ((c = getopt(argc, argv, "Rn:")) > 0) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen switch (c) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen case 'R':
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen recursive = TRUE;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen break;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen case 'n':
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (str_to_uint(optarg, &async_count) < 0)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_fatal("Invalid -n parameter: %s", optarg);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen break;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen default:
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen fs_cmd_help(cmd_fs_delete);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
244d1dd1a501d1e4b53d8af9a2704640b276b7daTimo Sirainen argc -= optind-1; argv += optind-1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (recursive) {
244d1dd1a501d1e4b53d8af9a2704640b276b7daTimo Sirainen cmd_fs_delete_recursive(argc, argv, async_count);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen return;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen }
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_delete(file) == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (errno == ENOENT) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("fs_delete(%s) failed: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_path(file), fs_file_last_error(file));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_file_deinit(&file);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_iter_full(int argc, char *argv[], enum fs_iter_flags flags,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_command_t *cmd)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs *fs;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct fs_iter *iter;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *fname;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen iter = fs_iter_init(fs, argv[0], flags);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen while ((fname = fs_iter_next(iter)) != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen printf("%s\n", fname);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (fs_iter_deinit(&iter) < 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen argv[0], fs_last_error(fs));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen fs_deinit(&fs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_iter(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen cmd_fs_iter_full(argc, argv, 0, cmd_fs_iter);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void cmd_fs_iter_dirs(int argc, char *argv[])
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen cmd_fs_iter_full(argc, argv, FS_ITER_FLAG_DIRS, cmd_fs_iter_dirs);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstruct doveadm_cmd doveadm_cmd_fs[] = {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen { cmd_fs_get, "fs get", "<fs-driver> <fs-args> <path>" },
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen { cmd_fs_put, "fs put", "[-h <hash>] <fs-driver> <fs-args> <input path> <path>" },
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen { cmd_fs_copy, "fs copy", "<fs-driver> <fs-args> <source path> <dest path>" },
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen { cmd_fs_stat, "fs stat", "<fs-driver> <fs-args> <path>" },
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen { cmd_fs_metadata, "fs metadata", "<fs-driver> <fs-args> <path>" },
e3734a6606e292b6673a506dfcd7e0964b7ba451Timo Sirainen { cmd_fs_delete, "fs delete", "[-R] [-n <count>] <fs-driver> <fs-args> <path>" },
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen { cmd_fs_iter, "fs iter", "<fs-driver> <fs-args> <path>" },
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen { cmd_fs_iter_dirs, "fs iter-dirs", "<fs-driver> <fs-args> <path>" },
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen};
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void fs_cmd_help(doveadm_command_t *cmd)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (doveadm_cmd_fs[i].cmd == cmd)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen help(&doveadm_cmd_fs[i]);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_unreached();
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid doveadm_register_fs_commands(void)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen doveadm_register_cmd(&doveadm_cmd_fs[i]);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}