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_section(u, mode, "cpu-accounting", 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) {
184 char buf[sizeof("CPUShares=") + DECIMAL_STR_MAX(ul)];
187 sprintf(buf, "CPUShares=%lu", ul);
188 unit_write_drop_in_private_section(u, mode, "cpu-shares", buf);
193 } else if (streq(name, "BlockIOAccounting")) {
195 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
198 if (mode != UNIT_CHECK) {
200 dbus_message_iter_get_basic(i, &b);
202 c->blockio_accounting = b;
203 unit_write_drop_in_private_section(u, mode, "block-io-accounting", b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
208 } else if (streq(name, "BlockIOWeight")) {
212 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
215 dbus_message_iter_get_basic(i, &u64);
216 ul = (unsigned long) u64;
218 if (u64 < 10 || u64 > 1000)
221 if (mode != UNIT_CHECK) {
222 char buf[sizeof("BlockIOWeight=") + DECIMAL_STR_MAX(ul)];
225 sprintf(buf, "BlockIOWeight=%lu", ul);
226 unit_write_drop_in_private_section(u, mode, "blockio-weight", buf);
231 } else if (streq(name, "MemoryAccounting")) {
233 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
236 if (mode != UNIT_CHECK) {
238 dbus_message_iter_get_basic(i, &b);
240 c->memory_accounting = b;
241 unit_write_drop_in_private_section(u, mode, "memory-accounting", b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
246 } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
248 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
251 if (mode != UNIT_CHECK) {
253 char buf[sizeof("MemorySoftLimit=") + DECIMAL_STR_MAX(limit)];
255 dbus_message_iter_get_basic(i, &limit);
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);
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);
270 } else if (streq(name, "DevicePolicy")) {
272 CGroupDevicePolicy p;
274 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
277 dbus_message_iter_get_basic(i, &policy);
278 p = cgroup_device_policy_from_string(policy);
282 if (mode != UNIT_CHECK) {
285 c->device_policy = p;
287 buf = strappenda("DevicePolicy=", policy);
288 unit_write_drop_in_private_section(u, mode, "device-policy", buf);
293 } else if (streq(name, "DeviceAllow")) {
297 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
298 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
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;
307 dbus_message_iter_recurse(&sub, &sub2);
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)
313 if (!path_startswith(path, "/dev")) {
314 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
321 if (!in_charset(rwm, "rwm")) {
322 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
326 if (mode != UNIT_CHECK) {
327 a = new0(CGroupDeviceAllow, 1);
331 a->path = strdup(path);
337 a->r = !!strchr(rwm, 'r');
338 a->w = !!strchr(rwm, 'w');
339 a->m = !!strchr(rwm, 'm');
341 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
345 dbus_message_iter_next(&sub);
348 if (mode != UNIT_CHECK) {
349 _cleanup_free_ char *buf = NULL;
350 _cleanup_fclose_ FILE *f = NULL;
351 CGroupDeviceAllow *a;
355 while (c->device_allow)
356 cgroup_context_free_device_allow(c, c->device_allow);
359 f = open_memstream(&buf, &size);
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" : "");
368 unit_write_drop_in_private_section(u, mode, "device-allow", buf);