chiark / gitweb /
journalctl(1): s/adm/systemd-journal/
[elogind.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 void scope_init(Unit *u) {
44         Scope *s = SCOPE(u);
45
46         assert(u);
47         assert(u->load_state == UNIT_STUB);
48
49         s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
50
51         watch_init(&s->timer_watch);
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         unit_unwatch_timer(u, &s->timer_watch);
71 }
72
73 static void scope_set_state(Scope *s, ScopeState state) {
74         ScopeState old_state;
75         assert(s);
76
77         old_state = s->state;
78         s->state = state;
79
80         if (state != SCOPE_STOP_SIGTERM &&
81             state != SCOPE_STOP_SIGKILL)
82                 unit_unwatch_timer(UNIT(s), &s->timer_watch);
83
84         if (state != old_state)
85                 log_debug("%s changed %s -> %s",
86                           UNIT(s)->id,
87                           scope_state_to_string(old_state),
88                           scope_state_to_string(state));
89
90         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
91 }
92
93 static int scope_add_default_dependencies(Scope *s) {
94         int r;
95
96         assert(s);
97
98         /* Make sure scopes are unloaded on shutdown */
99         r = unit_add_two_dependencies_by_name(
100                         UNIT(s),
101                         UNIT_BEFORE, UNIT_CONFLICTS,
102                         SPECIAL_SHUTDOWN_TARGET, NULL, true);
103         if (r < 0)
104                 return r;
105
106         return 0;
107 }
108
109 static int scope_verify(Scope *s) {
110         assert(s);
111
112         if (UNIT(s)->load_state != UNIT_LOADED)
113                 return 0;
114
115         if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
116                 log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
117                 return -EINVAL;
118         }
119
120         return 0;
121 }
122
123 static int scope_load(Unit *u) {
124         Scope *s = SCOPE(u);
125         int r;
126
127         assert(s);
128         assert(u->load_state == UNIT_STUB);
129
130         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
131                 return -ENOENT;
132
133         u->load_state = UNIT_LOADED;
134
135         r = unit_load_dropin(u);
136         if (r < 0)
137                 return r;
138
139         r = unit_add_default_slice(u);
140         if (r < 0)
141                 return r;
142
143         if (u->default_dependencies) {
144                 r = scope_add_default_dependencies(s);
145                 if (r < 0)
146                         return r;
147         }
148
149         return scope_verify(s);
150 }
151
152 static int scope_coldplug(Unit *u) {
153         Scope *s = SCOPE(u);
154         int r;
155
156         assert(s);
157         assert(s->state == SCOPE_DEAD);
158
159         if (s->deserialized_state != s->state) {
160
161                 if ((s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM)
162                     && s->timeout_stop_usec > 0) {
163                         r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch);
164                         if (r < 0)
165
166                                 return r;
167                 }
168
169                 scope_set_state(s, s->deserialized_state);
170         }
171
172         return 0;
173 }
174
175 static void scope_dump(Unit *u, FILE *f, const char *prefix) {
176         Scope *s = SCOPE(u);
177
178         assert(s);
179         assert(f);
180
181         fprintf(f,
182                 "%sScope State: %s\n"
183                 "%sResult: %s\n",
184                 prefix, scope_state_to_string(s->state),
185                 prefix, scope_result_to_string(s->result));
186
187         cgroup_context_dump(&s->cgroup_context, f, prefix);
188         kill_context_dump(&s->kill_context, f, prefix);
189 }
190
191 static void scope_enter_dead(Scope *s, ScopeResult f) {
192         assert(s);
193
194         if (f != SCOPE_SUCCESS)
195                 s->result = f;
196
197         scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
198 }
199
200 static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
201         int r;
202
203         assert(s);
204
205         if (f != SCOPE_SUCCESS)
206                 s->result = f;
207
208         r = unit_kill_context(
209                         UNIT(s),
210                         &s->kill_context,
211                         state != SCOPE_STOP_SIGTERM,
212                         -1, -1, false);
213         if (r < 0)
214                 goto fail;
215
216         if (r > 0) {
217                 if (s->timeout_stop_usec > 0) {
218                         r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch);
219                         if (r < 0)
220                                 goto fail;
221                 }
222
223                 scope_set_state(s, state);
224         } else
225                 scope_enter_dead(s, SCOPE_SUCCESS);
226
227         return;
228
229 fail:
230         log_warning_unit(UNIT(s)->id,
231                          "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
232
233         scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
234 }
235
236 static int scope_start(Unit *u) {
237         Scope *s = SCOPE(u);
238         int r;
239
240         assert(s);
241
242         if (s->state == SCOPE_FAILED)
243                 return -EPERM;
244
245         if (s->state == SCOPE_STOP_SIGTERM ||
246             s->state == SCOPE_STOP_SIGKILL)
247                 return -EAGAIN;
248
249         assert(s->state == SCOPE_DEAD);
250
251         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
252                 return -ENOENT;
253
254         r = unit_realize_cgroup(u);
255         if (r < 0) {
256                 log_error("Failed to realize cgroup: %s", strerror(-r));
257                 return r;
258         }
259
260         r = cg_attach_many_with_mask(u->cgroup_mask, u->cgroup_path, s->pids);
261         if (r < 0)
262                 return r;
263
264         set_free(s->pids);
265         s->pids = NULL;
266
267         s->result = SCOPE_SUCCESS;
268
269         scope_set_state(s, SCOPE_RUNNING);
270         return 0;
271 }
272
273 static int scope_stop(Unit *u) {
274         Scope *s = SCOPE(u);
275
276         assert(s);
277         assert(s->state == SCOPE_RUNNING);
278
279         if (s->state == SCOPE_STOP_SIGTERM ||
280             s->state == SCOPE_STOP_SIGKILL)
281                 return 0;
282
283         assert(s->state == SCOPE_RUNNING);
284
285         scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
286         return 0;
287 }
288
289 static void scope_reset_failed(Unit *u) {
290         Scope *s = SCOPE(u);
291
292         assert(s);
293
294         if (s->state == SCOPE_FAILED)
295                 scope_set_state(s, SCOPE_DEAD);
296
297         s->result = SCOPE_SUCCESS;
298 }
299
300 static int scope_kill(Unit *u, KillWho who, int signo, DBusError *error) {
301         return unit_kill_common(u, who, signo, -1, -1, error);
302 }
303
304 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
305         Scope *s = SCOPE(u);
306
307         assert(s);
308         assert(f);
309         assert(fds);
310
311         unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
312         return 0;
313 }
314
315 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
316         Scope *s = SCOPE(u);
317
318         assert(u);
319         assert(key);
320         assert(value);
321         assert(fds);
322
323         if (streq(key, "state")) {
324                 ScopeState state;
325
326                 state = scope_state_from_string(value);
327                 if (state < 0)
328                         log_debug("Failed to parse state value %s", value);
329                 else
330                         s->deserialized_state = state;
331
332         } else
333                 log_debug("Unknown serialization key '%s'", key);
334
335         return 0;
336 }
337
338 static bool scope_check_gc(Unit *u) {
339         Scope *s = SCOPE(u);
340         int r;
341
342         assert(s);
343
344         /* Never clean up scopes that still have a process around,
345          * even if the scope is formally dead. */
346
347         if (UNIT(s)->cgroup_path) {
348                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
349                 if (r <= 0)
350                         return true;
351         }
352
353         return false;
354 }
355
356 static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) {
357         Scope *s = SCOPE(u);
358
359         assert(s);
360         assert(elapsed == 1);
361         assert(w == &s->timer_watch);
362
363         switch (s->state) {
364
365         case SCOPE_STOP_SIGTERM:
366                 if (s->kill_context.send_sigkill) {
367                         log_warning_unit(u->id, "%s stopping timed out. Killing.", u->id);
368                         scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
369                 } else {
370                         log_warning_unit(u->id, "%s stopping timed out. Skipping SIGKILL.", u->id);
371                         scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
372                 }
373
374                 break;
375
376         case SCOPE_STOP_SIGKILL:
377                 log_warning_unit(u->id, "%s still around after SIGKILL. Ignoring.", u->id);
378                 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
379                 break;
380
381         default:
382                 assert_not_reached("Timeout at wrong time.");
383         }
384 }
385
386 static void scope_notify_cgroup_empty_event(Unit *u) {
387         Scope *s = SCOPE(u);
388         assert(u);
389
390         log_debug_unit(u->id, "%s: cgroup is empty", u->id);
391
392         switch (s->state) {
393
394         case SCOPE_RUNNING:
395         case SCOPE_STOP_SIGTERM:
396         case SCOPE_STOP_SIGKILL:
397                 scope_enter_dead(s, SCOPE_SUCCESS);
398
399                 break;
400
401         default:
402                 ;
403         }
404 }
405
406 _pure_ static UnitActiveState scope_active_state(Unit *u) {
407         assert(u);
408
409         return state_translation_table[SCOPE(u)->state];
410 }
411
412 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
413         assert(u);
414
415         return scope_state_to_string(SCOPE(u)->state);
416 }
417
418 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
419         [SCOPE_DEAD] = "dead",
420         [SCOPE_RUNNING] = "running",
421         [SCOPE_STOP_SIGTERM] = "stop-sigterm",
422         [SCOPE_STOP_SIGKILL] = "stop-sigkill",
423         [SCOPE_FAILED] = "failed",
424 };
425
426 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
427
428 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
429         [SCOPE_SUCCESS] = "success",
430         [SCOPE_FAILURE_RESOURCES] = "resources",
431         [SCOPE_FAILURE_TIMEOUT] = "timeout",
432 };
433
434 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
435
436 const UnitVTable scope_vtable = {
437         .object_size = sizeof(Scope),
438         .sections =
439                 "Unit\0"
440                 "Scope\0"
441                 "Install\0",
442
443         .private_section = "Scope",
444         .cgroup_context_offset = offsetof(Scope, cgroup_context),
445
446         .no_alias = true,
447         .no_instances = true,
448
449         .init = scope_init,
450         .load = scope_load,
451         .done = scope_done,
452
453         .coldplug = scope_coldplug,
454
455         .dump = scope_dump,
456
457         .start = scope_start,
458         .stop = scope_stop,
459
460         .kill = scope_kill,
461
462         .serialize = scope_serialize,
463         .deserialize_item = scope_deserialize_item,
464
465         .active_state = scope_active_state,
466         .sub_state_to_string = scope_sub_state_to_string,
467
468         .check_gc = scope_check_gc,
469
470         .timer_event = scope_timer_event,
471
472         .reset_failed = scope_reset_failed,
473
474         .notify_cgroup_empty = scope_notify_cgroup_empty_event,
475
476         .bus_interface = "org.freedesktop.systemd1.Scope",
477         .bus_message_handler = bus_scope_message_handler,
478         .bus_set_property = bus_scope_set_property,
479         .bus_commit_properties = bus_scope_commit_properties,
480
481         .can_transient = true
482 };