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