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 void scope_init(Unit *u) {
47 assert(u->load_state == UNIT_STUB);
49 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
51 watch_init(&s->timer_watch);
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 unit_unwatch_timer(u, &s->timer_watch);
73 static void scope_set_state(Scope *s, ScopeState state) {
80 if (state != SCOPE_STOP_SIGTERM &&
81 state != SCOPE_STOP_SIGKILL)
82 unit_unwatch_timer(UNIT(s), &s->timer_watch);
84 if (state != old_state)
85 log_debug("%s changed %s -> %s",
87 scope_state_to_string(old_state),
88 scope_state_to_string(state));
90 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
93 static int scope_add_default_dependencies(Scope *s) {
98 /* Make sure scopes are unloaded on shutdown */
99 r = unit_add_two_dependencies_by_name(
101 UNIT_BEFORE, UNIT_CONFLICTS,
102 SPECIAL_SHUTDOWN_TARGET, NULL, true);
109 static int scope_verify(Scope *s) {
112 if (UNIT(s)->load_state != UNIT_LOADED)
115 if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
116 log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
123 static int scope_load(Unit *u) {
128 assert(u->load_state == UNIT_STUB);
130 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
133 u->load_state = UNIT_LOADED;
135 r = unit_load_dropin(u);
139 r = unit_add_default_slice(u);
143 if (u->default_dependencies) {
144 r = scope_add_default_dependencies(s);
149 return scope_verify(s);
152 static int scope_coldplug(Unit *u) {
157 assert(s->state == SCOPE_DEAD);
159 if (s->deserialized_state != s->state) {
161 if ((s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM)
162 && s->timeout_stop_usec > 0) {
163 r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch);
169 scope_set_state(s, s->deserialized_state);
175 static void scope_dump(Unit *u, FILE *f, const char *prefix) {
182 "%sScope State: %s\n"
184 prefix, scope_state_to_string(s->state),
185 prefix, scope_result_to_string(s->result));
187 cgroup_context_dump(&s->cgroup_context, f, prefix);
188 kill_context_dump(&s->kill_context, f, prefix);
191 static void scope_enter_dead(Scope *s, ScopeResult f) {
194 if (f != SCOPE_SUCCESS)
197 scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
200 static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
205 if (f != SCOPE_SUCCESS)
208 r = unit_kill_context(
211 state != SCOPE_STOP_SIGTERM,
217 if (s->timeout_stop_usec > 0) {
218 r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch);
223 scope_set_state(s, state);
225 scope_enter_dead(s, SCOPE_SUCCESS);
230 log_warning_unit(UNIT(s)->id,
231 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
233 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
236 static int scope_start(Unit *u) {
242 if (s->state == SCOPE_FAILED)
245 if (s->state == SCOPE_STOP_SIGTERM ||
246 s->state == SCOPE_STOP_SIGKILL)
249 assert(s->state == SCOPE_DEAD);
251 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
254 r = unit_realize_cgroup(u);
256 log_error("Failed to realize cgroup: %s", strerror(-r));
260 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
267 s->result = SCOPE_SUCCESS;
269 scope_set_state(s, SCOPE_RUNNING);
273 static int scope_stop(Unit *u) {
277 assert(s->state == SCOPE_RUNNING);
279 if (s->state == SCOPE_STOP_SIGTERM ||
280 s->state == SCOPE_STOP_SIGKILL)
283 assert(s->state == SCOPE_RUNNING);
285 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
289 static void scope_reset_failed(Unit *u) {
294 if (s->state == SCOPE_FAILED)
295 scope_set_state(s, SCOPE_DEAD);
297 s->result = SCOPE_SUCCESS;
300 static int scope_kill(Unit *u, KillWho who, int signo, DBusError *error) {
301 return unit_kill_common(u, who, signo, -1, -1, error);
304 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
311 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
315 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
323 if (streq(key, "state")) {
326 state = scope_state_from_string(value);
328 log_debug("Failed to parse state value %s", value);
330 s->deserialized_state = state;
333 log_debug("Unknown serialization key '%s'", key);
338 static bool scope_check_gc(Unit *u) {
344 /* Never clean up scopes that still have a process around,
345 * even if the scope is formally dead. */
347 if (UNIT(s)->cgroup_path) {
348 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
356 static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) {
360 assert(elapsed == 1);
361 assert(w == &s->timer_watch);
365 case SCOPE_STOP_SIGTERM:
366 if (s->kill_context.send_sigkill) {
367 log_warning_unit(u->id, "%s stopping timed out. Killing.", u->id);
368 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
370 log_warning_unit(u->id, "%s stopping timed out. Skipping SIGKILL.", u->id);
371 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
376 case SCOPE_STOP_SIGKILL:
377 log_warning_unit(u->id, "%s still around after SIGKILL. Ignoring.", u->id);
378 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
382 assert_not_reached("Timeout at wrong time.");
386 static void scope_notify_cgroup_empty_event(Unit *u) {
390 log_debug_unit(u->id, "%s: cgroup is empty", u->id);
395 case SCOPE_STOP_SIGTERM:
396 case SCOPE_STOP_SIGKILL:
397 scope_enter_dead(s, SCOPE_SUCCESS);
406 _pure_ static UnitActiveState scope_active_state(Unit *u) {
409 return state_translation_table[SCOPE(u)->state];
412 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
415 return scope_state_to_string(SCOPE(u)->state);
418 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
419 [SCOPE_DEAD] = "dead",
420 [SCOPE_RUNNING] = "running",
421 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
422 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
423 [SCOPE_FAILED] = "failed",
426 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
428 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
429 [SCOPE_SUCCESS] = "success",
430 [SCOPE_FAILURE_RESOURCES] = "resources",
431 [SCOPE_FAILURE_TIMEOUT] = "timeout",
434 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
436 const UnitVTable scope_vtable = {
437 .object_size = sizeof(Scope),
443 .private_section = "Scope",
444 .cgroup_context_offset = offsetof(Scope, cgroup_context),
447 .no_instances = true,
453 .coldplug = scope_coldplug,
457 .start = scope_start,
462 .serialize = scope_serialize,
463 .deserialize_item = scope_deserialize_item,
465 .active_state = scope_active_state,
466 .sub_state_to_string = scope_sub_state_to_string,
468 .check_gc = scope_check_gc,
470 .timer_event = scope_timer_event,
472 .reset_failed = scope_reset_failed,
474 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
476 .bus_interface = "org.freedesktop.systemd1.Scope",
477 .bus_message_handler = bus_scope_message_handler,
478 .bus_set_property = bus_scope_set_property,
479 .bus_commit_properties = bus_scope_commit_properties,
481 .can_transient = true