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) {
325 unsigned long ul = u64;
327 if (ul < 10 || ul > 1000)
328 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
330 if (mode != UNIT_CHECK) {
331 CGroupBlockIODeviceWeight *a = NULL, *b;
333 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
334 if (path_equal(b->path, path)) {
341 a = new0(CGroupBlockIODeviceWeight, 1);
345 a->path = strdup(path);
350 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
359 if (mode != UNIT_CHECK) {
360 _cleanup_free_ char *buf = NULL;
361 _cleanup_fclose_ FILE *f = NULL;
362 CGroupBlockIODeviceWeight *a;
366 while (c->blockio_device_weights)
367 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
370 f = open_memstream(&buf, &size);
374 fputs("BlockIODeviceWeight=\n", f);
375 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
376 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
379 unit_write_drop_in_private(u, mode, name, buf);
384 } else if (streq(name, "MemoryAccounting")) {
387 r = sd_bus_message_read(message, "b", &b);
391 if (mode != UNIT_CHECK) {
392 c->memory_accounting = b;
393 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
398 } else if (streq(name, "MemoryLimit")) {
401 r = sd_bus_message_read(message, "t", &limit);
405 if (mode != UNIT_CHECK) {
406 c->memory_limit = limit;
407 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
412 } else if (streq(name, "DevicePolicy")) {
414 CGroupDevicePolicy p;
416 r = sd_bus_message_read(message, "s", &policy);
420 p = cgroup_device_policy_from_string(policy);
424 if (mode != UNIT_CHECK) {
427 c->device_policy = p;
429 buf = strappenda("DevicePolicy=", policy);
430 unit_write_drop_in_private(u, mode, name, buf);
435 } else if (streq(name, "DeviceAllow")) {
436 const char *path, *rwm;
439 r = sd_bus_message_enter_container(message, 'a', "(ss)");
443 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
445 if (!path_startswith(path, "/dev"))
446 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
451 if (!in_charset(rwm, "rwm"))
452 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
454 if (mode != UNIT_CHECK) {
455 CGroupDeviceAllow *a = NULL, *b;
457 LIST_FOREACH(device_allow, b, c->device_allow) {
458 if (path_equal(b->path, path)) {
465 a = new0(CGroupDeviceAllow, 1);
469 a->path = strdup(path);
475 LIST_PREPEND(device_allow, c->device_allow, a);
478 a->r = !!strchr(rwm, 'r');
479 a->w = !!strchr(rwm, 'w');
480 a->m = !!strchr(rwm, 'm');
489 if (mode != UNIT_CHECK) {
490 _cleanup_free_ char *buf = NULL;
491 _cleanup_fclose_ FILE *f = NULL;
492 CGroupDeviceAllow *a;
496 while (c->device_allow)
497 cgroup_context_free_device_allow(c, c->device_allow);
500 f = open_memstream(&buf, &size);
504 fputs("DeviceAllow=\n", f);
505 LIST_FOREACH(device_allow, a, c->device_allow)
506 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
509 unit_write_drop_in_private(u, mode, name, buf);