]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/slice.c
systemctl: show per-unit cgroup tree correctly following the new property
[thirdparty/systemd.git] / src / core / slice.c
CommitLineData
a016b922
LP
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 "slice.h"
28#include "load-fragment.h"
29#include "log.h"
30#include "dbus-slice.h"
31#include "special.h"
32#include "unit-name.h"
33
34static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
35 [SLICE_DEAD] = UNIT_INACTIVE,
36 [SLICE_ACTIVE] = UNIT_ACTIVE
37};
38
4ad49000
LP
39static void slice_init(Unit *u) {
40 Slice *s = SLICE(u);
41
42 assert(u);
43 assert(u->load_state == UNIT_STUB);
44
45 cgroup_context_init(&s->cgroup_context);
46}
47
48static void slice_done(Unit *u) {
49 Slice *s = SLICE(u);
50
51 assert(u);
52
53 cgroup_context_done(&s->cgroup_context);
54}
55
a016b922
LP
56static void slice_set_state(Slice *t, SliceState state) {
57 SliceState old_state;
58 assert(t);
59
60 old_state = t->state;
61 t->state = state;
62
63 if (state != old_state)
64 log_debug("%s changed %s -> %s",
65 UNIT(t)->id,
66 slice_state_to_string(old_state),
67 slice_state_to_string(state));
68
69 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
70}
71
4ad49000 72static int slice_add_parent_slice(Slice *s) {
a016b922 73 char *a, *dash;
a016b922 74 Unit *parent;
4ad49000 75 int r;
a016b922
LP
76
77 assert(s);
78
4ad49000 79 if (UNIT_ISSET(UNIT(s)->slice))
a016b922
LP
80 return 0;
81
4ad49000 82 if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
a016b922
LP
83 return 0;
84
4ad49000
LP
85 a = strdupa(UNIT(s)->id);
86 dash = strrchr(a, '-');
87 if (dash)
88 strcpy(dash, ".slice");
89 else
90 a = (char*) SPECIAL_ROOT_SLICE;
a016b922
LP
91
92 r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent);
93 if (r < 0)
94 return r;
95
96 unit_ref_set(&UNIT(s)->slice, parent);
97 return 0;
98}
99
100static int slice_add_default_dependencies(Slice *s) {
101 int r;
102
103 assert(s);
104
105 /* Make sure slices are unloaded on shutdown */
106 r = unit_add_dependency_by_name(UNIT(s), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
107 if (r < 0)
108 return r;
109
110 return 0;
111}
112
113static int slice_verify(Slice *s) {
114 assert(s);
115
116 if (UNIT(s)->load_state != UNIT_LOADED)
117 return 0;
118
119 if (UNIT_DEREF(UNIT(s)->slice)) {
120 char *a, *dash;
121
122 a = strdupa(UNIT(s)->id);
123 dash = strrchr(a, '-');
4ad49000 124 if (dash)
a016b922 125 strcpy(dash, ".slice");
4ad49000
LP
126 else
127 a = (char*) SPECIAL_ROOT_SLICE;
a016b922 128
4ad49000
LP
129 if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
130 log_error_unit(UNIT(s)->id,
131 "%s located outside its parent slice. Refusing.", UNIT(s)->id);
132 return -EINVAL;
a016b922
LP
133 }
134 }
135
136 return 0;
137}
138
139static int slice_load(Unit *u) {
140 Slice *s = SLICE(u);
141 int r;
142
143 assert(s);
144
4ad49000 145 r = unit_load_fragment_and_dropin_optional(u);
a016b922
LP
146 if (r < 0)
147 return r;
148
149 /* This is a new unit? Then let's add in some extras */
150 if (u->load_state == UNIT_LOADED) {
151
4ad49000 152 r = slice_add_parent_slice(s);
a016b922
LP
153 if (r < 0)
154 return r;
155
156 if (u->default_dependencies) {
157 r = slice_add_default_dependencies(s);
158 if (r < 0)
159 return r;
160 }
a016b922
LP
161 }
162
163 return slice_verify(s);
164}
165
166static int slice_coldplug(Unit *u) {
167 Slice *t = SLICE(u);
168
169 assert(t);
170 assert(t->state == SLICE_DEAD);
171
172 if (t->deserialized_state != t->state)
173 slice_set_state(t, t->deserialized_state);
174
175 return 0;
176}
177
178static void slice_dump(Unit *u, FILE *f, const char *prefix) {
179 Slice *t = SLICE(u);
180
181 assert(t);
182 assert(f);
183
184 fprintf(f,
185 "%sSlice State: %s\n",
186 prefix, slice_state_to_string(t->state));
4ad49000
LP
187
188 cgroup_context_dump(&t->cgroup_context, f, prefix);
a016b922
LP
189}
190
191static int slice_start(Unit *u) {
192 Slice *t = SLICE(u);
a016b922
LP
193
194 assert(t);
195 assert(t->state == SLICE_DEAD);
196
4ad49000 197 unit_realize_cgroup(u);
a016b922
LP
198
199 slice_set_state(t, SLICE_ACTIVE);
200 return 0;
201}
202
203static int slice_stop(Unit *u) {
204 Slice *t = SLICE(u);
205
206 assert(t);
207 assert(t->state == SLICE_ACTIVE);
208
4ad49000
LP
209 /* We do not need to destroy the cgroup explicitly,
210 * unit_notify() will do that for us anyway. */
a016b922
LP
211
212 slice_set_state(t, SLICE_DEAD);
213 return 0;
214}
215
216static int slice_kill(Unit *u, KillWho who, int signo, DBusError *error) {
217 return unit_kill_common(u, who, signo, -1, -1, error);
218}
219
220static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
221 Slice *s = SLICE(u);
222
223 assert(s);
224 assert(f);
225 assert(fds);
226
227 unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
228 return 0;
229}
230
231static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
232 Slice *s = SLICE(u);
233
234 assert(u);
235 assert(key);
236 assert(value);
237 assert(fds);
238
239 if (streq(key, "state")) {
240 SliceState state;
241
242 state = slice_state_from_string(value);
243 if (state < 0)
244 log_debug("Failed to parse state value %s", value);
245 else
246 s->deserialized_state = state;
247
248 } else
249 log_debug("Unknown serialization key '%s'", key);
250
251 return 0;
252}
253
254_pure_ static UnitActiveState slice_active_state(Unit *u) {
255 assert(u);
256
257 return state_translation_table[SLICE(u)->state];
258}
259
260_pure_ static const char *slice_sub_state_to_string(Unit *u) {
261 assert(u);
262
263 return slice_state_to_string(SLICE(u)->state);
264}
265
266static const char* const slice_state_table[_SLICE_STATE_MAX] = {
267 [SLICE_DEAD] = "dead",
268 [SLICE_ACTIVE] = "active"
269};
270
271DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
272
273const UnitVTable slice_vtable = {
274 .object_size = sizeof(Slice),
275 .sections =
276 "Unit\0"
277 "Slice\0"
278 "Install\0",
279
4ad49000
LP
280 .private_section = "Slice",
281 .cgroup_context_offset = offsetof(Slice, cgroup_context),
282
a016b922
LP
283 .no_alias = true,
284 .no_instances = true,
285
4ad49000 286 .init = slice_init,
a016b922 287 .load = slice_load,
4ad49000
LP
288 .done = slice_done,
289
a016b922
LP
290 .coldplug = slice_coldplug,
291
292 .dump = slice_dump,
293
294 .start = slice_start,
295 .stop = slice_stop,
296
297 .kill = slice_kill,
298
299 .serialize = slice_serialize,
300 .deserialize_item = slice_deserialize_item,
301
302 .active_state = slice_active_state,
303 .sub_state_to_string = slice_sub_state_to_string,
304
305 .bus_interface = "org.freedesktop.systemd1.Slice",
306 .bus_message_handler = bus_slice_message_handler,
8e2af478
LP
307 .bus_set_property = bus_slice_set_property,
308 .bus_commit_properties = bus_slice_commit_properties,
a016b922
LP
309
310 .status_message_formats = {
311 .finished_start_job = {
4ad49000 312 [JOB_DONE] = "Created slice %s.",
a016b922
LP
313 [JOB_DEPENDENCY] = "Dependency failed for %s.",
314 },
315 .finished_stop_job = {
4ad49000 316 [JOB_DONE] = "Removed slice %s.",
a016b922
LP
317 },
318 },
319};