doveadm-master.c revision de41dbb482990a4be10ca9033cf881a850ccdc50
7cb14f34a92e0a8eae07db027344126bf5c901c9KATOH Yasufumi/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
2b371b262f7272266ff18cc2aff65176a2c16383Sungbae Yoo
7cb14f34a92e0a8eae07db027344126bf5c901c9KATOH Yasufumi#include "lib.h"
7cb14f34a92e0a8eae07db027344126bf5c901c9KATOH Yasufumi#include "str.h"
2b371b262f7272266ff18cc2aff65176a2c16383Sungbae Yoo#include "istream.h"
7cb14f34a92e0a8eae07db027344126bf5c901c9KATOH Yasufumi#include "write-full.h"
892bd61e0fcc788390abfadd32b1897943290879dlezcano#include "doveadm.h"
953e611ceabed9ccf986e0b234379c2af4bb331aJames Hunt
953e611ceabed9ccf986e0b234379c2af4bb331aJames Hunt#include <unistd.h>
953e611ceabed9ccf986e0b234379c2af4bb331aJames Hunt#include <fcntl.h>
953e611ceabed9ccf986e0b234379c2af4bb331aJames Hunt#include <signal.h>
5c320b769229d713e84b02ed6b7ae1309ac31dbbGuido Trotter
55fc19a1042bca36ae431cb4a51c2abc0ca4d801Stéphane Graber#define MASTER_PID_FILE_NAME "master.pid"
55fc19a1042bca36ae431cb4a51c2abc0ca4d801Stéphane Graber
c13c0e08da7dbfecb52e85233ac6cd17afa5d818Stéphane Graberstatic bool pid_file_read(const char *path, pid_t *pid_r)
892bd61e0fcc788390abfadd32b1897943290879dlezcano{
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano char buf[32];
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano int fd;
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber ssize_t ret;
a6adab20ff4b58887ff1d4314c5736f54e139386Stéphane Graber bool found;
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber fd = open(path, O_RDONLY);
735f2c6e504a541cbb2592a3f94858bf337a24ffTycho Andersen if (fd == -1) {
ff5e27510540a2ee3c66d8496996313d01bb848fStéphane Graber if (errno == ENOENT)
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber return FALSE;
2b47bac3f81af9eb8ba392867c78fe3dec40a36aChristian Brauner i_fatal("open(%s) failed: %m", path);
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano }
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano
03f09a8ada8dcf15923b5913ec832e005179f962Wolfgang Bumiller ret = read(fd, buf, sizeof(buf)-1);
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano if (ret <= 0) {
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber if (ret == 0)
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber i_error("Empty PID file in %s", path);
94891ea3e44961f4369a7cc67d38c3a98a0e4c54Stéphane Graber else
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber i_fatal("read(%s) failed: %m", path);
813a4837659d5d7a2c0d0abe03c87196747217e9Serge Hallyn found = FALSE;
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano } else {
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano if (buf[ret-1] == '\n')
e71549fc7e1455d7bb8d7bdb26b9276093fd27c6Stéphane Graber ret--;
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano buf[ret] = '\0';
810567bbbe283c547e4ac837545d1e592916df26Serge Hallyn if (str_to_pid(buf, pid_r) < 0)
df3415e02282317348bbd5f9ce66d03e1c81eeecSerge Hallyn found = FALSE;
adade80c7e74c5185f63ff009116bf9d30c79876Serge Hallyn else {
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano found = !(*pid_r == getpid() ||
8a67a2b2eaf28033962a432c214bd3303c29c54cdlezcano (kill(*pid_r, 0) < 0 && errno == ESRCH));
8b8b04f80adf21480c25deb1aae263049ddd6754dlezcano }
55fc19a1042bca36ae431cb4a51c2abc0ca4d801Stéphane Graber }
55fc19a1042bca36ae431cb4a51c2abc0ca4d801Stéphane Graber i_close_fd(&fd);
df3415e02282317348bbd5f9ce66d03e1c81eeecSerge Hallyn return found;
8b8b04f80adf21480c25deb1aae263049ddd6754dlezcano}
8b8b04f80adf21480c25deb1aae263049ddd6754dlezcano
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcanovoid doveadm_master_send_signal(int signo)
d0a6bd39400a6d14cfec94ad647f3af1bda1e321Christian Brauner{
d0a6bd39400a6d14cfec94ad647f3af1bda1e321Christian Brauner const char *pidfile_path;
6a85cf91247b7dd9c3faeddceca8dacb96d02cd6Stéphane Graber unsigned int i;
4019712d198a7d50b08b326ade17f5ff1666efbbStéphane Graber pid_t pid;
6a85cf91247b7dd9c3faeddceca8dacb96d02cd6Stéphane Graber
d0a6bd39400a6d14cfec94ad647f3af1bda1e321Christian Brauner pidfile_path = t_strconcat(doveadm_settings->base_dir,
d1de19abd0067f38bc08a4a3357de701a4e5571ddlezcano "/"MASTER_PID_FILE_NAME, NULL);
aa8d013ec5b09cd1cd904173d6234ef126eb2126Peter Simons
7822022c4c72cee06905b540b89b653491d6f6b2Stéphane Graber if (!pid_file_read(pidfile_path, &pid))
6a85cf91247b7dd9c3faeddceca8dacb96d02cd6Stéphane Graber i_fatal("Dovecot is not running (read from %s)", pidfile_path);
8a67a2b2eaf28033962a432c214bd3303c29c54cdlezcano
aa8d013ec5b09cd1cd904173d6234ef126eb2126Peter Simons if (kill(pid, signo) < 0)
7822022c4c72cee06905b540b89b653491d6f6b2Stéphane Graber i_fatal("kill(%s, %d) failed: %m", dec2str(pid), signo);
6a85cf91247b7dd9c3faeddceca8dacb96d02cd6Stéphane Graber
8a67a2b2eaf28033962a432c214bd3303c29c54cdlezcano if (signo == SIGTERM) {
aa8d013ec5b09cd1cd904173d6234ef126eb2126Peter Simons /* wait for a while for the process to die */
7822022c4c72cee06905b540b89b653491d6f6b2Stéphane Graber usleep(1000);
6a85cf91247b7dd9c3faeddceca8dacb96d02cd6Stéphane Graber for (i = 0; i < 30; i++) {
99e4008cad9e959b683c6f48411fcf15a92be3b5Michel Normand if (kill(pid, 0) < 0) {
10fba81b9d0221b8e47aa1e0b43236413b7d28dfMichel Normand if (errno != ESRCH)
8b8b04f80adf21480c25deb1aae263049ddd6754dlezcano i_error("kill() failed: %m");
9a42db48e0bcf4f34b05a3de1cda23e06f51d131Stéphane Graber break;
3b9246c4aae3f7602c0ad64f5b1204eb559e5b07Daniel Lezcano }
892bd61e0fcc788390abfadd32b1897943290879dlezcano usleep(100000);
}
}
}
static void cmd_stop(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
{
doveadm_master_send_signal(SIGTERM);
}
static void cmd_reload(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
{
doveadm_master_send_signal(SIGHUP);
}
static struct istream *master_service_send_cmd(const char *cmd)
{
const char *path;
path = t_strconcat(doveadm_settings->base_dir, "/master", NULL);
int fd = net_connect_unix(path);
if (fd == -1)
i_fatal("net_connect_unix(%s) failed: %m", path);
net_set_nonblock(fd, FALSE);
const char *str =
t_strdup_printf("VERSION\tmaster-client\t1\t0\n%s\n", cmd);
if (write_full(fd, str, strlen(str)) < 0)
i_error("write(%s) failed: %m", path);
return i_stream_create_fd_autoclose(&fd, IO_BLOCK_SIZE);
}
static void cmd_service_stop(struct doveadm_cmd_context *cctx)
{
const char *line, *const *services;
if (!doveadm_cmd_param_array(cctx, "service", &services))
i_fatal("service parameter missing");
string_t *cmd = t_str_new(128);
str_append(cmd, "STOP");
for (unsigned int i = 0; services[i] != NULL; i++) {
str_append_c(cmd, '\t');
str_append(cmd, services[i]);
}
struct istream *input = master_service_send_cmd(str_c(cmd));
alarm(5);
if (i_stream_read_next_line(input) == NULL ||
(line = i_stream_read_next_line(input)) == NULL) {
i_error("read(%s) failed: %s", i_stream_get_name(input),
i_stream_get_error(input));
doveadm_exit_code = EX_TEMPFAIL;
} else if (line[0] == '-') {
doveadm_exit_code = DOVEADM_EX_NOTFOUND;
i_error("%s", line+1);
} else if (line[0] != '+') {
i_error("Unexpected input from %s: %s",
i_stream_get_name(input), line);
doveadm_exit_code = EX_TEMPFAIL;
}
alarm(0);
i_stream_destroy(&input);
}
struct doveadm_cmd_ver2 doveadm_cmd_stop_ver2 = {
.old_cmd = cmd_stop,
.name = "stop",
.usage = "",
DOVEADM_CMD_PARAMS_START
DOVEADM_CMD_PARAMS_END
};
struct doveadm_cmd_ver2 doveadm_cmd_reload_ver2 = {
.old_cmd = cmd_reload,
.name = "reload",
.usage = "",
DOVEADM_CMD_PARAMS_START
DOVEADM_CMD_PARAMS_END
};
struct doveadm_cmd_ver2 doveadm_cmd_service_stop_ver2 = {
.cmd = cmd_service_stop,
.name = "service stop",
.usage = "<service> [<service> [...]]",
DOVEADM_CMD_PARAMS_START
DOVEADM_CMD_PARAM('\0', "service", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL)
DOVEADM_CMD_PARAMS_END
};