1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #include <dbus/dbus.h>
24 #include "path-util.h"
25 #include "dbus-cgroup.h"
27 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
29 static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
30 DBusMessageIter sub, sub2;
31 CGroupContext *c = data;
32 CGroupBlockIODeviceWeight *w;
38 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
41 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
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))
50 if (!dbus_message_iter_close_container(i, &sub))
56 static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
57 DBusMessageIter sub, sub2;
58 CGroupContext *c = data;
59 CGroupBlockIODeviceBandwidth *b;
65 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
68 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
70 if (streq(property, "BlockIOReadBandwidth") != b->read)
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))
80 if (!dbus_message_iter_close_container(i, &sub))
86 static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
87 DBusMessageIter sub, sub2;
88 CGroupContext *c = data;
95 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
98 LIST_FOREACH(device_allow, a, c->device_allow) {
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))
120 if (!dbus_message_iter_close_container(i, &sub))
126 const 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 },
142 int bus_cgroup_set_property(
147 UnitSetPropertiesMode mode,
155 if (streq(name, "CPUAccounting")) {
157 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
160 if (mode != UNIT_CHECK) {
162 dbus_message_iter_get_basic(i, &b);
164 c->cpu_accounting = b;
165 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
170 } else if (streq(name, "CPUShares")) {
174 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
177 dbus_message_iter_get_basic(i, &u64);
178 ul = (unsigned long) u64;
180 if (u64 <= 0 || u64 != (uint64_t) ul)
183 if (mode != UNIT_CHECK) {
185 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
190 } else if (streq(name, "BlockIOAccounting")) {
192 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
195 if (mode != UNIT_CHECK) {
197 dbus_message_iter_get_basic(i, &b);
199 c->blockio_accounting = b;
200 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
205 } else if (streq(name, "BlockIOWeight")) {
209 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
212 dbus_message_iter_get_basic(i, &u64);
213 ul = (unsigned long) u64;
215 if (u64 < 10 || u64 > 1000)
218 if (mode != UNIT_CHECK) {
219 c->blockio_weight = ul;
220 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
225 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
230 if (streq(name, "BlockIOWriteBandwidth"))
233 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
234 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
237 dbus_message_iter_recurse(i, &sub);
238 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
239 DBusMessageIter sub2;
242 CGroupBlockIODeviceBandwidth *a;
244 dbus_message_iter_recurse(&sub, &sub2);
245 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
246 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0)
249 if (mode != UNIT_CHECK) {
250 CGroupBlockIODeviceBandwidth *b;
253 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
254 if (path_equal(path, b->path) && read == b->read) {
262 a = new0(CGroupBlockIODeviceBandwidth, 1);
267 a->path = strdup(path);
277 LIST_PREPEND(CGroupBlockIODeviceBandwidth, device_bandwidths,
278 c->blockio_device_bandwidths, a);
282 dbus_message_iter_next(&sub);
285 if (mode != UNIT_CHECK) {
286 _cleanup_free_ char *buf = NULL;
287 _cleanup_fclose_ FILE *f = NULL;
288 CGroupBlockIODeviceBandwidth *a;
289 CGroupBlockIODeviceBandwidth *next;
293 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
295 cgroup_context_free_blockio_device_bandwidth(c, a);
298 f = open_memstream(&buf, &size);
303 fputs("BlockIOReadBandwidth=\n", f);
304 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
306 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
308 fputs("BlockIOWriteBandwidth=\n", f);
309 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
311 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
315 unit_write_drop_in_private(u, mode, name, buf);
320 } else if (streq(name, "MemoryAccounting")) {
322 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
325 if (mode != UNIT_CHECK) {
327 dbus_message_iter_get_basic(i, &b);
329 c->memory_accounting = b;
330 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
335 } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
337 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
340 if (mode != UNIT_CHECK) {
343 dbus_message_iter_get_basic(i, &limit);
345 if (streq(name, "MemoryLimit"))
346 c->memory_limit = limit;
348 c->memory_soft_limit = limit;
350 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
355 } else if (streq(name, "DevicePolicy")) {
357 CGroupDevicePolicy p;
359 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
362 dbus_message_iter_get_basic(i, &policy);
363 p = cgroup_device_policy_from_string(policy);
367 if (mode != UNIT_CHECK) {
370 c->device_policy = p;
372 buf = strappenda("DevicePolicy=", policy);
373 unit_write_drop_in_private(u, mode, name, buf);
378 } else if (streq(name, "DeviceAllow")) {
382 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
383 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
386 dbus_message_iter_recurse(i, &sub);
387 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
388 DBusMessageIter sub2;
389 const char *path, *rwm;
390 CGroupDeviceAllow *a;
392 dbus_message_iter_recurse(&sub, &sub2);
394 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
395 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
398 if (!path_startswith(path, "/dev")) {
399 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
406 if (!in_charset(rwm, "rwm")) {
407 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
411 if (mode != UNIT_CHECK) {
412 CGroupDeviceAllow *b;
415 LIST_FOREACH(device_allow, b, c->device_allow) {
416 if (streq(b->path, path)) {
424 a = new0(CGroupDeviceAllow, 1);
428 a->path = strdup(path);
435 a->r = !!strchr(rwm, 'r');
436 a->w = !!strchr(rwm, 'w');
437 a->m = !!strchr(rwm, 'm');
440 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
444 dbus_message_iter_next(&sub);
447 if (mode != UNIT_CHECK) {
448 _cleanup_free_ char *buf = NULL;
449 _cleanup_fclose_ FILE *f = NULL;
450 CGroupDeviceAllow *a;
454 while (c->device_allow)
455 cgroup_context_free_device_allow(c, c->device_allow);
458 f = open_memstream(&buf, &size);
462 fputs("DeviceAllow=\n", f);
463 LIST_FOREACH(device_allow, a, c->device_allow)
464 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
467 unit_write_drop_in_private(u, mode, name, buf);