mirror of
https://github.com/systemd/systemd.git
synced 2025-03-22 06:50:18 +03:00
execute: make kill mode configurable
This commit is contained in:
parent
09082a94b6
commit
50159e6a77
24
cgroup.c
24
cgroup.c
@ -174,13 +174,19 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) {
|
||||
int r;
|
||||
Set *s;
|
||||
bool done;
|
||||
bool killed = false;
|
||||
|
||||
assert(b);
|
||||
assert(sig > 0);
|
||||
|
||||
if (!b->only_us)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
|
||||
return -ENOMEM;
|
||||
|
||||
log_debug("Killing processes from process group %s:%s", b->controller, b->path);
|
||||
|
||||
do {
|
||||
void *iterator;
|
||||
pid_t pid;
|
||||
@ -208,6 +214,7 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) {
|
||||
break;
|
||||
}
|
||||
|
||||
killed = true;
|
||||
done = false;
|
||||
|
||||
if ((r = set_put(s, INT_TO_PTR(pid))) < 0)
|
||||
@ -235,20 +242,29 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) {
|
||||
} while (!done && r >= 0);
|
||||
|
||||
set_free(s);
|
||||
return r;
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return killed ? 0 : -ESRCH;
|
||||
}
|
||||
|
||||
int cgroup_bonding_kill_list(CGroupBonding *first, int sig) {
|
||||
CGroupBonding *b;
|
||||
int r = -EAGAIN;
|
||||
|
||||
LIST_FOREACH(by_unit, b, first) {
|
||||
int r;
|
||||
if ((r = cgroup_bonding_kill(b, sig)) < 0) {
|
||||
if (r == -EAGAIN || -ESRCH)
|
||||
continue;
|
||||
|
||||
if ((r = cgroup_bonding_kill(b, sig)) < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
|
||||
|
3
cgroup.h
3
cgroup.h
@ -37,9 +37,6 @@ struct CGroupBonding {
|
||||
|
||||
struct cgroup *cgroup;
|
||||
|
||||
/* When shutting down, kill all tasks? */
|
||||
bool kill_all:1;
|
||||
|
||||
/* When shutting down, remove cgroup? */
|
||||
bool clean_up:1;
|
||||
|
||||
|
@ -979,6 +979,32 @@ static int config_parse_sysv_priority(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_parse_kill_mode(
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
const char *lvalue,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
KillMode *m = data, x;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if ((x = kill_mode_from_string(rvalue)) < 0) {
|
||||
log_error("[%s:%u] Failed to parse kill mode specifier: %s", filename, line, rvalue);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
*m = x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FOLLOW_MAX 8
|
||||
|
||||
static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
|
||||
@ -1177,6 +1203,7 @@ static int load_from_path(Unit *u, const char *path, UnitLoadState *new_state) {
|
||||
{ "RootDirectoryStartOnly", config_parse_bool, &u->service.root_directory_start_only, "Service" },
|
||||
{ "ValidNoProcess", config_parse_bool, &u->service.valid_no_process, "Service" },
|
||||
{ "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" },
|
||||
{ "KillMode", config_parse_kill_mode, &u->service.kill_mode, "Service" },
|
||||
EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
|
||||
|
||||
{ "ListenStream", config_parse_listen, &u->socket, "Socket" },
|
||||
@ -1192,6 +1219,7 @@ static int load_from_path(Unit *u, const char *path, UnitLoadState *new_state) {
|
||||
{ "ExecStopPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" },
|
||||
{ "DirectoryMode", config_parse_mode, &u->socket.directory_mode, "Socket" },
|
||||
{ "SocketMode", config_parse_mode, &u->socket.socket_mode, "Socket" },
|
||||
{ "KillMode", config_parse_kill_mode, &u->socket.kill_mode, "Socket" },
|
||||
EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
|
||||
|
||||
EXEC_CONTEXT_CONFIG_ITEMS(u->automount.exec_context, "Automount"),
|
||||
|
47
service.c
47
service.c
@ -700,8 +700,12 @@ static int service_init(Unit *u, UnitLoadState *new_state) {
|
||||
s->sysv_start_priority = -1;
|
||||
s->permissions_start_only = false;
|
||||
s->root_directory_start_only = false;
|
||||
|
||||
s->valid_no_process = false;
|
||||
s->kill_mode = 0;
|
||||
s->sysv_has_lsb = false;
|
||||
s->main_pid = s->control_pid = 0;
|
||||
s->main_pid_known = false;
|
||||
s->failure = false;
|
||||
|
||||
RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
|
||||
|
||||
@ -755,11 +759,13 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sPermissionsStartOnly: %s\n"
|
||||
"%sRootDirectoryStartOnly: %s\n"
|
||||
"%sValidNoProcess: %s\n"
|
||||
"%sKillMode: %s\n"
|
||||
"%sType: %s\n",
|
||||
prefix, service_state_to_string(s->state),
|
||||
prefix, yes_no(s->permissions_start_only),
|
||||
prefix, yes_no(s->root_directory_start_only),
|
||||
prefix, yes_no(s->valid_no_process),
|
||||
prefix, kill_mode_to_string(s->kill_mode),
|
||||
prefix, service_type_to_string(s->type));
|
||||
|
||||
if (s->pid_file)
|
||||
@ -1154,23 +1160,34 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) {
|
||||
|
||||
sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
|
||||
|
||||
r = 0;
|
||||
if (s->main_pid > 0) {
|
||||
if (kill(s->main_pid, sig) < 0 && errno != ESRCH)
|
||||
r = -errno;
|
||||
else
|
||||
if (s->kill_mode == KILL_CONTROL_GROUP) {
|
||||
|
||||
if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
|
||||
if (r != -EAGAIN && r != -ESRCH)
|
||||
goto fail;
|
||||
} else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (s->control_pid > 0) {
|
||||
if (kill(s->control_pid, sig) < 0 && errno != ESRCH)
|
||||
r = -errno;
|
||||
else
|
||||
sent = true;
|
||||
}
|
||||
if (!sent) {
|
||||
r = 0;
|
||||
if (s->main_pid > 0) {
|
||||
if (kill(s->kill_mode == KILL_PROCESS ? s->main_pid : -s->main_pid, sig) < 0 && errno != ESRCH)
|
||||
r = -errno;
|
||||
else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (s->control_pid > 0) {
|
||||
if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH)
|
||||
r = -errno;
|
||||
else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
service_set_state(s, state);
|
||||
@ -1538,7 +1555,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
|
||||
}
|
||||
|
||||
log_debug("%s: main process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status);
|
||||
log_debug("%s: main process exited, code=%s, status=%i", unit_id(u), sigchld_code_to_string(code), status);
|
||||
|
||||
/* The service exited, so the service is officially
|
||||
* gone. */
|
||||
|
@ -94,6 +94,8 @@ struct Service {
|
||||
|
||||
ServiceState state;
|
||||
|
||||
KillMode kill_mode;
|
||||
|
||||
ExecStatus main_exec_status;
|
||||
|
||||
ExecCommand *control_command;
|
||||
|
23
socket.c
23
socket.c
@ -109,6 +109,9 @@ static int socket_init(Unit *u, UnitLoadState *new_state) {
|
||||
s->timeout_usec = DEFAULT_TIMEOUT_USEC;
|
||||
s->directory_mode = 0755;
|
||||
s->socket_mode = 0666;
|
||||
s->kill_mode = 0;
|
||||
s->failure = false;
|
||||
s->control_pid = 0;
|
||||
exec_context_init(&s->exec_context);
|
||||
|
||||
if ((r = unit_load_fragment(u, new_state)) < 0)
|
||||
@ -183,11 +186,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sSocket State: %s\n"
|
||||
"%sBindIPv6Only: %s\n"
|
||||
"%sBacklog: %u\n"
|
||||
"%sKillMode: %s\n"
|
||||
"%sSocketMode: %04o\n"
|
||||
"%sDirectoryMode: %04o\n",
|
||||
prefix, state_string_table[s->state],
|
||||
prefix, yes_no(s->bind_ipv6_only),
|
||||
prefix, s->backlog,
|
||||
prefix, kill_mode_to_string(s->kill_mode),
|
||||
prefix, s->socket_mode,
|
||||
prefix, s->directory_mode);
|
||||
|
||||
@ -471,13 +476,25 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) {
|
||||
|
||||
if (s->control_pid > 0) {
|
||||
int sig;
|
||||
bool sent = false;
|
||||
|
||||
sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_POST_SIGTERM) ? SIGTERM : SIGKILL;
|
||||
|
||||
if (kill(s->control_pid, sig) < 0 && errno != ESRCH) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
if (s->kill_mode == KILL_CONTROL_GROUP) {
|
||||
|
||||
if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
|
||||
if (r != -EAGAIN && r != -ESRCH)
|
||||
goto fail;
|
||||
} else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (!sent)
|
||||
if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
socket_set_state(s, state);
|
||||
|
2
socket.h
2
socket.h
@ -89,6 +89,8 @@ struct Socket {
|
||||
|
||||
SocketState state;
|
||||
|
||||
KillMode kill_mode;
|
||||
|
||||
ExecCommand* control_command;
|
||||
pid_t control_pid;
|
||||
|
||||
|
8
unit.c
8
unit.c
@ -1439,3 +1439,11 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
|
||||
|
||||
static const char* const kill_mode_table[_KILL_MODE_MAX] = {
|
||||
[KILL_PROCESS] = "process",
|
||||
[KILL_PROCESS_GROUP] = "process-group",
|
||||
[KILL_CONTROL_GROUP] = "control-group"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
|
||||
|
15
unit.h
15
unit.h
@ -43,6 +43,14 @@ typedef enum UnitDependency UnitDependency;
|
||||
#define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC)
|
||||
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
|
||||
|
||||
typedef enum KillMode {
|
||||
KILL_CONTROL_GROUP = 0,
|
||||
KILL_PROCESS_GROUP,
|
||||
KILL_PROCESS,
|
||||
_KILL_MODE_MAX,
|
||||
_KILL_MODE_INVALID = -1
|
||||
} KillMode;
|
||||
|
||||
enum UnitType {
|
||||
UNIT_SERVICE = 0,
|
||||
UNIT_TIMER,
|
||||
@ -53,7 +61,7 @@ enum UnitType {
|
||||
UNIT_AUTOMOUNT,
|
||||
UNIT_SNAPSHOT,
|
||||
_UNIT_TYPE_MAX,
|
||||
_UNIT_TYPE_INVALID = -1,
|
||||
_UNIT_TYPE_INVALID = -1
|
||||
};
|
||||
|
||||
enum UnitLoadState {
|
||||
@ -314,6 +322,8 @@ int set_unit_path(const char *p);
|
||||
|
||||
char *unit_name_escape_path(const char *path, const char *suffix);
|
||||
|
||||
char *unit_dbus_path(Unit *u);
|
||||
|
||||
const char *unit_type_to_string(UnitType i);
|
||||
UnitType unit_type_from_string(const char *s);
|
||||
|
||||
@ -326,6 +336,7 @@ UnitActiveState unit_active_state_from_string(const char *s);
|
||||
const char *unit_dependency_to_string(UnitDependency i);
|
||||
UnitDependency unit_dependency_from_string(const char *s);
|
||||
|
||||
char *unit_dbus_path(Unit *u);
|
||||
const char *kill_mode_to_string(KillMode k);
|
||||
KillMode kill_mode_from_string(const char *s);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user