chiark / gitweb /
scope: implement reset-failed command
[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) {
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_STOP_SIGTERM ||
243             s->state == SCOPE_STOP_SIGKILL)
244                 return -EAGAIN;
245
246         assert(s->state == SCOPE_DEAD);
247
248         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
249                 return -ENOENT;
250
251         r = unit_realize_cgroup(u);
252         if (r < 0) {
253                 log_error("Failed to realize cgroup: %s", strerror(-r));
254                 return r;
255         }
256
257         r = cg_attach_many_with_mask(u->cgroup_mask, u->cgroup_path, s->pids);
258         if (r < 0)
259                 return r;
260
261         set_free(s->pids);
262         s->pids = NULL;
263
264         s->result = SCOPE_SUCCESS;
265
266         scope_set_state(s, SCOPE_RUNNING);
267         return 0;
268 }
269
270 static int scope_stop(Unit *u) {
271         Scope *s = SCOPE(u);
272
273         assert(s);
274         assert(s->state == SCOPE_RUNNING);
275
276         if (s->state == SCOPE_STOP_SIGTERM ||
277             s->state == SCOPE_STOP_SIGKILL)
278                 return 0;
279
280         assert(s->state == SCOPE_RUNNING);
281
282         scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
283         return 0;
284 }
285
286 static void scope_reset_failed(Unit *u) {
287         Scope *s = SCOPE(u);
288
289         assert(s);
290
291         if (s->state == SCOPE_FAILED)
292                 scope_set_state(s, SCOPE_DEAD);
293
294         s->result = SCOPE_SUCCESS;
295 }
296
297 static int scope_kill(Unit *u, KillWho who, int signo, DBusError *error) {
298         return unit_kill_common(u, who, signo, -1, -1, error);
299 }
300
301 static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
302         Scope *s = SCOPE(u);
303
304         assert(s);
305         assert(f);
306         assert(fds);
307
308         unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
309         return 0;
310 }
311
312 static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
313         Scope *s = SCOPE(u);
314
315         assert(u);
316         assert(key);
317         assert(value);
318         assert(fds);
319
320         if (streq(key, "state")) {
321                 ScopeState state;
322
323                 state = scope_state_from_string(value);
324                 if (state < 0)
325                         log_debug("Failed to parse state value %s", value);
326                 else
327                         s->deserialized_state = state;
328
329         } else
330                 log_debug("Unknown serialization key '%s'", key);
331
332         return 0;
333 }
334
335 static bool scope_check_gc(Unit *u) {
336         Scope *s = SCOPE(u);
337         int r;
338
339         assert(s);
340
341         /* Never clean up scopes that still have a process around,
342          * even if the scope is formally dead. */
343
344         if (UNIT(s)->cgroup_path) {
345                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
346                 if (r <= 0)
347                         return true;
348         }
349
350         return false;
351 }
352
353 static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) {
354         Scope *s = SCOPE(u);
355
356         assert(s);
357         assert(elapsed == 1);
358         assert(w == &s->timer_watch);
359
360         switch (s->state) {
361
362         case SCOPE_STOP_SIGTERM:
363                 if (s->kill_context.send_sigkill) {
364                         log_warning_unit(u->id, "%s stopping timed out. Killing.", u->id);
365                         scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
366                 } else {
367                         log_warning_unit(u->id, "%s stopping timed out. Skipping SIGKILL.", u->id);
368                         scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
369                 }
370
371                 break;
372
373         case SCOPE_STOP_SIGKILL:
374                 log_warning_unit(u->id, "%s still around after SIGKILL. Ignoring.", u->id);
375                 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
376                 break;
377
378         default:
379                 assert_not_reached("Timeout at wrong time.");
380         }
381 }
382
383 static void scope_notify_cgroup_empty_event(Unit *u) {
384         Scope *s = SCOPE(u);
385         assert(u);
386
387         log_debug_unit(u->id, "%s: cgroup is empty", u->id);
388
389         switch (s->state) {
390
391         case SCOPE_RUNNING:
392         case SCOPE_STOP_SIGTERM:
393         case SCOPE_STOP_SIGKILL:
394                 scope_enter_dead(s, SCOPE_SUCCESS);
395
396                 break;
397
398         default:
399                 ;
400         }
401 }
402
403 _pure_ static UnitActiveState scope_active_state(Unit *u) {
404         assert(u);
405
406         return state_translation_table[SCOPE(u)->state];
407 }
408
409 _pure_ static const char *scope_sub_state_to_string(Unit *u) {
410         assert(u);
411
412         return scope_state_to_string(SCOPE(u)->state);
413 }
414
415 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
416         [SCOPE_DEAD] = "dead",
417         [SCOPE_RUNNING] = "active",
418         [SCOPE_STOP_SIGTERM] = "stop-sigterm",
419         [SCOPE_STOP_SIGKILL] = "stop-sigkill",
420         [SCOPE_FAILED] = "failed",
421 };
422
423 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
424
425 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
426         [SCOPE_SUCCESS] = "success",
427         [SCOPE_FAILURE_RESOURCES] = "resources",
428         [SCOPE_FAILURE_TIMEOUT] = "timeout",
429 };
430
431 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
432
433 const UnitVTable scope_vtable = {
434         .object_size = sizeof(Scope),
435         .sections =
436                 "Unit\0"
437                 "Scope\0"
438                 "Install\0",
439
440         .private_section = "Scope",
441         .cgroup_context_offset = offsetof(Scope, cgroup_context),
442
443         .no_alias = true,
444         .no_instances = true,
445
446         .init = scope_init,
447         .load = scope_load,
448         .done = scope_done,
449
450         .coldplug = scope_coldplug,
451
452         .dump = scope_dump,
453
454         .start = scope_start,
455         .stop = scope_stop,
456
457         .kill = scope_kill,
458
459         .serialize = scope_serialize,
460         .deserialize_item = scope_deserialize_item,
461
462         .active_state = scope_active_state,
463         .sub_state_to_string = scope_sub_state_to_string,
464
465         .check_gc = scope_check_gc,
466
467         .timer_event = scope_timer_event,
468
469         .reset_failed = scope_reset_failed,
470
471         .notify_cgroup_empty = scope_notify_cgroup_empty_event,
472
473         .bus_interface = "org.freedesktop.systemd1.Scope",
474         .bus_message_handler = bus_scope_message_handler,
475         .bus_set_property = bus_scope_set_property,
476         .bus_commit_properties = bus_scope_commit_properties,
477
478         .can_transient = true
479 };