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 u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
177 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
182 } else if (streq(name, "CPUShares")) {
186 r = sd_bus_message_read(message, "t", &u64);
190 ul = (unsigned long) u64;
191 if (ul <= 0 || (uint64_t) ul != u64)
192 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
194 if (mode != UNIT_CHECK) {
196 u->cgroup_realized_mask &= ~CGROUP_CPU;
197 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
202 } else if (streq(name, "BlockIOAccounting")) {
205 r = sd_bus_message_read(message, "b", &b);
209 if (mode != UNIT_CHECK) {
210 c->blockio_accounting = b;
211 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
212 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
217 } else if (streq(name, "BlockIOWeight")) {
221 r = sd_bus_message_read(message, "t", &u64);
225 ul = (unsigned long) u64;
226 if (ul < 10 || ul > 1000)
227 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
229 if (mode != UNIT_CHECK) {
230 c->blockio_weight = ul;
231 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
232 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
237 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
243 if (streq(name, "BlockIOWriteBandwidth"))
246 r = sd_bus_message_enter_container(message, 'a', "(st)");
250 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
252 if (mode != UNIT_CHECK) {
253 CGroupBlockIODeviceBandwidth *a = NULL, *b;
255 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
256 if (path_equal(path, b->path) && read == b->read) {
263 a = new0(CGroupBlockIODeviceBandwidth, 1);
268 a->path = strdup(path);
274 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
285 r = sd_bus_message_exit_container(message);
289 if (mode != UNIT_CHECK) {
290 CGroupBlockIODeviceBandwidth *a, *next;
291 _cleanup_free_ char *buf = NULL;
292 _cleanup_fclose_ FILE *f = NULL;
296 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
298 cgroup_context_free_blockio_device_bandwidth(c, a);
301 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
303 f = open_memstream(&buf, &size);
308 fputs("BlockIOReadBandwidth=\n", f);
309 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
311 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
313 fputs("BlockIOWriteBandwidth=\n", f);
314 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
316 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
320 unit_write_drop_in_private(u, mode, name, buf);
325 } else if (streq(name, "BlockIODeviceWeight")) {
330 r = sd_bus_message_enter_container(message, 'a', "(st)");
334 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
335 unsigned long ul = u64;
337 if (ul < 10 || ul > 1000)
338 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
340 if (mode != UNIT_CHECK) {
341 CGroupBlockIODeviceWeight *a = NULL, *b;
343 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
344 if (path_equal(b->path, path)) {
351 a = new0(CGroupBlockIODeviceWeight, 1);
355 a->path = strdup(path);
360 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
369 r = sd_bus_message_exit_container(message);
373 if (mode != UNIT_CHECK) {
374 _cleanup_free_ char *buf = NULL;
375 _cleanup_fclose_ FILE *f = NULL;
376 CGroupBlockIODeviceWeight *a;
380 while (c->blockio_device_weights)
381 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
384 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
386 f = open_memstream(&buf, &size);
390 fputs("BlockIODeviceWeight=\n", f);
391 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
392 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
395 unit_write_drop_in_private(u, mode, name, buf);
400 } else if (streq(name, "MemoryAccounting")) {
403 r = sd_bus_message_read(message, "b", &b);
407 if (mode != UNIT_CHECK) {
408 c->memory_accounting = b;
409 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
410 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
415 } else if (streq(name, "MemoryLimit")) {
418 r = sd_bus_message_read(message, "t", &limit);
422 if (mode != UNIT_CHECK) {
423 c->memory_limit = limit;
424 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
425 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
430 } else if (streq(name, "DevicePolicy")) {
432 CGroupDevicePolicy p;
434 r = sd_bus_message_read(message, "s", &policy);
438 p = cgroup_device_policy_from_string(policy);
442 if (mode != UNIT_CHECK) {
445 c->device_policy = p;
446 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
448 buf = strappenda("DevicePolicy=", policy);
449 unit_write_drop_in_private(u, mode, name, buf);
454 } else if (streq(name, "DeviceAllow")) {
455 const char *path, *rwm;
458 r = sd_bus_message_enter_container(message, 'a', "(ss)");
462 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
464 if ((!startswith(path, "/dev/") &&
465 !startswith(path, "block-") &&
466 !startswith(path, "char-")) ||
467 strpbrk(path, WHITESPACE))
468 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
473 if (!in_charset(rwm, "rwm"))
474 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
476 if (mode != UNIT_CHECK) {
477 CGroupDeviceAllow *a = NULL, *b;
479 LIST_FOREACH(device_allow, b, c->device_allow) {
480 if (path_equal(b->path, path)) {
487 a = new0(CGroupDeviceAllow, 1);
491 a->path = strdup(path);
497 LIST_PREPEND(device_allow, c->device_allow, a);
500 a->r = !!strchr(rwm, 'r');
501 a->w = !!strchr(rwm, 'w');
502 a->m = !!strchr(rwm, 'm');
510 r = sd_bus_message_exit_container(message);
514 if (mode != UNIT_CHECK) {
515 _cleanup_free_ char *buf = NULL;
516 _cleanup_fclose_ FILE *f = NULL;
517 CGroupDeviceAllow *a;
521 while (c->device_allow)
522 cgroup_context_free_device_allow(c, c->device_allow);
525 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
527 f = open_memstream(&buf, &size);
531 fputs("DeviceAllow=\n", f);
532 LIST_FOREACH(device_allow, a, c->device_allow)
533 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
536 unit_write_drop_in_private(u, mode, name, buf);