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