doveadm-fs.c revision ca096c557fac1cf87dd5f129c202b2c1d990ff59
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen#include "array.h"
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen#include "istream.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "ostream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "iostream-ssl.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "fs-api.h"
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen#include "doveadm.h"
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stdio.h>
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainenstatic void fs_cmd_help(doveadm_command_t *cmd);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainenstatic void cmd_fs_delete(int argc, char *argv[]);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainenstatic struct fs *
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainencmd_fs_init(int *argc, char **argv[], int own_arg_count, doveadm_command_t *cmd)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct ssl_iostream_settings ssl_set;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct fs_settings fs_set;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct fs *fs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *error;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen if (*argc != 3 + own_arg_count)
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen fs_cmd_help(cmd);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen memset(&ssl_set, 0, sizeof(ssl_set));
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen ssl_set.ca_dir = doveadm_settings->ssl_client_ca_dir;
9b7eeffb5752b500ac62ba1fd01c4a8c4ada14e9Timo Sirainen ssl_set.ca_file = doveadm_settings->ssl_client_ca_file;
9b7eeffb5752b500ac62ba1fd01c4a8c4ada14e9Timo Sirainen ssl_set.verbose = doveadm_debug;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen memset(&fs_set, 0, sizeof(fs_set));
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen fs_set.ssl_client_set = &ssl_set;
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen fs_set.temp_dir = "/tmp";
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen fs_set.base_dir = doveadm_settings->base_dir;
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen fs_set.debug = doveadm_debug;
b565a6a7a66fb9f224d00c06a950e3c1c585c18eTimo Sirainen
b565a6a7a66fb9f224d00c06a950e3c1c585c18eTimo Sirainen if (fs_init((*argv)[1], (*argv)[2], &fs_set, &fs, &error) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("fs_init() failed: %s", error);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen *argc += 3;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen *argv += 3;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return fs;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic void cmd_fs_get(int argc, char *argv[])
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct fs *fs;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct fs_file *file;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct istream *input;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const unsigned char *data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_get);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen input = fs_read_stream(file, IO_BLOCK_SIZE);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen fwrite(data, 1, size, stdout);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen i_stream_skip(input, size);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen }
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen i_assert(ret == -1);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen if (input->stream_errno == ENOENT) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (input->stream_errno != 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_error("read(%s) failed: %m", fs_file_path(file));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_stream_unref(&input);
683eebe490bbe5caec246c535a10ea9f93f5c330Timo Sirainen fs_file_deinit(&file);
683eebe490bbe5caec246c535a10ea9f93f5c330Timo Sirainen fs_deinit(&fs);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainenstatic void cmd_fs_put(int argc, char *argv[])
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct fs *fs;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const char *src_path, *dest_path;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen struct fs_file *file;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen struct istream *input;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct ostream *output;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen off_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_put);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen src_path = argv[0];
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen dest_path = argv[1];
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen output = fs_write_stream(file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen input = i_stream_create_file(src_path, IO_BLOCK_SIZE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((ret = o_stream_send_istream(output, input)) < 0) {
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (output->stream_errno != 0)
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen i_error("write(%s) failed: %m", dest_path);
d7e72877b7a5085c3addf9729d0bfbe1b5357853Timo Sirainen else
d7e72877b7a5085c3addf9729d0bfbe1b5357853Timo Sirainen i_error("read(%s) failed: %m", src_path);
d7e72877b7a5085c3addf9729d0bfbe1b5357853Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
d7e72877b7a5085c3addf9729d0bfbe1b5357853Timo Sirainen }
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen i_stream_destroy(&input);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (fs_write_stream_finish(file, &output) < 0) {
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen i_error("fs_write_stream_finish() failed: %s",
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen fs_file_last_error(file));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen fs_file_deinit(&file);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen fs_deinit(&fs);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void cmd_fs_copy(int argc, char *argv[])
{
struct fs *fs;
struct fs_file *src_file, *dest_file;
const char *src_path, *dest_path;
fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_copy);
src_path = argv[0];
dest_path = argv[1];
src_file = fs_file_init(fs, src_path, FS_OPEN_MODE_READONLY);
dest_file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
if (fs_copy(src_file, dest_file) == 0) ;
else if (errno == ENOENT) {
i_error("%s doesn't exist", src_path);
doveadm_exit_code = DOVEADM_EX_NOTFOUND;
} else {
i_error("fs_copy(%s, %s) failed: %s",
src_path, dest_path, fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
fs_file_deinit(&src_file);
fs_file_deinit(&dest_file);
fs_deinit(&fs);
}
static void cmd_fs_stat(int argc, char *argv[])
{
struct fs *fs;
struct fs_file *file;
struct stat st;
fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_stat);
file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
if (fs_stat(file, &st) == 0) {
printf("%s size=%lld\n", fs_file_path(file),
(long long)st.st_size);
} else if (errno == ENOENT) {
i_error("%s doesn't exist", fs_file_path(file));
doveadm_exit_code = DOVEADM_EX_NOTFOUND;
} else {
i_error("fs_stat(%s) failed: %s",
fs_file_path(file), fs_file_last_error(file));
doveadm_exit_code = EX_TEMPFAIL;
}
fs_file_deinit(&file);
fs_deinit(&fs);
}
static void cmd_fs_delete_dir_recursive(struct fs *fs, const char *path)
{
struct fs_iter *iter;
struct fs_file *file;
ARRAY_TYPE(const_string) dirs;
const char *fname, *const *fnamep;
/* delete subdirs first. all fs backends can't handle recursive
lookups, so save the list first. */
t_array_init(&dirs, 8);
iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS);
while ((fname = fs_iter_next(iter)) != NULL) {
fname = t_strdup(fname);
array_append(&dirs, &fname, 1);
}
if (fs_iter_deinit(&iter) < 0) {
i_error("fs_iter_deinit(%s) failed: %s",
path, fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
array_foreach(&dirs, fnamep) T_BEGIN {
cmd_fs_delete_dir_recursive(fs,
t_strdup_printf("%s/%s", path, *fnamep));
} T_END;
/* delete files */
iter = fs_iter_init(fs, path, 0);
while ((fname = fs_iter_next(iter)) != NULL) T_BEGIN {
file = fs_file_init(fs, t_strdup_printf("%s/%s", path, fname),
FS_OPEN_MODE_READONLY);
if (fs_delete(file) < 0) {
i_error("fs_delete(%s) failed: %s",
fs_file_path(file), fs_file_last_error(file));
doveadm_exit_code = EX_TEMPFAIL;
}
fs_file_deinit(&file);
} T_END;
if (fs_iter_deinit(&iter) < 0) {
i_error("fs_iter_deinit(%s) failed: %s",
path, fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
}
static void cmd_fs_delete_recursive(int argc, char *argv[])
{
struct fs *fs;
fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
cmd_fs_delete_dir_recursive(fs, argv[0]);
fs_deinit(&fs);
}
static void cmd_fs_delete(int argc, char *argv[])
{
struct fs *fs;
struct fs_file *file;
if (null_strcmp(argv[1], "-R") == 0) {
cmd_fs_delete_recursive(argc-1, argv+1);
return;
}
fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
if (fs_delete(file) == 0)
;
else if (errno == ENOENT) {
i_error("%s doesn't exist", fs_file_path(file));
doveadm_exit_code = DOVEADM_EX_NOTFOUND;
} else {
i_error("fs_delete(%s) failed: %s",
fs_file_path(file), fs_file_last_error(file));
doveadm_exit_code = EX_TEMPFAIL;
}
fs_file_deinit(&file);
fs_deinit(&fs);
}
static void cmd_fs_iter_full(int argc, char *argv[], enum fs_iter_flags flags,
doveadm_command_t *cmd)
{
struct fs *fs;
struct fs_iter *iter;
const char *fname;
fs = cmd_fs_init(&argc, &argv, 1, cmd);
iter = fs_iter_init(fs, argv[0], flags);
while ((fname = fs_iter_next(iter)) != NULL)
printf("%s\n", fname);
if (fs_iter_deinit(&iter) < 0) {
i_error("fs_iter_deinit(%s) failed: %s",
argv[0], fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
fs_deinit(&fs);
}
static void cmd_fs_iter(int argc, char *argv[])
{
cmd_fs_iter_full(argc, argv, 0, cmd_fs_iter);
}
static void cmd_fs_iter_dirs(int argc, char *argv[])
{
cmd_fs_iter_full(argc, argv, FS_ITER_FLAG_DIRS, cmd_fs_iter_dirs);
}
struct doveadm_cmd doveadm_cmd_fs[] = {
{ cmd_fs_get, "fs get", "<fs-driver> <fs-args> <path>" },
{ cmd_fs_put, "fs put", "<fs-driver> <fs-args> <input path> <path>" },
{ cmd_fs_copy, "fs copy", "<fs-driver> <fs-args> <source path> <dest path>" },
{ cmd_fs_stat, "fs stat", "<fs-driver> <fs-args> <path>" },
{ cmd_fs_delete, "fs delete", "[-R] <fs-driver> <fs-args> <path>" },
{ cmd_fs_iter, "fs iter", "<fs-driver> <fs-args> <path>" },
{ cmd_fs_iter_dirs, "fs iter-dirs", "<fs-driver> <fs-args> <path>" },
};
static void fs_cmd_help(doveadm_command_t *cmd)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++) {
if (doveadm_cmd_fs[i].cmd == cmd)
help(&doveadm_cmd_fs[i]);
}
i_unreached();
}
void doveadm_register_fs_commands(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++)
doveadm_register_cmd(&doveadm_cmd_fs[i]);
}