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