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_serialize(Unit *u, FILE *f, FDSet *fds) {
328 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
332 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
340 if (streq(key, "state")) {
343 state = scope_state_from_string(value);
345 log_debug("Failed to parse state value %s", value);
347 s->deserialized_state = state;
350 log_debug("Unknown serialization key '%s'", key);
355 static bool scope_check_gc(Unit *u) {
361 /* Never clean up scopes that still have a process around,
362 * even if the scope is formally dead. */
364 if (UNIT(s)->cgroup_path) {
365 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
373 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
374 Scope *s = SCOPE(userdata);
377 assert(s->timer_event_source == source);
381 case SCOPE_STOP_SIGTERM:
382 if (s->kill_context.send_sigkill) {
383 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
384 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
386 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
387 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
392 case SCOPE_STOP_SIGKILL:
393 log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
394 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
398 assert_not_reached("Timeout at wrong time.");
404 static void scope_notify_cgroup_empty_event(Unit *u) {
408 log_debug_unit(u->id, "%s: cgroup is empty", u->id);
413 case SCOPE_STOP_SIGTERM:
414 case SCOPE_STOP_SIGKILL:
415 scope_enter_dead(s, SCOPE_SUCCESS);
424 _pure_ static UnitActiveState scope_active_state(Unit *u) {
427 return state_translation_table[SCOPE(u)->state];
430 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
433 return scope_state_to_string(SCOPE(u)->state);
436 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
437 [SCOPE_DEAD] = "dead",
438 [SCOPE_RUNNING] = "running",
439 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
440 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
441 [SCOPE_FAILED] = "failed",
444 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
446 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
447 [SCOPE_SUCCESS] = "success",
448 [SCOPE_FAILURE_RESOURCES] = "resources",
449 [SCOPE_FAILURE_TIMEOUT] = "timeout",
452 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
454 const UnitVTable scope_vtable = {
455 .object_size = sizeof(Scope),
456 .cgroup_context_offset = offsetof(Scope, cgroup_context),
457 .kill_context_offset = offsetof(Scope, kill_context),
463 .private_section = "Scope",
466 .no_instances = true,
472 .coldplug = scope_coldplug,
476 .start = scope_start,
481 .serialize = scope_serialize,
482 .deserialize_item = scope_deserialize_item,
484 .active_state = scope_active_state,
485 .sub_state_to_string = scope_sub_state_to_string,
487 .check_gc = scope_check_gc,
489 .reset_failed = scope_reset_failed,
491 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
493 .bus_interface = "org.freedesktop.systemd1.Scope",
494 .bus_vtable = bus_scope_vtable,
495 .bus_changing_properties = bus_scope_changing_properties,
496 .bus_set_property = bus_scope_set_property,
497 .bus_commit_properties = bus_scope_commit_properties,
499 .can_transient = true