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 { "DevicePolicy", bus_cgroup_append_device_policy
, "s", offsetof(CGroupContext
, device_policy
) },
137 { "DeviceAllow", bus_cgroup_append_device_allow
, "a(ss)", 0 },
141 int bus_cgroup_set_property(
146 UnitSetPropertiesMode mode
,
154 if (streq(name
, "CPUAccounting")) {
156 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_BOOLEAN
)
159 if (mode
!= UNIT_CHECK
) {
161 dbus_message_iter_get_basic(i
, &b
);
163 c
->cpu_accounting
= b
;
164 unit_write_drop_in_private(u
, mode
, name
, b
? "CPUAccounting=yes" : "CPUAccounting=no");
169 } else if (streq(name
, "CPUShares")) {
173 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_UINT64
)
176 dbus_message_iter_get_basic(i
, &u64
);
177 ul
= (unsigned long) u64
;
179 if (u64
<= 0 || u64
!= (uint64_t) ul
)
182 if (mode
!= UNIT_CHECK
) {
184 unit_write_drop_in_private_format(u
, mode
, name
, "CPUShares=%lu", ul
);
189 } else if (streq(name
, "BlockIOAccounting")) {
191 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_BOOLEAN
)
194 if (mode
!= UNIT_CHECK
) {
196 dbus_message_iter_get_basic(i
, &b
);
198 c
->blockio_accounting
= b
;
199 unit_write_drop_in_private(u
, mode
, name
, b
? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
204 } else if (streq(name
, "BlockIOWeight")) {
208 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_UINT64
)
211 dbus_message_iter_get_basic(i
, &u64
);
212 ul
= (unsigned long) u64
;
214 if (u64
< 10 || u64
> 1000)
217 if (mode
!= UNIT_CHECK
) {
218 c
->blockio_weight
= ul
;
219 unit_write_drop_in_private_format(u
, mode
, name
, "BlockIOWeight=%lu", ul
);
224 } else if (streq(name
, "BlockIOReadBandwidth") || streq(name
, "BlockIOWriteBandwidth")) {
229 if (streq(name
, "BlockIOWriteBandwidth"))
232 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_ARRAY
||
233 dbus_message_iter_get_element_type(i
) != DBUS_TYPE_STRUCT
)
236 dbus_message_iter_recurse(i
, &sub
);
237 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
238 DBusMessageIter sub2
;
241 CGroupBlockIODeviceBandwidth
*a
;
243 dbus_message_iter_recurse(&sub
, &sub2
);
244 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0 ||
245 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &u64
, false) < 0)
248 if (mode
!= UNIT_CHECK
) {
249 CGroupBlockIODeviceBandwidth
*b
;
252 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
253 if (path_equal(path
, b
->path
) && read
== b
->read
) {
261 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
266 a
->path
= strdup(path
);
276 LIST_PREPEND(CGroupBlockIODeviceBandwidth
, device_bandwidths
,
277 c
->blockio_device_bandwidths
, a
);
281 dbus_message_iter_next(&sub
);
284 if (mode
!= UNIT_CHECK
) {
285 _cleanup_free_
char *buf
= NULL
;
286 _cleanup_fclose_
FILE *f
= NULL
;
287 CGroupBlockIODeviceBandwidth
*a
;
288 CGroupBlockIODeviceBandwidth
*next
;
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")) {
323 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_ARRAY
||
324 dbus_message_iter_get_element_type(i
) != DBUS_TYPE_STRUCT
)
327 dbus_message_iter_recurse(i
, &sub
);
328 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
329 DBusMessageIter sub2
;
333 CGroupBlockIODeviceWeight
*a
;
335 dbus_message_iter_recurse(&sub
, &sub2
);
337 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0 ||
338 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &u64
, false) < 0)
341 ul
= (unsigned long) u64
;
342 if (ul
< 10 || ul
> 1000)
345 if (mode
!= UNIT_CHECK
) {
346 CGroupBlockIODeviceWeight
*b
;
349 LIST_FOREACH(device_weights
, b
, c
->blockio_device_weights
) {
350 if (path_equal(b
->path
, path
)) {
358 a
= new0(CGroupBlockIODeviceWeight
, 1);
362 a
->path
= strdup(path
);
372 LIST_PREPEND(CGroupBlockIODeviceWeight
, device_weights
,
373 c
->blockio_device_weights
, a
);
377 dbus_message_iter_next(&sub
);
380 if (mode
!= UNIT_CHECK
) {
381 _cleanup_free_
char *buf
= NULL
;
382 _cleanup_fclose_
FILE *f
= NULL
;
383 CGroupBlockIODeviceWeight
*a
;
387 while (c
->blockio_device_weights
)
388 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
391 f
= open_memstream(&buf
, &size
);
395 fputs("BlockIODeviceWeight=\n", f
);
396 LIST_FOREACH(device_weights
, a
, c
->blockio_device_weights
)
397 fprintf(f
, "BlockIODeviceWeight=%s %lu\n", a
->path
, a
->weight
);
400 unit_write_drop_in_private(u
, mode
, name
, buf
);
405 } else if (streq(name
, "MemoryAccounting")) {
407 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_BOOLEAN
)
410 if (mode
!= UNIT_CHECK
) {
412 dbus_message_iter_get_basic(i
, &b
);
414 c
->memory_accounting
= b
;
415 unit_write_drop_in_private(u
, mode
, name
, b
? "MemoryAccounting=yes" : "MemoryAccounting=no");
420 } else if (streq(name
, "MemoryLimit")) {
422 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_UINT64
)
425 if (mode
!= UNIT_CHECK
) {
427 dbus_message_iter_get_basic(i
, &limit
);
429 c
->memory_limit
= limit
;
430 unit_write_drop_in_private_format(u
, mode
, name
, "%s=%" PRIu64
, name
, limit
);
435 } else if (streq(name
, "DevicePolicy")) {
437 CGroupDevicePolicy p
;
439 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_STRING
)
442 dbus_message_iter_get_basic(i
, &policy
);
443 p
= cgroup_device_policy_from_string(policy
);
447 if (mode
!= UNIT_CHECK
) {
450 c
->device_policy
= p
;
452 buf
= strappenda("DevicePolicy=", policy
);
453 unit_write_drop_in_private(u
, mode
, name
, buf
);
458 } else if (streq(name
, "DeviceAllow")) {
462 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_ARRAY
||
463 dbus_message_iter_get_element_type(i
) != DBUS_TYPE_STRUCT
)
466 dbus_message_iter_recurse(i
, &sub
);
467 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
468 DBusMessageIter sub2
;
469 const char *path
, *rwm
;
470 CGroupDeviceAllow
*a
;
472 dbus_message_iter_recurse(&sub
, &sub2
);
474 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0 ||
475 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &rwm
, false) < 0)
478 if (!path_startswith(path
, "/dev")) {
479 dbus_set_error(error
, DBUS_ERROR_INVALID_ARGS
, "DeviceAllow= requires device node");
486 if (!in_charset(rwm
, "rwm")) {
487 dbus_set_error(error
, DBUS_ERROR_INVALID_ARGS
, "DeviceAllow= requires combination of rwm flags");
491 if (mode
!= UNIT_CHECK
) {
492 CGroupDeviceAllow
*b
;
495 LIST_FOREACH(device_allow
, b
, c
->device_allow
) {
496 if (path_equal(b
->path
, path
)) {
504 a
= new0(CGroupDeviceAllow
, 1);
508 a
->path
= strdup(path
);
515 a
->r
= !!strchr(rwm
, 'r');
516 a
->w
= !!strchr(rwm
, 'w');
517 a
->m
= !!strchr(rwm
, 'm');
520 LIST_PREPEND(CGroupDeviceAllow
, device_allow
, c
->device_allow
, a
);
524 dbus_message_iter_next(&sub
);
527 if (mode
!= UNIT_CHECK
) {
528 _cleanup_free_
char *buf
= NULL
;
529 _cleanup_fclose_
FILE *f
= NULL
;
530 CGroupDeviceAllow
*a
;
534 while (c
->device_allow
)
535 cgroup_context_free_device_allow(c
, c
->device_allow
);
538 f
= open_memstream(&buf
, &size
);
542 fputs("DeviceAllow=\n", f
);
543 LIST_FOREACH(device_allow
, a
, c
->device_allow
)
544 fprintf(f
, "DeviceAllow=%s %s%s%s\n", a
->path
, a
->r
? "r" : "", a
->w
? "w" : "", a
->m
? "m" : "");
547 unit_write_drop_in_private(u
, mode
, name
, buf
);