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/>.
23 #include "path-util.h"
24 #include "cgroup-util.h"
26 #include "dbus-cgroup.h"
28 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
30 static int property_get_blockio_device_weight(
33 const char *interface,
35 sd_bus_message *reply,
37 sd_bus_error *error) {
39 CGroupContext *c = userdata;
40 CGroupBlockIODeviceWeight *w;
47 r = sd_bus_message_open_container(reply, 'a', "(st)");
51 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
52 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
57 return sd_bus_message_close_container(reply);
60 static int property_get_blockio_device_bandwidths(
63 const char *interface,
65 sd_bus_message *reply,
67 sd_bus_error *error) {
69 CGroupContext *c = userdata;
70 CGroupBlockIODeviceBandwidth *b;
77 r = sd_bus_message_open_container(reply, 'a', "(st)");
81 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
83 if (streq(property, "BlockIOReadBandwidth") != b->read)
86 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
91 return sd_bus_message_close_container(reply);
94 static int property_get_device_allow(
97 const char *interface,
99 sd_bus_message *reply,
101 sd_bus_error *error) {
103 CGroupContext *c = userdata;
104 CGroupDeviceAllow *a;
111 r = sd_bus_message_open_container(reply, 'a', "(ss)");
115 LIST_FOREACH(device_allow, a, c->device_allow) {
128 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
133 return sd_bus_message_close_container(reply);
136 const sd_bus_vtable bus_cgroup_vtable[] = {
137 SD_BUS_VTABLE_START(0),
138 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
139 SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
140 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
141 SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
142 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
143 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
144 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
145 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
146 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
147 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
148 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
152 int bus_cgroup_set_property(
156 sd_bus_message *message,
157 UnitSetPropertiesMode mode,
158 sd_bus_error *error) {
167 if (streq(name, "CPUAccounting")) {
170 r = sd_bus_message_read(message, "b", &b);
174 if (mode != UNIT_CHECK) {
175 c->cpu_accounting = b;
176 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
181 } else if (streq(name, "CPUShares")) {
185 r = sd_bus_message_read(message, "t", &u64);
189 ul = (unsigned long) u64;
190 if (ul <= 0 || (uint64_t) ul != u64)
191 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
193 if (mode != UNIT_CHECK) {
195 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
200 } else if (streq(name, "BlockIOAccounting")) {
203 r = sd_bus_message_read(message, "b", &b);
207 if (mode != UNIT_CHECK) {
208 c->blockio_accounting = b;
209 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
214 } else if (streq(name, "BlockIOWeight")) {
218 r = sd_bus_message_read(message, "t", &u64);
222 ul = (unsigned long) u64;
223 if (ul < 10 || ul > 1000)
224 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
226 if (mode != UNIT_CHECK) {
227 c->blockio_weight = ul;
228 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
233 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
239 if (streq(name, "BlockIOWriteBandwidth"))
242 r = sd_bus_message_enter_container(message, 'a', "(st)");
246 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
248 if (mode != UNIT_CHECK) {
249 CGroupBlockIODeviceBandwidth *a = NULL, *b;
251 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
252 if (path_equal(path, b->path) && read == b->read) {
259 a = new0(CGroupBlockIODeviceBandwidth, 1);
264 a->path = strdup(path);
270 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
281 if (mode != UNIT_CHECK) {
282 CGroupBlockIODeviceBandwidth *a, *next;
283 _cleanup_free_ char *buf = NULL;
284 _cleanup_fclose_ FILE *f = NULL;
288 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
290 cgroup_context_free_blockio_device_bandwidth(c, a);
293 f = open_memstream(&buf, &size);
298 fputs("BlockIOReadBandwidth=\n", f);
299 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
301 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
303 fputs("BlockIOWriteBandwidth=\n", f);
304 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
306 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
310 unit_write_drop_in_private(u, mode, name, buf);
315 } else if (streq(name, "BlockIODeviceWeight")) {
320 r = sd_bus_message_enter_container(message, 'a', "(st)");
324 while (( r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
327 ul = (unsigned long) u64;
328 if (ul < 10 || ul > 1000)
329 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
331 if (mode != UNIT_CHECK) {
332 CGroupBlockIODeviceWeight *a = NULL, *b;
334 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
335 if (path_equal(b->path, path)) {
342 a = new0(CGroupBlockIODeviceWeight, 1);
346 a->path = strdup(path);
351 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
360 if (mode != UNIT_CHECK) {
361 _cleanup_free_ char *buf = NULL;
362 _cleanup_fclose_ FILE *f = NULL;
363 CGroupBlockIODeviceWeight *a;
367 while (c->blockio_device_weights)
368 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
371 f = open_memstream(&buf, &size);
375 fputs("BlockIODeviceWeight=\n", f);
376 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
377 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
380 unit_write_drop_in_private(u, mode, name, buf);
385 } else if (streq(name, "MemoryAccounting")) {
388 r = sd_bus_message_read(message, "b", &b);
392 if (mode != UNIT_CHECK) {
393 c->memory_accounting = b;
394 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
399 } else if (streq(name, "MemoryLimit")) {
402 r = sd_bus_message_read(message, "t", &limit);
406 if (mode != UNIT_CHECK) {
407 c->memory_limit = limit;
408 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
413 } else if (streq(name, "DevicePolicy")) {
415 CGroupDevicePolicy p;
417 r = sd_bus_message_read(message, "s", &policy);
421 p = cgroup_device_policy_from_string(policy);
425 if (mode != UNIT_CHECK) {
428 c->device_policy = p;
430 buf = strappenda("DevicePolicy=", policy);
431 unit_write_drop_in_private(u, mode, name, buf);
436 } else if (streq(name, "DeviceAllow")) {
437 const char *path, *rwm;
440 r = sd_bus_message_enter_container(message, 'a', "(ss)");
444 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
446 if (!path_startswith(path, "/dev"))
447 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
452 if (!in_charset(rwm, "rwm"))
453 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
455 if (mode != UNIT_CHECK) {
456 CGroupDeviceAllow *a = NULL, *b;
458 LIST_FOREACH(device_allow, b, c->device_allow) {
459 if (path_equal(b->path, path)) {
466 a = new0(CGroupDeviceAllow, 1);
470 a->path = strdup(path);
476 LIST_PREPEND(device_allow, c->device_allow, a);
479 a->r = !!strchr(rwm, 'r');
480 a->w = !!strchr(rwm, 'w');
481 a->m = !!strchr(rwm, 'm');
488 if (mode != UNIT_CHECK) {
489 _cleanup_free_ char *buf = NULL;
490 _cleanup_fclose_ FILE *f = NULL;
491 CGroupDeviceAllow *a;
495 while (c->device_allow)
496 cgroup_context_free_device_allow(c, c->device_allow);
499 f = open_memstream(&buf, &size);
503 fputs("DeviceAllow=\n", f);
504 LIST_FOREACH(device_allow, a, c->device_allow)
505 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
508 unit_write_drop_in_private(u, mode, name, buf);