]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/scope.c
core: remove unused variables
[thirdparty/systemd.git] / src / core / scope.c
CommitLineData
6c12b52e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <errno.h>
23#include <signal.h>
24#include <unistd.h>
25
26#include "unit.h"
27#include "scope.h"
28#include "load-fragment.h"
29#include "log.h"
30#include "dbus-scope.h"
31#include "special.h"
32#include "unit-name.h"
33#include "load-dropin.h"
34
35static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
36 [SCOPE_DEAD] = UNIT_INACTIVE,
37 [SCOPE_RUNNING] = UNIT_ACTIVE,
a911bb9a 38 [SCOPE_ABANDONED] = UNIT_ACTIVE,
6c12b52e
LP
39 [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
40 [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
41 [SCOPE_FAILED] = UNIT_FAILED
42};
43
718db961
LP
44static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
45
6c12b52e
LP
46static void scope_init(Unit *u) {
47 Scope *s = SCOPE(u);
48
49 assert(u);
50 assert(u->load_state == UNIT_STUB);
51
1f19a534 52 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
6c12b52e 53
6c12b52e
LP
54 UNIT(s)->ignore_on_isolate = true;
55 UNIT(s)->ignore_on_snapshot = true;
56}
57
58static void scope_done(Unit *u) {
59 Scope *s = SCOPE(u);
60
61 assert(u);
62
2d4a39e7
LP
63 free(s->controller);
64
718db961
LP
65 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
66}
67
68static int scope_arm_timer(Scope *s) {
69 int r;
70
71 assert(s);
72
73 if (s->timeout_stop_usec <= 0) {
74 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
75 return 0;
76 }
77
78 if (s->timer_event_source) {
79 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
80 if (r < 0)
81 return r;
82
83 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
84 }
85
6a0f1f6d
LP
86 return sd_event_add_time(
87 UNIT(s)->manager->event,
88 &s->timer_event_source,
89 CLOCK_MONOTONIC,
90 now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
91 scope_dispatch_timer, s);
6c12b52e
LP
92}
93
94static void scope_set_state(Scope *s, ScopeState state) {
95 ScopeState old_state;
96 assert(s);
97
98 old_state = s->state;
99 s->state = state;
100
a911bb9a 101 if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
718db961 102 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
6c12b52e 103
a911bb9a
LP
104 if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
105 unit_unwatch_all_pids(UNIT(s));
106
6c12b52e 107 if (state != old_state)
a911bb9a 108 log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
6c12b52e
LP
109
110 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
111}
112
113static int scope_add_default_dependencies(Scope *s) {
114 int r;
115
116 assert(s);
117
118 /* Make sure scopes are unloaded on shutdown */
119 r = unit_add_two_dependencies_by_name(
120 UNIT(s),
121 UNIT_BEFORE, UNIT_CONFLICTS,
122 SPECIAL_SHUTDOWN_TARGET, NULL, true);
123 if (r < 0)
124 return r;
125
126 return 0;
127}
128
129static int scope_verify(Scope *s) {
130 assert(s);
131
132 if (UNIT(s)->load_state != UNIT_LOADED)
133 return 0;
134
a911bb9a 135 if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
79008bdd 136 log_unit_error(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
6c12b52e
LP
137 return -EINVAL;
138 }
139
140 return 0;
141}
142
143static int scope_load(Unit *u) {
144 Scope *s = SCOPE(u);
145 int r;
146
147 assert(s);
148 assert(u->load_state == UNIT_STUB);
149
150 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
151 return -ENOENT;
152
153 u->load_state = UNIT_LOADED;
154
155 r = unit_load_dropin(u);
156 if (r < 0)
157 return r;
158
598459ce
LP
159 r = unit_patch_contexts(u);
160 if (r < 0)
161 return r;
162
163 r = unit_add_default_slice(u, &s->cgroup_context);
6c12b52e
LP
164 if (r < 0)
165 return r;
166
167 if (u->default_dependencies) {
168 r = scope_add_default_dependencies(s);
169 if (r < 0)
170 return r;
171 }
172
173 return scope_verify(s);
174}
175
176static int scope_coldplug(Unit *u) {
177 Scope *s = SCOPE(u);
178 int r;
179
180 assert(s);
181 assert(s->state == SCOPE_DEAD);
182
183 if (s->deserialized_state != s->state) {
184
a911bb9a 185 if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
718db961 186 r = scope_arm_timer(s);
6c12b52e 187 if (r < 0)
6c12b52e
LP
188 return r;
189 }
190
a911bb9a
LP
191 if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
192 unit_watch_all_pids(UNIT(s));
193
6c12b52e
LP
194 scope_set_state(s, s->deserialized_state);
195 }
196
197 return 0;
198}
199
200static void scope_dump(Unit *u, FILE *f, const char *prefix) {
201 Scope *s = SCOPE(u);
202
203 assert(s);
204 assert(f);
205
206 fprintf(f,
207 "%sScope State: %s\n"
208 "%sResult: %s\n",
209 prefix, scope_state_to_string(s->state),
210 prefix, scope_result_to_string(s->result));
211
212 cgroup_context_dump(&s->cgroup_context, f, prefix);
213 kill_context_dump(&s->kill_context, f, prefix);
214}
215
216static void scope_enter_dead(Scope *s, ScopeResult f) {
217 assert(s);
218
219 if (f != SCOPE_SUCCESS)
220 s->result = f;
221
222 scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
223}
224
225static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
2d4a39e7 226 bool skip_signal = false;
6c12b52e
LP
227 int r;
228
229 assert(s);
230
231 if (f != SCOPE_SUCCESS)
232 s->result = f;
233
a911bb9a
LP
234 unit_watch_all_pids(UNIT(s));
235
2d4a39e7
LP
236 /* If we have a controller set let's ask the controller nicely
237 * to terminate the scope, instead of us going directly into
238 * SIGTERM beserk mode */
239 if (state == SCOPE_STOP_SIGTERM)
240 skip_signal = bus_scope_send_request_stop(s) > 0;
241
242 if (!skip_signal) {
243 r = unit_kill_context(
244 UNIT(s),
245 &s->kill_context,
db2cb23b 246 state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE,
2d4a39e7
LP
247 -1, -1, false);
248 if (r < 0)
249 goto fail;
250 } else
251 r = 1;
6c12b52e
LP
252
253 if (r > 0) {
718db961
LP
254 r = scope_arm_timer(s);
255 if (r < 0)
256 goto fail;
6c12b52e
LP
257
258 scope_set_state(s, state);
ac84d1fb
LP
259 } else if (state == SCOPE_STOP_SIGTERM)
260 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
261 else
6c12b52e
LP
262 scope_enter_dead(s, SCOPE_SUCCESS);
263
264 return;
265
266fail:
79008bdd 267 log_unit_warning(UNIT(s)->id,
6c12b52e
LP
268 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
269
270 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
271}
272
273static int scope_start(Unit *u) {
274 Scope *s = SCOPE(u);
275 int r;
276
277 assert(s);
278
7b617155
LP
279 if (s->state == SCOPE_FAILED)
280 return -EPERM;
281
6c12b52e
LP
282 if (s->state == SCOPE_STOP_SIGTERM ||
283 s->state == SCOPE_STOP_SIGKILL)
284 return -EAGAIN;
285
286 assert(s->state == SCOPE_DEAD);
287
288 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
289 return -ENOENT;
290
291 r = unit_realize_cgroup(u);
23bbb0de
MS
292 if (r < 0)
293 return log_error_errno(r, "Failed to realize cgroup: %m");
6c12b52e 294
a911bb9a 295 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, UNIT(s)->pids);
6c12b52e
LP
296 if (r < 0)
297 return r;
298
6c12b52e
LP
299 s->result = SCOPE_SUCCESS;
300
301 scope_set_state(s, SCOPE_RUNNING);
302 return 0;
303}
304
305static int scope_stop(Unit *u) {
306 Scope *s = SCOPE(u);
307
308 assert(s);
6c12b52e
LP
309
310 if (s->state == SCOPE_STOP_SIGTERM ||
311 s->state == SCOPE_STOP_SIGKILL)
312 return 0;
313
a911bb9a
LP
314 assert(s->state == SCOPE_RUNNING ||
315 s->state == SCOPE_ABANDONED);
6c12b52e
LP
316
317 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
318 return 0;
319}
320
8bcca7e2
LP
321static void scope_reset_failed(Unit *u) {
322 Scope *s = SCOPE(u);
323
324 assert(s);
325
326 if (s->state == SCOPE_FAILED)
327 scope_set_state(s, SCOPE_DEAD);
328
329 s->result = SCOPE_SUCCESS;
330}
331
718db961 332static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
6c12b52e
LP
333 return unit_kill_common(u, who, signo, -1, -1, error);
334}
335
68db7a3b
ZJS
336static int scope_get_timeout(Unit *u, uint64_t *timeout) {
337 Scope *s = SCOPE(u);
338 int r;
339
340 if (!s->timer_event_source)
341 return 0;
342
343 r = sd_event_source_get_time(s->timer_event_source, timeout);
344 if (r < 0)
345 return r;
346
347 return 1;
348}
349
6c12b52e
LP
350static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
351 Scope *s = SCOPE(u);
352
353 assert(s);
354 assert(f);
355 assert(fds);
356
357 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
358 return 0;
359}
360
361static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
362 Scope *s = SCOPE(u);
363
364 assert(u);
365 assert(key);
366 assert(value);
367 assert(fds);
368
369 if (streq(key, "state")) {
370 ScopeState state;
371
372 state = scope_state_from_string(value);
373 if (state < 0)
374 log_debug("Failed to parse state value %s", value);
375 else
376 s->deserialized_state = state;
377
378 } else
379 log_debug("Unknown serialization key '%s'", key);
380
381 return 0;
382}
383
384static bool scope_check_gc(Unit *u) {
4e2744fc 385 assert(u);
6c12b52e
LP
386
387 /* Never clean up scopes that still have a process around,
388 * even if the scope is formally dead. */
389
a911bb9a 390 if (u->cgroup_path) {
4e2744fc
RC
391 int r;
392
a911bb9a 393 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
6c12b52e
LP
394 if (r <= 0)
395 return true;
396 }
397
398 return false;
399}
400
a911bb9a
LP
401static void scope_notify_cgroup_empty_event(Unit *u) {
402 Scope *s = SCOPE(u);
403 assert(u);
404
79008bdd 405 log_unit_debug(u->id, "%s: cgroup is empty", u->id);
a911bb9a
LP
406
407 if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
408 scope_enter_dead(s, SCOPE_SUCCESS);
409}
410
411static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
412
413 /* If we get a SIGCHLD event for one of the processes we were
414 interested in, then we look for others to watch, under the
415 assumption that we'll sooner or later get a SIGCHLD for
416 them, as the original process we watched was probably the
417 parent of them, and they are hence now our children. */
418
419 unit_tidy_watch_pids(u, 0, 0);
420 unit_watch_all_pids(u);
421
422 /* If the PID set is empty now, then let's finish this off */
423 if (set_isempty(u->pids))
424 scope_notify_cgroup_empty_event(u);
425}
426
718db961
LP
427static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
428 Scope *s = SCOPE(userdata);
6c12b52e
LP
429
430 assert(s);
718db961 431 assert(s->timer_event_source == source);
6c12b52e
LP
432
433 switch (s->state) {
434
435 case SCOPE_STOP_SIGTERM:
436 if (s->kill_context.send_sigkill) {
79008bdd 437 log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
6c12b52e
LP
438 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
439 } else {
79008bdd 440 log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
6c12b52e
LP
441 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
442 }
443
444 break;
445
446 case SCOPE_STOP_SIGKILL:
79008bdd 447 log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
6c12b52e
LP
448 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
449 break;
450
451 default:
452 assert_not_reached("Timeout at wrong time.");
453 }
718db961
LP
454
455 return 0;
6c12b52e
LP
456}
457
a911bb9a
LP
458int scope_abandon(Scope *s) {
459 assert(s);
6c12b52e 460
a911bb9a
LP
461 if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
462 return -ESTALE;
6c12b52e 463
a911bb9a
LP
464 free(s->controller);
465 s->controller = NULL;
6c12b52e 466
a911bb9a
LP
467 /* The client is no longer watching the remaining processes,
468 * so let's step in here, under the assumption that the
469 * remaining processes will be sooner or later reassigned to
470 * us as parent. */
6c12b52e 471
a911bb9a
LP
472 unit_tidy_watch_pids(UNIT(s), 0, 0);
473 unit_watch_all_pids(UNIT(s));
6c12b52e 474
a911bb9a
LP
475 /* If the PID set is empty now, then let's finish this off */
476 if (set_isempty(UNIT(s)->pids))
477 scope_notify_cgroup_empty_event(UNIT(s));
478 else
479 scope_set_state(s, SCOPE_ABANDONED);
480
481 return 0;
6c12b52e
LP
482}
483
484_pure_ static UnitActiveState scope_active_state(Unit *u) {
485 assert(u);
486
487 return state_translation_table[SCOPE(u)->state];
488}
489
490_pure_ static const char *scope_sub_state_to_string(Unit *u) {
491 assert(u);
492
493 return scope_state_to_string(SCOPE(u)->state);
494}
495
496static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
497 [SCOPE_DEAD] = "dead",
358712f3 498 [SCOPE_RUNNING] = "running",
a911bb9a 499 [SCOPE_ABANDONED] = "abandoned",
6c12b52e
LP
500 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
501 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
502 [SCOPE_FAILED] = "failed",
503};
504
505DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
506
507static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
508 [SCOPE_SUCCESS] = "success",
509 [SCOPE_FAILURE_RESOURCES] = "resources",
510 [SCOPE_FAILURE_TIMEOUT] = "timeout",
511};
512
513DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
514
515const UnitVTable scope_vtable = {
516 .object_size = sizeof(Scope),
718db961
LP
517 .cgroup_context_offset = offsetof(Scope, cgroup_context),
518 .kill_context_offset = offsetof(Scope, kill_context),
519
6c12b52e
LP
520 .sections =
521 "Unit\0"
522 "Scope\0"
523 "Install\0",
6c12b52e 524 .private_section = "Scope",
6c12b52e
LP
525
526 .no_alias = true,
527 .no_instances = true,
528
529 .init = scope_init,
530 .load = scope_load,
531 .done = scope_done,
532
533 .coldplug = scope_coldplug,
534
535 .dump = scope_dump,
536
537 .start = scope_start,
538 .stop = scope_stop,
539
540 .kill = scope_kill,
541
68db7a3b
ZJS
542 .get_timeout = scope_get_timeout,
543
6c12b52e
LP
544 .serialize = scope_serialize,
545 .deserialize_item = scope_deserialize_item,
546
547 .active_state = scope_active_state,
548 .sub_state_to_string = scope_sub_state_to_string,
549
550 .check_gc = scope_check_gc,
551
a911bb9a
LP
552 .sigchld_event = scope_sigchld_event,
553
8bcca7e2
LP
554 .reset_failed = scope_reset_failed,
555
6c12b52e
LP
556 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
557
558 .bus_interface = "org.freedesktop.systemd1.Scope",
718db961 559 .bus_vtable = bus_scope_vtable,
6c12b52e
LP
560 .bus_set_property = bus_scope_set_property,
561 .bus_commit_properties = bus_scope_commit_properties,
562
563 .can_transient = true
564};