1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "load-fragment.h"
30 #include "dbus-scope.h"
32 #include "unit-name.h"
33 #include "load-dropin.h"
35 static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
36 [SCOPE_DEAD] = UNIT_INACTIVE,
37 [SCOPE_RUNNING] = UNIT_ACTIVE,
38 [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
39 [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
40 [SCOPE_FAILED] = UNIT_FAILED
43 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
45 static void scope_init(Unit *u) {
49 assert(u->load_state == UNIT_STUB);
51 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
53 cgroup_context_init(&s->cgroup_context);
54 kill_context_init(&s->kill_context);
56 UNIT(s)->ignore_on_isolate = true;
57 UNIT(s)->ignore_on_snapshot = true;
60 static void scope_done(Unit *u) {
65 cgroup_context_done(&s->cgroup_context);
70 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
73 static int scope_arm_timer(Scope *s) {
78 if (s->timeout_stop_usec <= 0) {
79 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
83 if (s->timer_event_source) {
84 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
88 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
91 return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0, scope_dispatch_timer, s, &s->timer_event_source);
94 static void scope_set_state(Scope *s, ScopeState state) {
101 if (state != SCOPE_STOP_SIGTERM &&
102 state != SCOPE_STOP_SIGKILL)
103 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
105 if (state != old_state)
106 log_debug("%s changed %s -> %s",
108 scope_state_to_string(old_state),
109 scope_state_to_string(state));
111 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
114 static int scope_add_default_dependencies(Scope *s) {
119 /* Make sure scopes are unloaded on shutdown */
120 r = unit_add_two_dependencies_by_name(
122 UNIT_BEFORE, UNIT_CONFLICTS,
123 SPECIAL_SHUTDOWN_TARGET, NULL, true);
130 static int scope_verify(Scope *s) {
133 if (UNIT(s)->load_state != UNIT_LOADED)
136 if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
137 log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
144 static int scope_load(Unit *u) {
149 assert(u->load_state == UNIT_STUB);
151 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
154 u->load_state = UNIT_LOADED;
156 r = unit_load_dropin(u);
160 r = unit_add_default_slice(u);
164 if (u->default_dependencies) {
165 r = scope_add_default_dependencies(s);
170 return scope_verify(s);
173 static int scope_coldplug(Unit *u) {
178 assert(s->state == SCOPE_DEAD);
180 if (s->deserialized_state != s->state) {
182 if (s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) {
183 r = scope_arm_timer(s);
188 scope_set_state(s, s->deserialized_state);
194 static void scope_dump(Unit *u, FILE *f, const char *prefix) {
201 "%sScope State: %s\n"
203 prefix, scope_state_to_string(s->state),
204 prefix, scope_result_to_string(s->result));
206 cgroup_context_dump(&s->cgroup_context, f, prefix);
207 kill_context_dump(&s->kill_context, f, prefix);
210 static void scope_enter_dead(Scope *s, ScopeResult f) {
213 if (f != SCOPE_SUCCESS)
216 scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
219 static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
224 if (f != SCOPE_SUCCESS)
227 r = unit_kill_context(
230 state != SCOPE_STOP_SIGTERM,
236 r = scope_arm_timer(s);
240 scope_set_state(s, state);
242 scope_enter_dead(s, SCOPE_SUCCESS);
247 log_warning_unit(UNIT(s)->id,
248 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
250 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
253 static int scope_start(Unit *u) {
259 if (s->state == SCOPE_FAILED)
262 if (s->state == SCOPE_STOP_SIGTERM ||
263 s->state == SCOPE_STOP_SIGKILL)
266 assert(s->state == SCOPE_DEAD);
268 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
271 r = unit_realize_cgroup(u);
273 log_error("Failed to realize cgroup: %s", strerror(-r));
277 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
284 s->result = SCOPE_SUCCESS;
286 scope_set_state(s, SCOPE_RUNNING);
290 static int scope_stop(Unit *u) {
294 assert(s->state == SCOPE_RUNNING);
296 if (s->state == SCOPE_STOP_SIGTERM ||
297 s->state == SCOPE_STOP_SIGKILL)
300 assert(s->state == SCOPE_RUNNING);
302 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
306 static void scope_reset_failed(Unit *u) {
311 if (s->state == SCOPE_FAILED)
312 scope_set_state(s, SCOPE_DEAD);
314 s->result = SCOPE_SUCCESS;
317 static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
318 return unit_kill_common(u, who, signo, -1, -1, error);
321 static int scope_get_timeout(Unit *u, uint64_t *timeout) {
325 if (!s->timer_event_source)
328 r = sd_event_source_get_time(s->timer_event_source, timeout);
335 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
342 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
346 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
354 if (streq(key, "state")) {
357 state = scope_state_from_string(value);
359 log_debug("Failed to parse state value %s", value);
361 s->deserialized_state = state;
364 log_debug("Unknown serialization key '%s'", key);
369 static bool scope_check_gc(Unit *u) {
375 /* Never clean up scopes that still have a process around,
376 * even if the scope is formally dead. */
378 if (UNIT(s)->cgroup_path) {
379 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
387 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
388 Scope *s = SCOPE(userdata);
391 assert(s->timer_event_source == source);
395 case SCOPE_STOP_SIGTERM:
396 if (s->kill_context.send_sigkill) {
397 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
398 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
400 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
401 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
406 case SCOPE_STOP_SIGKILL:
407 log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
408 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
412 assert_not_reached("Timeout at wrong time.");
418 static void scope_notify_cgroup_empty_event(Unit *u) {
422 log_debug_unit(u->id, "%s: cgroup is empty", u->id);
427 case SCOPE_STOP_SIGTERM:
428 case SCOPE_STOP_SIGKILL:
429 scope_enter_dead(s, SCOPE_SUCCESS);
438 _pure_ static UnitActiveState scope_active_state(Unit *u) {
441 return state_translation_table[SCOPE(u)->state];
444 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
447 return scope_state_to_string(SCOPE(u)->state);
450 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
451 [SCOPE_DEAD] = "dead",
452 [SCOPE_RUNNING] = "running",
453 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
454 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
455 [SCOPE_FAILED] = "failed",
458 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
460 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
461 [SCOPE_SUCCESS] = "success",
462 [SCOPE_FAILURE_RESOURCES] = "resources",
463 [SCOPE_FAILURE_TIMEOUT] = "timeout",
466 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
468 const UnitVTable scope_vtable = {
469 .object_size = sizeof(Scope),
470 .cgroup_context_offset = offsetof(Scope, cgroup_context),
471 .kill_context_offset = offsetof(Scope, kill_context),
477 .private_section = "Scope",
480 .no_instances = true,
486 .coldplug = scope_coldplug,
490 .start = scope_start,
495 .get_timeout = scope_get_timeout,
497 .serialize = scope_serialize,
498 .deserialize_item = scope_deserialize_item,
500 .active_state = scope_active_state,
501 .sub_state_to_string = scope_sub_state_to_string,
503 .check_gc = scope_check_gc,
505 .reset_failed = scope_reset_failed,
507 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
509 .bus_interface = "org.freedesktop.systemd1.Scope",
510 .bus_vtable = bus_scope_vtable,
511 .bus_set_property = bus_scope_set_property,
512 .bus_commit_properties = bus_scope_commit_properties,
514 .can_transient = true