]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
core: add transient units
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
4ad49000
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 <dbus/dbus.h>
23
7041efe9 24#include "path-util.h"
4ad49000
LP
25#include "dbus-cgroup.h"
26
27static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
28
29static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
30 DBusMessageIter sub, sub2;
31 CGroupContext *c = data;
32 CGroupBlockIODeviceWeight *w;
33
34 assert(i);
35 assert(property);
36 assert(c);
37
38 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
39 return -ENOMEM;
40
41 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
42
43 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
44 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) ||
45 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) ||
46 !dbus_message_iter_close_container(&sub, &sub2))
47 return -ENOMEM;
48 }
49
50 if (!dbus_message_iter_close_container(i, &sub))
51 return -ENOMEM;
52
53 return 0;
54}
55
56static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
57 DBusMessageIter sub, sub2;
58 CGroupContext *c = data;
59 CGroupBlockIODeviceBandwidth *b;
60
61 assert(i);
62 assert(property);
63 assert(c);
64
65 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
66 return -ENOMEM;
67
68 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
69
70 if (streq(property, "BlockIOReadBandwidth") != b->read)
71 continue;
72
73 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
74 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) ||
75 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) ||
76 !dbus_message_iter_close_container(&sub, &sub2))
77 return -ENOMEM;
78 }
79
80 if (!dbus_message_iter_close_container(i, &sub))
81 return -ENOMEM;
82
83 return 0;
84}
85
86static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
87 DBusMessageIter sub, sub2;
88 CGroupContext *c = data;
89 CGroupDeviceAllow *a;
90
91 assert(i);
92 assert(property);
93 assert(c);
94
95 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
96 return -ENOMEM;
97
98 LIST_FOREACH(device_allow, a, c->device_allow) {
99 const char *rwm;
100 char buf[4];
101 unsigned k = 0;
102
103 if (a->r)
104 buf[k++] = 'r';
105 if (a->w)
106 buf[k++] = 'w';
107 if (a->m)
108 buf[k++] = 'm';
109
110 buf[k] = 0;
111 rwm = buf;
112
113 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
114 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) ||
115 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) ||
116 !dbus_message_iter_close_container(&sub, &sub2))
117 return -ENOMEM;
118 }
119
120 if (!dbus_message_iter_close_container(i, &sub))
121 return -ENOMEM;
122
123 return 0;
124}
125
126const BusProperty bus_cgroup_context_properties[] = {
127 { "CPUAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, cpu_accounting) },
128 { "CPUShares", bus_property_append_ul, "t", offsetof(CGroupContext, cpu_shares) },
129 { "BlockIOAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, blockio_accounting) },
130 { "BlockIOWeight", bus_property_append_ul, "t", offsetof(CGroupContext, blockio_weight) },
131 { "BlockIODeviceWeight", bus_cgroup_append_device_weights, "a(st)", 0 },
132 { "BlockIOReadBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
133 { "BlockIOWriteBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
134 { "MemoryAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, memory_accounting) },
135 { "MemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_limit) },
136 { "MemorySoftLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_soft_limit) },
137 { "DevicePolicy", bus_cgroup_append_device_policy, "s", offsetof(CGroupContext, device_policy) },
138 { "DeviceAllow", bus_cgroup_append_device_allow, "a(ss)", 0 },
139 {}
140};
8e2af478
LP
141
142int bus_cgroup_set_property(
143 Unit *u,
144 CGroupContext *c,
145 const char *name,
146 DBusMessageIter *i,
147 UnitSetPropertiesMode mode,
148 DBusError *error) {
149
150 assert(name);
151 assert(u);
152 assert(c);
153 assert(i);
154
155 if (streq(name, "CPUAccounting")) {
8e2af478
LP
156
157 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
158 return -EINVAL;
159
160 if (mode != UNIT_CHECK) {
b42defe3 161 dbus_bool_t b;
8e2af478
LP
162 dbus_message_iter_get_basic(i, &b);
163
164 c->cpu_accounting = b;
b42defe3
LP
165 unit_write_drop_in_private_section(u, mode, "cpu-accounting", b ? "CPUAccounting=yes" : "CPUAccounting=no");
166 }
167
168 return 1;
169
170 } else if (streq(name, "CPUShares")) {
171 uint64_t u64;
172 unsigned long ul;
173
174 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
175 return -EINVAL;
176
177 dbus_message_iter_get_basic(i, &u64);
178 ul = (unsigned long) u64;
179
180 if (u64 <= 0 || u64 != (uint64_t) ul)
181 return -EINVAL;
182
183 if (mode != UNIT_CHECK) {
184 char buf[sizeof("CPUShares=") + DECIMAL_STR_MAX(ul)];
185 c->cpu_shares = ul;
186
187 sprintf(buf, "CPUShares=%lu", ul);
188 unit_write_drop_in_private_section(u, mode, "cpu-shares", buf);
8e2af478
LP
189 }
190
191 return 1;
192
193 } else if (streq(name, "BlockIOAccounting")) {
8e2af478
LP
194
195 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
196 return -EINVAL;
197
198 if (mode != UNIT_CHECK) {
b42defe3 199 dbus_bool_t b;
8e2af478
LP
200 dbus_message_iter_get_basic(i, &b);
201
202 c->blockio_accounting = b;
b42defe3 203 unit_write_drop_in_private_section(u, mode, "block-io-accounting", b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
204 }
205
206 return 1;
b42defe3
LP
207
208 } else if (streq(name, "BlockIOWeight")) {
209 uint64_t u64;
210 unsigned long ul;
211
212 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
213 return -EINVAL;
214
215 dbus_message_iter_get_basic(i, &u64);
216 ul = (unsigned long) u64;
217
218 if (u64 < 10 || u64 > 1000)
219 return -EINVAL;
220
221 if (mode != UNIT_CHECK) {
222 char buf[sizeof("BlockIOWeight=") + DECIMAL_STR_MAX(ul)];
223 c->cpu_shares = ul;
224
225 sprintf(buf, "BlockIOWeight=%lu", ul);
226 unit_write_drop_in_private_section(u, mode, "blockio-weight", buf);
227 }
228
229 return 1;
230
8e2af478 231 } else if (streq(name, "MemoryAccounting")) {
8e2af478
LP
232
233 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
234 return -EINVAL;
235
236 if (mode != UNIT_CHECK) {
b42defe3 237 dbus_bool_t b;
8e2af478
LP
238 dbus_message_iter_get_basic(i, &b);
239
b42defe3
LP
240 c->memory_accounting = b;
241 unit_write_drop_in_private_section(u, mode, "memory-accounting", b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
242 }
243
244 return 1;
8e2af478 245
b42defe3
LP
246 } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
247
248 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
249 return -EINVAL;
250
251 if (mode != UNIT_CHECK) {
252 uint64_t limit;
253 char buf[sizeof("MemorySoftLimit=") + DECIMAL_STR_MAX(limit)];
254
255 dbus_message_iter_get_basic(i, &limit);
256
257 if (streq(name, "MemoryLimit")) {
258 c->memory_limit = limit;
259 sprintf(buf, "MemoryLimit=%" PRIu64, limit);
260 unit_write_drop_in_private_section(u, mode, "memory-limit", buf);
261 } else {
262 c->memory_soft_limit = limit;
263 sprintf(buf, "MemorySoftLimit=%" PRIu64, limit);
264 unit_write_drop_in_private_section(u, mode, "memory-soft-limit", buf);
265 }
266 }
267
7041efe9
LP
268 return 1;
269
270 } else if (streq(name, "DevicePolicy")) {
271 const char *policy;
272 CGroupDevicePolicy p;
273
274 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
275 return -EINVAL;
276
277 dbus_message_iter_get_basic(i, &policy);
278 p = cgroup_device_policy_from_string(policy);
279 if (p < 0)
280 return -EINVAL;
281
282 if (mode != UNIT_CHECK) {
283 char *buf;
284
285 c->device_policy = p;
286
287 buf = strappenda("DevicePolicy=", policy);
288 unit_write_drop_in_private_section(u, mode, "device-policy", buf);
289 }
290
291 return 1;
292
293 } else if (streq(name, "DeviceAllow")) {
294 DBusMessageIter sub;
295 unsigned n = 0;
296
297 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
298 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
299 return -EINVAL;
300
301 dbus_message_iter_recurse(i, &sub);
302 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
303 DBusMessageIter sub2;
304 const char *path, *rwm;
305 CGroupDeviceAllow *a;
306
307 dbus_message_iter_recurse(&sub, &sub2);
308
309 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
310 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
311 return -EINVAL;
312
313 if (!path_startswith(path, "/dev")) {
314 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
315 return -EINVAL;
316 }
317
318 if (isempty(rwm))
319 rwm = "rwm";
320
321 if (!in_charset(rwm, "rwm")) {
322 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
323 return -EINVAL;
324 }
325
7041efe9
LP
326 if (mode != UNIT_CHECK) {
327 a = new0(CGroupDeviceAllow, 1);
328 if (!a)
329 return -ENOMEM;
330
331 a->path = strdup(path);
332 if (!a->path) {
333 free(a);
334 return -ENOMEM;
335 }
336
337 a->r = !!strchr(rwm, 'r');
338 a->w = !!strchr(rwm, 'w');
339 a->m = !!strchr(rwm, 'm');
340
341 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
342 }
343
c2756a68 344 n++;
7041efe9
LP
345 dbus_message_iter_next(&sub);
346 }
347
348 if (mode != UNIT_CHECK) {
349 _cleanup_free_ char *buf = NULL;
350 _cleanup_fclose_ FILE *f = NULL;
351 CGroupDeviceAllow *a;
352 size_t size = 0;
353
354 if (n == 0) {
355 while (c->device_allow)
356 cgroup_context_free_device_allow(c, c->device_allow);
357 }
358
359 f = open_memstream(&buf, &size);
360 if (!f)
361 return -ENOMEM;
362
363 fputs("DeviceAllow=\n", f);
364 LIST_FOREACH(device_allow, a, c->device_allow)
365 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
366
367 fflush(f);
368 unit_write_drop_in_private_section(u, mode, "device-allow", buf);
369 }
370
b42defe3
LP
371 return 1;
372 }
8e2af478
LP
373
374 return 0;
375}