chiark / gitweb /
rtnl: drop "sd_" prefix from cleanup macros
[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_two_dependencies_by_name(
107                         UNIT(s),
108                         UNIT_BEFORE, UNIT_CONFLICTS,
109                         SPECIAL_SHUTDOWN_TARGET, NULL, true);
110         if (r < 0)
111                 return r;
112
113         return 0;
114 }
115
116 static int slice_verify(Slice *s) {
117         assert(s);
118
119         if (UNIT(s)->load_state != UNIT_LOADED)
120                 return 0;
121
122         if (UNIT_DEREF(UNIT(s)->slice)) {
123                 char *a, *dash;
124
125                 a = strdupa(UNIT(s)->id);
126                 dash = strrchr(a, '-');
127                 if (dash)
128                         strcpy(dash, ".slice");
129                 else
130                         a = (char*) SPECIAL_ROOT_SLICE;
131
132                 if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
133                         log_error_unit(UNIT(s)->id,
134                                        "%s located outside its parent slice. Refusing.", UNIT(s)->id);
135                         return -EINVAL;
136                 }
137         }
138
139         return 0;
140 }
141
142 static int slice_load(Unit *u) {
143         Slice *s = SLICE(u);
144         int r;
145
146         assert(s);
147
148         r = unit_load_fragment_and_dropin_optional(u);
149         if (r < 0)
150                 return r;
151
152         /* This is a new unit? Then let's add in some extras */
153         if (u->load_state == UNIT_LOADED) {
154
155                 r = slice_add_parent_slice(s);
156                 if (r < 0)
157                         return r;
158
159                 if (u->default_dependencies) {
160                         r = slice_add_default_dependencies(s);
161                         if (r < 0)
162                                 return r;
163                 }
164         }
165
166         return slice_verify(s);
167 }
168
169 static int slice_coldplug(Unit *u) {
170         Slice *t = SLICE(u);
171
172         assert(t);
173         assert(t->state == SLICE_DEAD);
174
175         if (t->deserialized_state != t->state)
176                 slice_set_state(t, t->deserialized_state);
177
178         return 0;
179 }
180
181 static void slice_dump(Unit *u, FILE *f, const char *prefix) {
182         Slice *t = SLICE(u);
183
184         assert(t);
185         assert(f);
186
187         fprintf(f,
188                 "%sSlice State: %s\n",
189                 prefix, slice_state_to_string(t->state));
190
191         cgroup_context_dump(&t->cgroup_context, f, prefix);
192 }
193
194 static int slice_start(Unit *u) {
195         Slice *t = SLICE(u);
196
197         assert(t);
198         assert(t->state == SLICE_DEAD);
199
200         unit_realize_cgroup(u);
201
202         slice_set_state(t, SLICE_ACTIVE);
203         return 0;
204 }
205
206 static int slice_stop(Unit *u) {
207         Slice *t = SLICE(u);
208
209         assert(t);
210         assert(t->state == SLICE_ACTIVE);
211
212         /* We do not need to destroy the cgroup explicitly,
213          * unit_notify() will do that for us anyway. */
214
215         slice_set_state(t, SLICE_DEAD);
216         return 0;
217 }
218
219 static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
220         return unit_kill_common(u, who, signo, -1, -1, error);
221 }
222
223 static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
224         Slice *s = SLICE(u);
225
226         assert(s);
227         assert(f);
228         assert(fds);
229
230         unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
231         return 0;
232 }
233
234 static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
235         Slice *s = SLICE(u);
236
237         assert(u);
238         assert(key);
239         assert(value);
240         assert(fds);
241
242         if (streq(key, "state")) {
243                 SliceState state;
244
245                 state = slice_state_from_string(value);
246                 if (state < 0)
247                         log_debug("Failed to parse state value %s", value);
248                 else
249                         s->deserialized_state = state;
250
251         } else
252                 log_debug("Unknown serialization key '%s'", key);
253
254         return 0;
255 }
256
257 _pure_ static UnitActiveState slice_active_state(Unit *u) {
258         assert(u);
259
260         return state_translation_table[SLICE(u)->state];
261 }
262
263 _pure_ static const char *slice_sub_state_to_string(Unit *u) {
264         assert(u);
265
266         return slice_state_to_string(SLICE(u)->state);
267 }
268
269 static const char* const slice_state_table[_SLICE_STATE_MAX] = {
270         [SLICE_DEAD] = "dead",
271         [SLICE_ACTIVE] = "active"
272 };
273
274 DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
275
276 const UnitVTable slice_vtable = {
277         .object_size = sizeof(Slice),
278         .cgroup_context_offset = offsetof(Slice, cgroup_context),
279
280         .sections =
281                 "Unit\0"
282                 "Slice\0"
283                 "Install\0",
284         .private_section = "Slice",
285
286         .no_alias = true,
287         .no_instances = true,
288
289         .init = slice_init,
290         .load = slice_load,
291         .done = slice_done,
292
293         .coldplug = slice_coldplug,
294
295         .dump = slice_dump,
296
297         .start = slice_start,
298         .stop = slice_stop,
299
300         .kill = slice_kill,
301
302         .serialize = slice_serialize,
303         .deserialize_item = slice_deserialize_item,
304
305         .active_state = slice_active_state,
306         .sub_state_to_string = slice_sub_state_to_string,
307
308         .bus_interface = "org.freedesktop.systemd1.Slice",
309         .bus_vtable = bus_slice_vtable,
310         .bus_set_property = bus_slice_set_property,
311         .bus_commit_properties = bus_slice_commit_properties,
312
313         .status_message_formats = {
314                 .finished_start_job = {
315                         [JOB_DONE]       = "Created slice %s.",
316                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
317                 },
318                 .finished_stop_job = {
319                         [JOB_DONE]       = "Removed slice %s.",
320                 },
321         },
322 };