]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/scope.c
pam_systemd: Ignore vtnr when seat != seat0
[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,
38 [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
39 [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
40 [SCOPE_FAILED] = UNIT_FAILED
41};
42
718db961
LP
43static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
44
6c12b52e
LP
45static void scope_init(Unit *u) {
46 Scope *s = SCOPE(u);
47
48 assert(u);
49 assert(u->load_state == UNIT_STUB);
50
1f19a534 51 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
6c12b52e 52
6c12b52e
LP
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
60static 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
718db961
LP
70 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
71}
72
73static 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);
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
101 if (state != SCOPE_STOP_SIGTERM &&
102 state != SCOPE_STOP_SIGKILL)
718db961 103 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
6c12b52e
LP
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
114static 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
130static int scope_verify(Scope *s) {
131 assert(s);
132
133 if (UNIT(s)->load_state != UNIT_LOADED)
134 return 0;
135
0c5778a2 136 if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
6c12b52e
LP
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
144static 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
173static 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
718db961
LP
182 if (s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) {
183 r = scope_arm_timer(s);
6c12b52e 184 if (r < 0)
6c12b52e
LP
185 return r;
186 }
187
188 scope_set_state(s, s->deserialized_state);
189 }
190
191 return 0;
192}
193
194static 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
210static 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
219static 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) {
718db961
LP
236 r = scope_arm_timer(s);
237 if (r < 0)
238 goto fail;
6c12b52e
LP
239
240 scope_set_state(s, state);
241 } else
242 scope_enter_dead(s, SCOPE_SUCCESS);
243
244 return;
245
246fail:
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
253static int scope_start(Unit *u) {
254 Scope *s = SCOPE(u);
255 int r;
256
257 assert(s);
258
7b617155
LP
259 if (s->state == SCOPE_FAILED)
260 return -EPERM;
261
6c12b52e
LP
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
13b84ec7 277 r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
6c12b52e
LP
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
290static 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
8bcca7e2
LP
306static 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
718db961 317static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
6c12b52e
LP
318 return unit_kill_common(u, who, signo, -1, -1, error);
319}
320
321static 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
332static 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
355static 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
718db961
LP
373static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
374 Scope *s = SCOPE(userdata);
6c12b52e
LP
375
376 assert(s);
718db961 377 assert(s->timer_event_source == source);
6c12b52e
LP
378
379 switch (s->state) {
380
381 case SCOPE_STOP_SIGTERM:
382 if (s->kill_context.send_sigkill) {
718db961 383 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
6c12b52e
LP
384 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
385 } else {
718db961 386 log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
6c12b52e
LP
387 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
388 }
389
390 break;
391
392 case SCOPE_STOP_SIGKILL:
718db961 393 log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
6c12b52e
LP
394 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
395 break;
396
397 default:
398 assert_not_reached("Timeout at wrong time.");
399 }
718db961
LP
400
401 return 0;
6c12b52e
LP
402}
403
404static 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
436static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
437 [SCOPE_DEAD] = "dead",
358712f3 438 [SCOPE_RUNNING] = "running",
6c12b52e
LP
439 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
440 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
441 [SCOPE_FAILED] = "failed",
442};
443
444DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
445
446static 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
452DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
453
454const UnitVTable scope_vtable = {
455 .object_size = sizeof(Scope),
718db961
LP
456 .cgroup_context_offset = offsetof(Scope, cgroup_context),
457 .kill_context_offset = offsetof(Scope, kill_context),
458
6c12b52e
LP
459 .sections =
460 "Unit\0"
461 "Scope\0"
462 "Install\0",
6c12b52e 463 .private_section = "Scope",
6c12b52e
LP
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
8bcca7e2
LP
489 .reset_failed = scope_reset_failed,
490
6c12b52e
LP
491 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
492
493 .bus_interface = "org.freedesktop.systemd1.Scope",
718db961 494 .bus_vtable = bus_scope_vtable,
6c12b52e
LP
495 .bus_set_property = bus_scope_set_property,
496 .bus_commit_properties = bus_scope_commit_properties,
497
498 .can_transient = true
499};