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