]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/scope.c
core: convert PID 1 to libsystemd-bus
[thirdparty/systemd.git] / src / core / scope.c
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
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
41 };
42
43 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
44
45 static void scope_init(Unit *u) {
46 Scope *s = SCOPE(u);
47
48 assert(u);
49 assert(u->load_state == UNIT_STUB);
50
51 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
52
53 cgroup_context_init(&s->cgroup_context);
54 kill_context_init(&s->kill_context);
55
56 UNIT(s)->ignore_on_isolate = true;
57 UNIT(s)->ignore_on_snapshot = true;
58 }
59
60 static void scope_done(Unit *u) {
61 Scope *s = SCOPE(u);
62
63 assert(u);
64
65 cgroup_context_done(&s->cgroup_context);
66
67 set_free(s->pids);
68 s->pids = NULL;
69
70 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
71 }
72
73 static int scope_arm_timer(Scope *s) {
74 int r;
75
76 assert(s);
77
78 if (s->timeout_stop_usec <= 0) {
79 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
80 return 0;
81 }
82
83 if (s->timer_event_source) {
84 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
85 if (r < 0)
86 return r;
87
88 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
89 }
90
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);
92 }
93
94 static 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
101 if (state != SCOPE_STOP_SIGTERM &&
102 state != SCOPE_STOP_SIGKILL)
103 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
104
105 if (state != old_state)
106 log_debug("%s changed %s -> %s",
107 UNIT(s)->id,
108 scope_state_to_string(old_state),
109 scope_state_to_string(state));
110
111 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
112 }
113
114 static int scope_add_default_dependencies(Scope *s) {
115 int r;
116
117 assert(s);
118
119 /* Make sure scopes are unloaded on shutdown */
120 r = unit_add_two_dependencies_by_name(
121 UNIT(s),
122 UNIT_BEFORE, UNIT_CONFLICTS,
123 SPECIAL_SHUTDOWN_TARGET, NULL, true);
124 if (r < 0)
125 return r;
126
127 return 0;
128 }
129
130 static int scope_verify(Scope *s) {
131 assert(s);
132
133 if (UNIT(s)->load_state != UNIT_LOADED)
134 return 0;
135
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);
138 return -EINVAL;
139 }
140
141 return 0;
142 }
143
144 static int scope_load(Unit *u) {
145 Scope *s = SCOPE(u);
146 int r;
147
148 assert(s);
149 assert(u->load_state == UNIT_STUB);
150
151 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
152 return -ENOENT;
153
154 u->load_state = UNIT_LOADED;
155
156 r = unit_load_dropin(u);
157 if (r < 0)
158 return r;
159
160 r = unit_add_default_slice(u);
161 if (r < 0)
162 return r;
163
164 if (u->default_dependencies) {
165 r = scope_add_default_dependencies(s);
166 if (r < 0)
167 return r;
168 }
169
170 return scope_verify(s);
171 }
172
173 static int scope_coldplug(Unit *u) {
174 Scope *s = SCOPE(u);
175 int r;
176
177 assert(s);
178 assert(s->state == SCOPE_DEAD);
179
180 if (s->deserialized_state != s->state) {
181
182 if (s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) {
183 r = scope_arm_timer(s);
184 if (r < 0)
185 return r;
186 }
187
188 scope_set_state(s, s->deserialized_state);
189 }
190
191 return 0;
192 }
193
194 static void scope_dump(Unit *u, FILE *f, const char *prefix) {
195 Scope *s = SCOPE(u);
196
197 assert(s);
198 assert(f);
199
200 fprintf(f,
201 "%sScope State: %s\n"
202 "%sResult: %s\n",
203 prefix, scope_state_to_string(s->state),
204 prefix, scope_result_to_string(s->result));
205
206 cgroup_context_dump(&s->cgroup_context, f, prefix);
207 kill_context_dump(&s->kill_context, f, prefix);
208 }
209
210 static void scope_enter_dead(Scope *s, ScopeResult f) {
211 assert(s);
212
213 if (f != SCOPE_SUCCESS)
214 s->result = f;
215
216 scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
217 }
218
219 static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
220 int r;
221
222 assert(s);
223
224 if (f != SCOPE_SUCCESS)
225 s->result = f;
226
227 r = unit_kill_context(
228 UNIT(s),
229 &s->kill_context,
230 state != SCOPE_STOP_SIGTERM,
231 -1, -1, false);
232 if (r < 0)
233 goto fail;
234
235 if (r > 0) {
236 r = scope_arm_timer(s);
237 if (r < 0)
238 goto fail;
239
240 scope_set_state(s, state);
241 } else
242 scope_enter_dead(s, SCOPE_SUCCESS);
243
244 return;
245
246 fail:
247 log_warning_unit(UNIT(s)->id,
248 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
249
250 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
251 }
252
253 static int scope_start(Unit *u) {
254 Scope *s = SCOPE(u);
255 int r;
256
257 assert(s);
258
259 if (s->state == SCOPE_FAILED)
260 return -EPERM;
261
262 if (s->state == SCOPE_STOP_SIGTERM ||
263 s->state == SCOPE_STOP_SIGKILL)
264 return -EAGAIN;
265
266 assert(s->state == SCOPE_DEAD);
267
268 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
269 return -ENOENT;
270
271 r = unit_realize_cgroup(u);
272 if (r < 0) {
273 log_error("Failed to realize cgroup: %s", strerror(-r));
274 return r;
275 }
276
277 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
278 if (r < 0)
279 return r;
280
281 set_free(s->pids);
282 s->pids = NULL;
283
284 s->result = SCOPE_SUCCESS;
285
286 scope_set_state(s, SCOPE_RUNNING);
287 return 0;
288 }
289
290 static int scope_stop(Unit *u) {
291 Scope *s = SCOPE(u);
292
293 assert(s);
294 assert(s->state == SCOPE_RUNNING);
295
296 if (s->state == SCOPE_STOP_SIGTERM ||
297 s->state == SCOPE_STOP_SIGKILL)
298 return 0;
299
300 assert(s->state == SCOPE_RUNNING);
301
302 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
303 return 0;
304 }
305
306 static void scope_reset_failed(Unit *u) {
307 Scope *s = SCOPE(u);
308
309 assert(s);
310
311 if (s->state == SCOPE_FAILED)
312 scope_set_state(s, SCOPE_DEAD);
313
314 s->result = SCOPE_SUCCESS;
315 }
316
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);
319 }
320
321 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
322 Scope *s = SCOPE(u);
323
324 assert(s);
325 assert(f);
326 assert(fds);
327
328 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
329 return 0;
330 }
331
332 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
333 Scope *s = SCOPE(u);
334
335 assert(u);
336 assert(key);
337 assert(value);
338 assert(fds);
339
340 if (streq(key, "state")) {
341 ScopeState state;
342
343 state = scope_state_from_string(value);
344 if (state < 0)
345 log_debug("Failed to parse state value %s", value);
346 else
347 s->deserialized_state = state;
348
349 } else
350 log_debug("Unknown serialization key '%s'", key);
351
352 return 0;
353 }
354
355 static bool scope_check_gc(Unit *u) {
356 Scope *s = SCOPE(u);
357 int r;
358
359 assert(s);
360
361 /* Never clean up scopes that still have a process around,
362 * even if the scope is formally dead. */
363
364 if (UNIT(s)->cgroup_path) {
365 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
366 if (r <= 0)
367 return true;
368 }
369
370 return false;
371 }
372
373 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
374 Scope *s = SCOPE(userdata);
375
376 assert(s);
377 assert(s->timer_event_source == source);
378
379 switch (s->state) {
380
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);
385 } else {
386 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
387 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
388 }
389
390 break;
391
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);
395 break;
396
397 default:
398 assert_not_reached("Timeout at wrong time.");
399 }
400
401 return 0;
402 }
403
404 static void scope_notify_cgroup_empty_event(Unit *u) {
405 Scope *s = SCOPE(u);
406 assert(u);
407
408 log_debug_unit(u->id, "%s: cgroup is empty", u->id);
409
410 switch (s->state) {
411
412 case SCOPE_RUNNING:
413 case SCOPE_STOP_SIGTERM:
414 case SCOPE_STOP_SIGKILL:
415 scope_enter_dead(s, SCOPE_SUCCESS);
416
417 break;
418
419 default:
420 ;
421 }
422 }
423
424 _pure_ static UnitActiveState scope_active_state(Unit *u) {
425 assert(u);
426
427 return state_translation_table[SCOPE(u)->state];
428 }
429
430 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
431 assert(u);
432
433 return scope_state_to_string(SCOPE(u)->state);
434 }
435
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",
442 };
443
444 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
445
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",
450 };
451
452 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
453
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),
458
459 .sections =
460 "Unit\0"
461 "Scope\0"
462 "Install\0",
463 .private_section = "Scope",
464
465 .no_alias = true,
466 .no_instances = true,
467
468 .init = scope_init,
469 .load = scope_load,
470 .done = scope_done,
471
472 .coldplug = scope_coldplug,
473
474 .dump = scope_dump,
475
476 .start = scope_start,
477 .stop = scope_stop,
478
479 .kill = scope_kill,
480
481 .serialize = scope_serialize,
482 .deserialize_item = scope_deserialize_item,
483
484 .active_state = scope_active_state,
485 .sub_state_to_string = scope_sub_state_to_string,
486
487 .check_gc = scope_check_gc,
488
489 .reset_failed = scope_reset_failed,
490
491 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
492
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,
498
499 .can_transient = true
500 };