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 { "DevicePolicy", bus_cgroup_append_device_policy, "s", offsetof(CGroupContext, device_policy) },
137 { "DeviceAllow", bus_cgroup_append_device_allow, "a(ss)", 0 },
141 int bus_cgroup_set_property(
146 UnitSetPropertiesMode mode,
154 if (streq(name, "CPUAccounting")) {
156 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
159 if (mode != UNIT_CHECK) {
161 dbus_message_iter_get_basic(i, &b);
163 c->cpu_accounting = b;
164 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
169 } else if (streq(name, "CPUShares")) {
173 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
176 dbus_message_iter_get_basic(i, &u64);
177 ul = (unsigned long) u64;
179 if (u64 <= 0 || u64 != (uint64_t) ul)
182 if (mode != UNIT_CHECK) {
184 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
189 } else if (streq(name, "BlockIOAccounting")) {
191 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
194 if (mode != UNIT_CHECK) {
196 dbus_message_iter_get_basic(i, &b);
198 c->blockio_accounting = b;
199 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
204 } else if (streq(name, "BlockIOWeight")) {
208 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
211 dbus_message_iter_get_basic(i, &u64);
212 ul = (unsigned long) u64;
214 if (u64 < 10 || u64 > 1000)
217 if (mode != UNIT_CHECK) {
218 c->blockio_weight = ul;
219 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
224 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
229 if (streq(name, "BlockIOWriteBandwidth"))
232 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
233 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
236 dbus_message_iter_recurse(i, &sub);
237 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
238 DBusMessageIter sub2;
242 dbus_message_iter_recurse(&sub, &sub2);
243 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
244 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0)
247 if (mode != UNIT_CHECK) {
248 CGroupBlockIODeviceBandwidth *a = NULL;
249 CGroupBlockIODeviceBandwidth *b;
252 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
253 if (path_equal(path, b->path) && read == b->read) {
261 a = new0(CGroupBlockIODeviceBandwidth, 1);
266 a->path = strdup(path);
276 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
280 dbus_message_iter_next(&sub);
283 if (mode != UNIT_CHECK) {
284 _cleanup_free_ char *buf = NULL;
285 _cleanup_fclose_ FILE *f = NULL;
286 CGroupBlockIODeviceBandwidth *a;
287 CGroupBlockIODeviceBandwidth *next;
291 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
293 cgroup_context_free_blockio_device_bandwidth(c, a);
296 f = open_memstream(&buf, &size);
301 fputs("BlockIOReadBandwidth=\n", f);
302 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
304 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
306 fputs("BlockIOWriteBandwidth=\n", f);
307 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
309 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
313 unit_write_drop_in_private(u, mode, name, buf);
318 } else if (streq(name, "BlockIODeviceWeight")) {
322 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
323 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
326 dbus_message_iter_recurse(i, &sub);
327 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
328 DBusMessageIter sub2;
333 dbus_message_iter_recurse(&sub, &sub2);
335 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
336 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0)
339 ul = (unsigned long) u64;
340 if (ul < 10 || ul > 1000)
343 if (mode != UNIT_CHECK) {
344 CGroupBlockIODeviceWeight *a = NULL;
345 CGroupBlockIODeviceWeight *b;
348 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
349 if (path_equal(b->path, path)) {
357 a = new0(CGroupBlockIODeviceWeight, 1);
361 a->path = strdup(path);
371 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
375 dbus_message_iter_next(&sub);
378 if (mode != UNIT_CHECK) {
379 _cleanup_free_ char *buf = NULL;
380 _cleanup_fclose_ FILE *f = NULL;
381 CGroupBlockIODeviceWeight *a;
385 while (c->blockio_device_weights)
386 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
389 f = open_memstream(&buf, &size);
393 fputs("BlockIODeviceWeight=\n", f);
394 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
395 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
398 unit_write_drop_in_private(u, mode, name, buf);
403 } else if (streq(name, "MemoryAccounting")) {
405 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
408 if (mode != UNIT_CHECK) {
410 dbus_message_iter_get_basic(i, &b);
412 c->memory_accounting = b;
413 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
418 } else if (streq(name, "MemoryLimit")) {
420 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
423 if (mode != UNIT_CHECK) {
425 dbus_message_iter_get_basic(i, &limit);
427 c->memory_limit = limit;
428 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
433 } else if (streq(name, "DevicePolicy")) {
435 CGroupDevicePolicy p;
437 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
440 dbus_message_iter_get_basic(i, &policy);
441 p = cgroup_device_policy_from_string(policy);
445 if (mode != UNIT_CHECK) {
448 c->device_policy = p;
450 buf = strappenda("DevicePolicy=", policy);
451 unit_write_drop_in_private(u, mode, name, buf);
456 } else if (streq(name, "DeviceAllow")) {
460 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
461 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
464 dbus_message_iter_recurse(i, &sub);
465 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
466 DBusMessageIter sub2;
467 const char *path, *rwm;
469 dbus_message_iter_recurse(&sub, &sub2);
471 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
472 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
475 if (!path_startswith(path, "/dev")) {
476 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
483 if (!in_charset(rwm, "rwm")) {
484 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
488 if (mode != UNIT_CHECK) {
489 CGroupDeviceAllow *a = NULL;
490 CGroupDeviceAllow *b;
493 LIST_FOREACH(device_allow, b, c->device_allow) {
494 if (path_equal(b->path, path)) {
502 a = new0(CGroupDeviceAllow, 1);
506 a->path = strdup(path);
513 a->r = !!strchr(rwm, 'r');
514 a->w = !!strchr(rwm, 'w');
515 a->m = !!strchr(rwm, 'm');
518 LIST_PREPEND(device_allow, c->device_allow, a);
522 dbus_message_iter_next(&sub);
525 if (mode != UNIT_CHECK) {
526 _cleanup_free_ char *buf = NULL;
527 _cleanup_fclose_ FILE *f = NULL;
528 CGroupDeviceAllow *a;
532 while (c->device_allow)
533 cgroup_context_free_device_allow(c, c->device_allow);
536 f = open_memstream(&buf, &size);
540 fputs("DeviceAllow=\n", f);
541 LIST_FOREACH(device_allow, a, c->device_allow)
542 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
545 unit_write_drop_in_private(u, mode, name, buf);