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