bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "lib.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "master-instance.h"
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen#include "master-service-settings.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "doveadm.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "doveadm-print.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen#include <stdio.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include <unistd.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include <fcntl.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include <signal.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenextern struct doveadm_cmd doveadm_cmd_instance[];
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic void instance_cmd_help(doveadm_command_t *cmd) ATTR_NORETURN;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic bool pid_file_read(const char *path)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen char buf[32];
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen int fd;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen ssize_t ret;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen pid_t pid;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen bool found = FALSE;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen fd = open(path, O_RDONLY);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (fd == -1) {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (errno != ENOENT)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen i_error("open(%s) failed: %m", path);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen return FALSE;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen ret = read(fd, buf, sizeof(buf));
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (ret < 0)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen i_error("read(%s) failed: %m", path);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen else if (ret > 0 && buf[ret-1] == '\n') {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen buf[ret-1] = '\0';
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (str_to_pid(buf, &pid) == 0) {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen found = !(pid == getpid() ||
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen (kill(pid, 0) < 0 && errno == ESRCH));
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen }
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen return found;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
1c7d88528a964f0a0e16bfe48d76da1cea94088eTimo Sirainenstatic void cmd_instance_list(int argc, char *argv[])
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen struct master_instance_list *list;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen struct master_instance_list_iter *iter;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen const struct master_instance *inst;
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen const char *instance_path, *pidfile_path;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen bool show_config = FALSE;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen int c;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen while ((c = getopt(argc, argv, "c")) > 0) {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen switch (c) {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen case 'c':
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen show_config = TRUE;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen break;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen default:
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen help(&doveadm_cmd_instance[0]);
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen }
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen }
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen argv += optind;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen if (!show_config) {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen doveadm_print_header("path", "path", DOVEADM_PRINT_HEADER_FLAG_EXPAND);
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen doveadm_print_header_simple("name");
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen doveadm_print_header_simple("last used");
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen doveadm_print_header_simple("running");
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen instance_path = t_strconcat(service_set->state_dir,
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen "/"MASTER_INSTANCE_FNAME, NULL);
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen list = master_instance_list_init(instance_path);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen iter = master_instance_list_iterate_init(list);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen while ((inst = master_instance_iterate_list_next(iter)) != NULL) {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen if (argv[0] != NULL && strcmp(argv[0], inst->name) != 0)
1c7d88528a964f0a0e16bfe48d76da1cea94088eTimo Sirainen continue;
1c7d88528a964f0a0e16bfe48d76da1cea94088eTimo Sirainen
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen if (show_config) {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen printf("%s\n", inst->config_path == NULL ? "" :
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen inst->config_path);
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen continue;
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen doveadm_print(inst->base_dir);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen doveadm_print(inst->name);
5f252b9777617d67196e59fbd1f1d404a5323719Timo Sirainen doveadm_print(unixdate2str(inst->last_used));
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen pidfile_path = t_strconcat(inst->base_dir, "/master.pid", NULL);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (pid_file_read(pidfile_path))
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen doveadm_print("yes");
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen else
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen doveadm_print("no");
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen master_instance_iterate_list_deinit(&iter);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen master_instance_list_deinit(&list);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic void cmd_instance_remove(int argc, char *argv[])
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen struct master_instance_list *list;
2b602d8698d82e974eba6339ef96c29e256bde31Timo Sirainen const struct master_instance *inst;
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen const char *base_dir, *instance_path;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen int ret;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (argc != 2)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen instance_cmd_help(cmd_instance_remove);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen instance_path = t_strconcat(service_set->state_dir,
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen "/"MASTER_INSTANCE_FNAME, NULL);
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen list = master_instance_list_init(instance_path);
2b602d8698d82e974eba6339ef96c29e256bde31Timo Sirainen inst = master_instance_list_find_by_name(list, argv[1]);
2b602d8698d82e974eba6339ef96c29e256bde31Timo Sirainen base_dir = inst != NULL ? inst->base_dir : argv[1];
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if ((ret = master_instance_list_remove(list, base_dir)) < 0) {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen i_error("Failed to remove instance");
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen } else if (ret == 0) {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen i_error("Instance already didn't exist");
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen master_instance_list_deinit(&list);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstruct doveadm_cmd doveadm_cmd_instance[] = {
6ea1de17b3d415f6ff2e6a2af8d34d8f6cf17636Timo Sirainen { cmd_instance_list, "instance list", "[-c] [<name>]" },
2b602d8698d82e974eba6339ef96c29e256bde31Timo Sirainen { cmd_instance_remove, "instance remove", "<name> | <base dir>" }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen};
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic void instance_cmd_help(doveadm_command_t *cmd)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen unsigned int i;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_instance); i++) {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen if (doveadm_cmd_instance[i].cmd == cmd)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen help(&doveadm_cmd_instance[i]);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen }
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen i_unreached();
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenvoid doveadm_register_instance_commands(void)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen unsigned int i;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_instance); i++)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen doveadm_register_cmd(&doveadm_cmd_instance[i]);
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}