chiark / gitweb /
557f8290883c1a794511cace3509e4f07ed388ce
[elogind.git] / src / core / slice.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 "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
34 static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
35         [SLICE_DEAD] = UNIT_INACTIVE,
36         [SLICE_ACTIVE] = UNIT_ACTIVE
37 };
38
39 static 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
48 static void slice_done(Unit *u) {
49         Slice *s = SLICE(u);
50
51         assert(u);
52
53         cgroup_context_done(&s->cgroup_context);
54 }
55
56 static 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
72 static int slice_add_parent_slice(Slice *s) {
73         char *a, *dash;
74         Unit *parent;
75         int r;
76
77         assert(s);
78
79         if (UNIT_ISSET(UNIT(s)->slice))
80                 return 0;
81
82         if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
83                 return 0;
84
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;
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
100 static 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
113 static 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, '-');
124                 if (dash)
125                         strcpy(dash, ".slice");
126                 else
127                         a = (char*) SPECIAL_ROOT_SLICE;
128
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;
133                 }
134         }
135
136         return 0;
137 }
138
139 static int slice_load(Unit *u) {
140         Slice *s = SLICE(u);
141         int r;
142
143         assert(s);
144
145         r = unit_load_fragment_and_dropin_optional(u);
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
152                 r = slice_add_parent_slice(s);
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                 }
161         }
162
163         return slice_verify(s);
164 }
165
166 static 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
178 static 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));
187
188         cgroup_context_dump(&t->cgroup_context, f, prefix);
189 }
190
191 static int slice_start(Unit *u) {
192         Slice *t = SLICE(u);
193
194         assert(t);
195         assert(t->state == SLICE_DEAD);
196
197         unit_realize_cgroup(u);
198
199         slice_set_state(t, SLICE_ACTIVE);
200         return 0;
201 }
202
203 static int slice_stop(Unit *u) {
204         Slice *t = SLICE(u);
205
206         assert(t);
207         assert(t->state == SLICE_ACTIVE);
208
209         /* We do not need to destroy the cgroup explicitly,
210          * unit_notify() will do that for us anyway. */
211
212         slice_set_state(t, SLICE_DEAD);
213         return 0;
214 }
215
216 static int slice_kill(Unit *u, KillWho who, int signo, DBusError *error) {
217         return unit_kill_common(u, who, signo, -1, -1, error);
218 }
219
220 static 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
231 static 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
266 static const char* const slice_state_table[_SLICE_STATE_MAX] = {
267         [SLICE_DEAD] = "dead",
268         [SLICE_ACTIVE] = "active"
269 };
270
271 DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
272
273 const UnitVTable slice_vtable = {
274         .object_size = sizeof(Slice),
275         .sections =
276                 "Unit\0"
277                 "Slice\0"
278                 "Install\0",
279
280         .private_section = "Slice",
281         .cgroup_context_offset = offsetof(Slice, cgroup_context),
282
283         .no_alias = true,
284         .no_instances = true,
285
286         .init = slice_init,
287         .load = slice_load,
288         .done = slice_done,
289
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,
307         .bus_set_property = bus_slice_set_property,
308         .bus_commit_properties = bus_slice_commit_properties,
309
310         .status_message_formats = {
311                 .finished_start_job = {
312                         [JOB_DONE]       = "Created slice %s.",
313                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
314                 },
315                 .finished_stop_job = {
316                         [JOB_DONE]       = "Removed slice %s.",
317                 },
318         },
319 };