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) {
220 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
225 } else if (streq(name, "MemoryAccounting")) {
227 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
230 if (mode != UNIT_CHECK) {
232 dbus_message_iter_get_basic(i, &b);
234 c->memory_accounting = b;
235 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
240 } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
242 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
245 if (mode != UNIT_CHECK) {
248 dbus_message_iter_get_basic(i, &limit);
250 if (streq(name, "MemoryLimit"))
251 c->memory_limit = limit;
253 c->memory_soft_limit = limit;
255 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
260 } else if (streq(name, "DevicePolicy")) {
262 CGroupDevicePolicy p;
264 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
267 dbus_message_iter_get_basic(i, &policy);
268 p = cgroup_device_policy_from_string(policy);
272 if (mode != UNIT_CHECK) {
275 c->device_policy = p;
277 buf = strappenda("DevicePolicy=", policy);
278 unit_write_drop_in_private(u, mode, name, buf);
283 } else if (streq(name, "DeviceAllow")) {
287 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
288 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
291 dbus_message_iter_recurse(i, &sub);
292 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
293 DBusMessageIter sub2;
294 const char *path, *rwm;
295 CGroupDeviceAllow *a;
297 dbus_message_iter_recurse(&sub, &sub2);
299 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
300 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
303 if (!path_startswith(path, "/dev")) {
304 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
311 if (!in_charset(rwm, "rwm")) {
312 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
316 if (mode != UNIT_CHECK) {
317 a = new0(CGroupDeviceAllow, 1);
321 a->path = strdup(path);
327 a->r = !!strchr(rwm, 'r');
328 a->w = !!strchr(rwm, 'w');
329 a->m = !!strchr(rwm, 'm');
331 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
335 dbus_message_iter_next(&sub);
338 if (mode != UNIT_CHECK) {
339 _cleanup_free_ char *buf = NULL;
340 _cleanup_fclose_ FILE *f = NULL;
341 CGroupDeviceAllow *a;
345 while (c->device_allow)
346 cgroup_context_free_device_allow(c, c->device_allow);
349 f = open_memstream(&buf, &size);
353 fputs("DeviceAllow=\n", f);
354 LIST_FOREACH(device_allow, a, c->device_allow)
355 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
358 unit_write_drop_in_private(u, mode, name, buf);