]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/scope.c
core: output unit status output strings to console, only if we actually are changing...
[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_ABANDONED] = UNIT_ACTIVE,
39 [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
40 [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
41 [SCOPE_FAILED] = UNIT_FAILED
42 };
43
44 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
45
46 static void scope_init(Unit *u) {
47 Scope *s = SCOPE(u);
48
49 assert(u);
50 assert(u->load_state == UNIT_STUB);
51
52 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
53
54 UNIT(s)->ignore_on_isolate = true;
55 UNIT(s)->ignore_on_snapshot = true;
56 }
57
58 static void scope_done(Unit *u) {
59 Scope *s = SCOPE(u);
60
61 assert(u);
62
63 free(s->controller);
64
65 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
66 }
67
68 static 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
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);
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 (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
102 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
103
104 if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
105 unit_unwatch_all_pids(UNIT(s));
106
107 if (state != old_state)
108 log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
109
110 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
111 }
112
113 static 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
129 static int scope_verify(Scope *s) {
130 assert(s);
131
132 if (UNIT(s)->load_state != UNIT_LOADED)
133 return 0;
134
135 if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
136 log_unit_error(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
137 return -EINVAL;
138 }
139
140 return 0;
141 }
142
143 static 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
159 r = unit_patch_contexts(u);
160 if (r < 0)
161 return r;
162
163 r = unit_add_default_slice(u, &s->cgroup_context);
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
176 static 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
185 if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
186 r = scope_arm_timer(s);
187 if (r < 0)
188 return r;
189 }
190
191 if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
192 unit_watch_all_pids(UNIT(s));
193
194 scope_set_state(s, s->deserialized_state);
195 }
196
197 return 0;
198 }
199
200 static 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
216 static 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
225 static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
226 bool skip_signal = false;
227 int r;
228
229 assert(s);
230
231 if (f != SCOPE_SUCCESS)
232 s->result = f;
233
234 unit_watch_all_pids(UNIT(s));
235
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,
246 state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE,
247 -1, -1, false);
248 if (r < 0)
249 goto fail;
250 } else
251 r = 1;
252
253 if (r > 0) {
254 r = scope_arm_timer(s);
255 if (r < 0)
256 goto fail;
257
258 scope_set_state(s, state);
259 } else if (state == SCOPE_STOP_SIGTERM)
260 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
261 else
262 scope_enter_dead(s, SCOPE_SUCCESS);
263
264 return;
265
266 fail:
267 log_unit_warning(UNIT(s)->id,
268 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
269
270 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
271 }
272
273 static int scope_start(Unit *u) {
274 Scope *s = SCOPE(u);
275 int r;
276
277 assert(s);
278
279 if (s->state == SCOPE_FAILED)
280 return -EPERM;
281
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_attach_pids_to_cgroup(u);
292 if (r < 0)
293 return r;
294
295 s->result = SCOPE_SUCCESS;
296
297 scope_set_state(s, SCOPE_RUNNING);
298 return 1;
299 }
300
301 static int scope_stop(Unit *u) {
302 Scope *s = SCOPE(u);
303
304 assert(s);
305
306 if (s->state == SCOPE_STOP_SIGTERM ||
307 s->state == SCOPE_STOP_SIGKILL)
308 return 0;
309
310 assert(s->state == SCOPE_RUNNING ||
311 s->state == SCOPE_ABANDONED);
312
313 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
314 return 1;
315 }
316
317 static void scope_reset_failed(Unit *u) {
318 Scope *s = SCOPE(u);
319
320 assert(s);
321
322 if (s->state == SCOPE_FAILED)
323 scope_set_state(s, SCOPE_DEAD);
324
325 s->result = SCOPE_SUCCESS;
326 }
327
328 static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
329 return unit_kill_common(u, who, signo, -1, -1, error);
330 }
331
332 static int scope_get_timeout(Unit *u, uint64_t *timeout) {
333 Scope *s = SCOPE(u);
334 int r;
335
336 if (!s->timer_event_source)
337 return 0;
338
339 r = sd_event_source_get_time(s->timer_event_source, timeout);
340 if (r < 0)
341 return r;
342
343 return 1;
344 }
345
346 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
347 Scope *s = SCOPE(u);
348
349 assert(s);
350 assert(f);
351 assert(fds);
352
353 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
354 return 0;
355 }
356
357 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
358 Scope *s = SCOPE(u);
359
360 assert(u);
361 assert(key);
362 assert(value);
363 assert(fds);
364
365 if (streq(key, "state")) {
366 ScopeState state;
367
368 state = scope_state_from_string(value);
369 if (state < 0)
370 log_debug("Failed to parse state value %s", value);
371 else
372 s->deserialized_state = state;
373
374 } else
375 log_debug("Unknown serialization key '%s'", key);
376
377 return 0;
378 }
379
380 static bool scope_check_gc(Unit *u) {
381 assert(u);
382
383 /* Never clean up scopes that still have a process around,
384 * even if the scope is formally dead. */
385
386 if (u->cgroup_path) {
387 int r;
388
389 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
390 if (r <= 0)
391 return true;
392 }
393
394 return false;
395 }
396
397 static void scope_notify_cgroup_empty_event(Unit *u) {
398 Scope *s = SCOPE(u);
399 assert(u);
400
401 log_unit_debug(u->id, "%s: cgroup is empty", u->id);
402
403 if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
404 scope_enter_dead(s, SCOPE_SUCCESS);
405 }
406
407 static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
408
409 /* If we get a SIGCHLD event for one of the processes we were
410 interested in, then we look for others to watch, under the
411 assumption that we'll sooner or later get a SIGCHLD for
412 them, as the original process we watched was probably the
413 parent of them, and they are hence now our children. */
414
415 unit_tidy_watch_pids(u, 0, 0);
416 unit_watch_all_pids(u);
417
418 /* If the PID set is empty now, then let's finish this off */
419 if (set_isempty(u->pids))
420 scope_notify_cgroup_empty_event(u);
421 }
422
423 static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
424 Scope *s = SCOPE(userdata);
425
426 assert(s);
427 assert(s->timer_event_source == source);
428
429 switch (s->state) {
430
431 case SCOPE_STOP_SIGTERM:
432 if (s->kill_context.send_sigkill) {
433 log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
434 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
435 } else {
436 log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
437 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
438 }
439
440 break;
441
442 case SCOPE_STOP_SIGKILL:
443 log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
444 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
445 break;
446
447 default:
448 assert_not_reached("Timeout at wrong time.");
449 }
450
451 return 0;
452 }
453
454 int scope_abandon(Scope *s) {
455 assert(s);
456
457 if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
458 return -ESTALE;
459
460 free(s->controller);
461 s->controller = NULL;
462
463 /* The client is no longer watching the remaining processes,
464 * so let's step in here, under the assumption that the
465 * remaining processes will be sooner or later reassigned to
466 * us as parent. */
467
468 unit_tidy_watch_pids(UNIT(s), 0, 0);
469 unit_watch_all_pids(UNIT(s));
470
471 /* If the PID set is empty now, then let's finish this off */
472 if (set_isempty(UNIT(s)->pids))
473 scope_notify_cgroup_empty_event(UNIT(s));
474 else
475 scope_set_state(s, SCOPE_ABANDONED);
476
477 return 0;
478 }
479
480 _pure_ static UnitActiveState scope_active_state(Unit *u) {
481 assert(u);
482
483 return state_translation_table[SCOPE(u)->state];
484 }
485
486 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
487 assert(u);
488
489 return scope_state_to_string(SCOPE(u)->state);
490 }
491
492 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
493 [SCOPE_DEAD] = "dead",
494 [SCOPE_RUNNING] = "running",
495 [SCOPE_ABANDONED] = "abandoned",
496 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
497 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
498 [SCOPE_FAILED] = "failed",
499 };
500
501 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
502
503 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
504 [SCOPE_SUCCESS] = "success",
505 [SCOPE_FAILURE_RESOURCES] = "resources",
506 [SCOPE_FAILURE_TIMEOUT] = "timeout",
507 };
508
509 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
510
511 const UnitVTable scope_vtable = {
512 .object_size = sizeof(Scope),
513 .cgroup_context_offset = offsetof(Scope, cgroup_context),
514 .kill_context_offset = offsetof(Scope, kill_context),
515
516 .sections =
517 "Unit\0"
518 "Scope\0"
519 "Install\0",
520 .private_section = "Scope",
521
522 .no_alias = true,
523 .no_instances = true,
524
525 .init = scope_init,
526 .load = scope_load,
527 .done = scope_done,
528
529 .coldplug = scope_coldplug,
530
531 .dump = scope_dump,
532
533 .start = scope_start,
534 .stop = scope_stop,
535
536 .kill = scope_kill,
537
538 .get_timeout = scope_get_timeout,
539
540 .serialize = scope_serialize,
541 .deserialize_item = scope_deserialize_item,
542
543 .active_state = scope_active_state,
544 .sub_state_to_string = scope_sub_state_to_string,
545
546 .check_gc = scope_check_gc,
547
548 .sigchld_event = scope_sigchld_event,
549
550 .reset_failed = scope_reset_failed,
551
552 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
553
554 .bus_interface = "org.freedesktop.systemd1.Scope",
555 .bus_vtable = bus_scope_vtable,
556 .bus_set_property = bus_scope_set_property,
557 .bus_commit_properties = bus_scope_commit_properties,
558
559 .can_transient = true
560 };