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 r = sd_bus_message_exit_container(message);
285 if (mode != UNIT_CHECK) {
286 CGroupBlockIODeviceBandwidth *a, *next;
287 _cleanup_free_ char *buf = NULL;
288 _cleanup_fclose_ FILE *f = NULL;
292 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
294 cgroup_context_free_blockio_device_bandwidth(c, a);
297 f = open_memstream(&buf, &size);
302 fputs("BlockIOReadBandwidth=\n", f);
303 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
305 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
307 fputs("BlockIOWriteBandwidth=\n", f);
308 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
310 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
314 unit_write_drop_in_private(u, mode, name, buf);
319 } else if (streq(name, "BlockIODeviceWeight")) {
324 r = sd_bus_message_enter_container(message, 'a', "(st)");
328 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
329 unsigned long ul = u64;
331 if (ul < 10 || ul > 1000)
332 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
334 if (mode != UNIT_CHECK) {
335 CGroupBlockIODeviceWeight *a = NULL, *b;
337 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
338 if (path_equal(b->path, path)) {
345 a = new0(CGroupBlockIODeviceWeight, 1);
349 a->path = strdup(path);
354 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
363 r = sd_bus_message_exit_container(message);
367 if (mode != UNIT_CHECK) {
368 _cleanup_free_ char *buf = NULL;
369 _cleanup_fclose_ FILE *f = NULL;
370 CGroupBlockIODeviceWeight *a;
374 while (c->blockio_device_weights)
375 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
378 f = open_memstream(&buf, &size);
382 fputs("BlockIODeviceWeight=\n", f);
383 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
384 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
387 unit_write_drop_in_private(u, mode, name, buf);
392 } else if (streq(name, "MemoryAccounting")) {
395 r = sd_bus_message_read(message, "b", &b);
399 if (mode != UNIT_CHECK) {
400 c->memory_accounting = b;
401 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
406 } else if (streq(name, "MemoryLimit")) {
409 r = sd_bus_message_read(message, "t", &limit);
413 if (mode != UNIT_CHECK) {
414 c->memory_limit = limit;
415 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
420 } else if (streq(name, "DevicePolicy")) {
422 CGroupDevicePolicy p;
424 r = sd_bus_message_read(message, "s", &policy);
428 p = cgroup_device_policy_from_string(policy);
432 if (mode != UNIT_CHECK) {
435 c->device_policy = p;
437 buf = strappenda("DevicePolicy=", policy);
438 unit_write_drop_in_private(u, mode, name, buf);
443 } else if (streq(name, "DeviceAllow")) {
444 const char *path, *rwm;
447 r = sd_bus_message_enter_container(message, 'a', "(ss)");
451 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
453 if ((!startswith(path, "/dev/") &&
454 !startswith(path, "block-") &&
455 !startswith(path, "char-")) ||
456 strpbrk(path, WHITESPACE))
457 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
462 if (!in_charset(rwm, "rwm"))
463 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
465 if (mode != UNIT_CHECK) {
466 CGroupDeviceAllow *a = NULL, *b;
468 LIST_FOREACH(device_allow, b, c->device_allow) {
469 if (path_equal(b->path, path)) {
476 a = new0(CGroupDeviceAllow, 1);
480 a->path = strdup(path);
486 LIST_PREPEND(device_allow, c->device_allow, a);
489 a->r = !!strchr(rwm, 'r');
490 a->w = !!strchr(rwm, 'w');
491 a->m = !!strchr(rwm, 'm');
499 r = sd_bus_message_exit_container(message);
503 if (mode != UNIT_CHECK) {
504 _cleanup_free_ char *buf = NULL;
505 _cleanup_fclose_ FILE *f = NULL;
506 CGroupDeviceAllow *a;
510 while (c->device_allow)
511 cgroup_context_free_device_allow(c, c->device_allow);
514 f = open_memstream(&buf, &size);
518 fputs("DeviceAllow=\n", f);
519 LIST_FOREACH(device_allow, a, c->device_allow)
520 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
523 unit_write_drop_in_private(u, mode, name, buf);