]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/slice.c
slice, scope: IgnoreOnIsolate=yes is already the default
[thirdparty/systemd.git] / src / core / slice.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a016b922
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
a016b922 22
b5efdb8a 23#include "alloc-util.h"
07630cea 24#include "dbus-slice.h"
a016b922 25#include "log.h"
cf0fbc49 26#include "slice.h"
a016b922 27#include "special.h"
07630cea
LP
28#include "string-util.h"
29#include "strv.h"
a016b922 30#include "unit-name.h"
efdb0237 31#include "unit.h"
a016b922
LP
32
33static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
34 [SLICE_DEAD] = UNIT_INACTIVE,
35 [SLICE_ACTIVE] = UNIT_ACTIVE
36};
37
1b4cd0cf
LP
38static void slice_init(Unit *u) {
39 assert(u);
40 assert(u->load_state == UNIT_STUB);
41
42 u->ignore_on_isolate = true;
43}
44
a016b922
LP
45static void slice_set_state(Slice *t, SliceState state) {
46 SliceState old_state;
47 assert(t);
48
49 old_state = t->state;
50 t->state = state;
51
52 if (state != old_state)
53 log_debug("%s changed %s -> %s",
54 UNIT(t)->id,
55 slice_state_to_string(old_state),
56 slice_state_to_string(state));
57
58 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
59}
60
4ad49000 61static int slice_add_parent_slice(Slice *s) {
a7894207
ZJS
62 Unit *u = UNIT(s), *parent;
63 _cleanup_free_ char *a = NULL;
4ad49000 64 int r;
a016b922
LP
65
66 assert(s);
67
a7894207 68 if (UNIT_ISSET(u->slice))
a016b922
LP
69 return 0;
70
a7894207
ZJS
71 r = slice_build_parent_slice(u->id, &a);
72 if (r <= 0) /* 0 means root slice */
73 return r;
a016b922 74
a7894207 75 r = manager_load_unit(u->manager, a, NULL, NULL, &parent);
a016b922
LP
76 if (r < 0)
77 return r;
78
a7894207 79 unit_ref_set(&u->slice, parent);
a016b922
LP
80 return 0;
81}
82
83static int slice_add_default_dependencies(Slice *s) {
84 int r;
85
86 assert(s);
87
4c9ea260
LP
88 if (!UNIT(s)->default_dependencies)
89 return 0;
90
a016b922 91 /* Make sure slices are unloaded on shutdown */
6c12b52e
LP
92 r = unit_add_two_dependencies_by_name(
93 UNIT(s),
94 UNIT_BEFORE, UNIT_CONFLICTS,
eef85c4a 95 SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
a016b922
LP
96 if (r < 0)
97 return r;
98
99 return 0;
100}
101
102static int slice_verify(Slice *s) {
93c47472
LP
103 _cleanup_free_ char *parent = NULL;
104 int r;
105
a016b922
LP
106 assert(s);
107
108 if (UNIT(s)->load_state != UNIT_LOADED)
109 return 0;
110
93c47472 111 if (!slice_name_is_valid(UNIT(s)->id)) {
f2341e0a 112 log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id);
93c47472
LP
113 return -EINVAL;
114 }
115
116 r = slice_build_parent_slice(UNIT(s)->id, &parent);
117 if (r < 0)
f2341e0a 118 return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
93c47472
LP
119
120 if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
f2341e0a 121 log_unit_error(UNIT(s), "Located outside of parent slice. Refusing.");
93c47472 122 return -EINVAL;
a016b922
LP
123 }
124
125 return 0;
126}
127
8e4e851f
LP
128static int slice_load_root_slice(Unit *u) {
129 assert(u);
130
131 if (!unit_has_name(u, SPECIAL_ROOT_SLICE))
132 return 0;
133
f5869324 134 u->perpetual = true;
8e4e851f
LP
135
136 /* The root slice is a bit special. For example it is always running and cannot be terminated. Because of its
137 * special semantics we synthesize it here, instead of relying on the unit file on disk. */
138
139 u->default_dependencies = false;
8e4e851f
LP
140
141 if (!u->description)
142 u->description = strdup("Root Slice");
143 if (!u->documentation)
144 u->documentation = strv_new("man:systemd.special(7)", NULL);
145
146 return 1;
147}
148
a016b922
LP
149static int slice_load(Unit *u) {
150 Slice *s = SLICE(u);
151 int r;
152
153 assert(s);
4f4afc88 154 assert(u->load_state == UNIT_STUB);
a016b922 155
8e4e851f
LP
156 r = slice_load_root_slice(u);
157 if (r < 0)
158 return r;
4ad49000 159 r = unit_load_fragment_and_dropin_optional(u);
a016b922
LP
160 if (r < 0)
161 return r;
162
163 /* This is a new unit? Then let's add in some extras */
164 if (u->load_state == UNIT_LOADED) {
165
598459ce
LP
166 r = unit_patch_contexts(u);
167 if (r < 0)
168 return r;
169
4ad49000 170 r = slice_add_parent_slice(s);
a016b922
LP
171 if (r < 0)
172 return r;
173
4c9ea260
LP
174 r = slice_add_default_dependencies(s);
175 if (r < 0)
176 return r;
a016b922
LP
177 }
178
179 return slice_verify(s);
180}
181
be847e82 182static int slice_coldplug(Unit *u) {
a016b922
LP
183 Slice *t = SLICE(u);
184
185 assert(t);
186 assert(t->state == SLICE_DEAD);
187
188 if (t->deserialized_state != t->state)
189 slice_set_state(t, t->deserialized_state);
190
191 return 0;
192}
193
194static void slice_dump(Unit *u, FILE *f, const char *prefix) {
195 Slice *t = SLICE(u);
196
197 assert(t);
198 assert(f);
199
200 fprintf(f,
201 "%sSlice State: %s\n",
202 prefix, slice_state_to_string(t->state));
4ad49000
LP
203
204 cgroup_context_dump(&t->cgroup_context, f, prefix);
a016b922
LP
205}
206
207static int slice_start(Unit *u) {
208 Slice *t = SLICE(u);
4b58153d 209 int r;
a016b922
LP
210
211 assert(t);
212 assert(t->state == SLICE_DEAD);
213
4b58153d
LP
214 r = unit_acquire_invocation_id(u);
215 if (r < 0)
216 return r;
217
5ad096b3 218 (void) unit_realize_cgroup(u);
906c06f6
DM
219 (void) unit_reset_cpu_accounting(u);
220 (void) unit_reset_ip_accounting(u);
a016b922
LP
221
222 slice_set_state(t, SLICE_ACTIVE);
82a2b6bb 223 return 1;
a016b922
LP
224}
225
226static int slice_stop(Unit *u) {
227 Slice *t = SLICE(u);
228
229 assert(t);
230 assert(t->state == SLICE_ACTIVE);
231
4ad49000
LP
232 /* We do not need to destroy the cgroup explicitly,
233 * unit_notify() will do that for us anyway. */
a016b922
LP
234
235 slice_set_state(t, SLICE_DEAD);
82a2b6bb 236 return 1;
a016b922
LP
237}
238
718db961 239static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
a016b922
LP
240 return unit_kill_common(u, who, signo, -1, -1, error);
241}
242
243static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
244 Slice *s = SLICE(u);
245
246 assert(s);
247 assert(f);
248 assert(fds);
249
250 unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
251 return 0;
252}
253
254static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
255 Slice *s = SLICE(u);
256
257 assert(u);
258 assert(key);
259 assert(value);
260 assert(fds);
261
262 if (streq(key, "state")) {
263 SliceState state;
264
265 state = slice_state_from_string(value);
266 if (state < 0)
267 log_debug("Failed to parse state value %s", value);
268 else
269 s->deserialized_state = state;
270
271 } else
272 log_debug("Unknown serialization key '%s'", key);
273
274 return 0;
275}
276
277_pure_ static UnitActiveState slice_active_state(Unit *u) {
278 assert(u);
279
280 return state_translation_table[SLICE(u)->state];
281}
282
283_pure_ static const char *slice_sub_state_to_string(Unit *u) {
284 assert(u);
285
286 return slice_state_to_string(SLICE(u)->state);
287}
288
ba64af90 289static void slice_enumerate(Manager *m) {
efdb0237
LP
290 Unit *u;
291 int r;
292
293 assert(m);
294
295 u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
296 if (!u) {
a581e45a 297 r = unit_new_for_name(m, sizeof(Slice), SPECIAL_ROOT_SLICE, &u);
efdb0237 298 if (r < 0) {
a581e45a 299 log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_SLICE " unit: %m");
ba64af90 300 return;
efdb0237
LP
301 }
302 }
303
f5869324 304 u->perpetual = true;
efdb0237
LP
305 SLICE(u)->deserialized_state = SLICE_ACTIVE;
306
efdb0237
LP
307 unit_add_to_load_queue(u);
308 unit_add_to_dbus_queue(u);
efdb0237
LP
309}
310
a016b922
LP
311const UnitVTable slice_vtable = {
312 .object_size = sizeof(Slice),
718db961
LP
313 .cgroup_context_offset = offsetof(Slice, cgroup_context),
314
a016b922
LP
315 .sections =
316 "Unit\0"
317 "Slice\0"
318 "Install\0",
4ad49000 319 .private_section = "Slice",
4ad49000 320
17f62e9b 321 .can_transient = true,
a016b922 322
1b4cd0cf 323 .init = slice_init,
a016b922 324 .load = slice_load,
4ad49000 325
a016b922
LP
326 .coldplug = slice_coldplug,
327
328 .dump = slice_dump,
329
330 .start = slice_start,
331 .stop = slice_stop,
332
333 .kill = slice_kill,
334
335 .serialize = slice_serialize,
336 .deserialize_item = slice_deserialize_item,
337
338 .active_state = slice_active_state,
339 .sub_state_to_string = slice_sub_state_to_string,
340
718db961 341 .bus_vtable = bus_slice_vtable,
8e2af478
LP
342 .bus_set_property = bus_slice_set_property,
343 .bus_commit_properties = bus_slice_commit_properties,
a016b922 344
efdb0237
LP
345 .enumerate = slice_enumerate,
346
a016b922
LP
347 .status_message_formats = {
348 .finished_start_job = {
4ad49000 349 [JOB_DONE] = "Created slice %s.",
a016b922
LP
350 },
351 .finished_stop_job = {
4ad49000 352 [JOB_DONE] = "Removed slice %s.",
a016b922
LP
353 },
354 },
355};