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);
241 } else if (state == SCOPE_STOP_SIGTERM)
242 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
244 scope_enter_dead(s, SCOPE_SUCCESS);
249 log_warning_unit(UNIT(s)->id,
250 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
252 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
255 static int scope_start(Unit *u) {
261 if (s->state == SCOPE_FAILED)
264 if (s->state == SCOPE_STOP_SIGTERM ||
265 s->state == SCOPE_STOP_SIGKILL)
268 assert(s->state == SCOPE_DEAD);
270 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
273 r = unit_realize_cgroup(u);
275 log_error("Failed to realize cgroup: %s", strerror(-r));
279 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
286 s->result = SCOPE_SUCCESS;
288 scope_set_state(s, SCOPE_RUNNING);
292 static int scope_stop(Unit *u) {
296 assert(s->state == SCOPE_RUNNING);
298 if (s->state == SCOPE_STOP_SIGTERM ||
299 s->state == SCOPE_STOP_SIGKILL)
302 assert(s->state == SCOPE_RUNNING);
304 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
308 static void scope_reset_failed(Unit *u) {
313 if (s->state == SCOPE_FAILED)
314 scope_set_state(s, SCOPE_DEAD);
316 s->result = SCOPE_SUCCESS;
319 static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
320 return unit_kill_common(u, who, signo, -1, -1, error);
323 static int scope_get_timeout(Unit *u, uint64_t *timeout) {
327 if (!s->timer_event_source)
330 r = sd_event_source_get_time(s->timer_event_source, timeout);
337 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
344 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
348 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
356 if (streq(key, "state")) {
359 state = scope_state_from_string(value);
361 log_debug("Failed to parse state value %s", value);
363 s->deserialized_state = state;
366 log_debug("Unknown serialization key '%s'", key);
371 static bool scope_check_gc(Unit *u) {
377 /* Never clean up scopes that still have a process around,
378 * even if the scope is formally dead. */
380 if (UNIT(s)->cgroup_path) {
381 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
389 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
390 Scope *s = SCOPE(userdata);
393 assert(s->timer_event_source == source);
397 case SCOPE_STOP_SIGTERM:
398 if (s->kill_context.send_sigkill) {
399 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
400 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
402 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
403 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
408 case SCOPE_STOP_SIGKILL:
409 log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
410 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
414 assert_not_reached("Timeout at wrong time.");
420 static void scope_notify_cgroup_empty_event(Unit *u) {
424 log_debug_unit(u->id, "%s: cgroup is empty", u->id);
429 case SCOPE_STOP_SIGTERM:
430 case SCOPE_STOP_SIGKILL:
431 scope_enter_dead(s, SCOPE_SUCCESS);
440 _pure_ static UnitActiveState scope_active_state(Unit *u) {
443 return state_translation_table[SCOPE(u)->state];
446 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
449 return scope_state_to_string(SCOPE(u)->state);
452 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
453 [SCOPE_DEAD] = "dead",
454 [SCOPE_RUNNING] = "running",
455 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
456 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
457 [SCOPE_FAILED] = "failed",
460 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
462 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
463 [SCOPE_SUCCESS] = "success",
464 [SCOPE_FAILURE_RESOURCES] = "resources",
465 [SCOPE_FAILURE_TIMEOUT] = "timeout",
468 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
470 const UnitVTable scope_vtable = {
471 .object_size = sizeof(Scope),
472 .cgroup_context_offset = offsetof(Scope, cgroup_context),
473 .kill_context_offset = offsetof(Scope, kill_context),
479 .private_section = "Scope",
482 .no_instances = true,
488 .coldplug = scope_coldplug,
492 .start = scope_start,
497 .get_timeout = scope_get_timeout,
499 .serialize = scope_serialize,
500 .deserialize_item = scope_deserialize_item,
502 .active_state = scope_active_state,
503 .sub_state_to_string = scope_sub_state_to_string,
505 .check_gc = scope_check_gc,
507 .reset_failed = scope_reset_failed,
509 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
511 .bus_interface = "org.freedesktop.systemd1.Scope",
512 .bus_vtable = bus_scope_vtable,
513 .bus_set_property = bus_scope_set_property,
514 .bus_commit_properties = bus_scope_commit_properties,
516 .can_transient = true