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 static int property_get_ulong_as_u64(
139 const char *interface
,
140 const char *property
,
141 sd_bus_message
*reply
,
143 sd_bus_error
*error
) {
145 unsigned long *ul
= userdata
;
151 return sd_bus_message_append(reply
, "t", *ul
== (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul
);
154 const sd_bus_vtable bus_cgroup_vtable
[] = {
155 SD_BUS_VTABLE_START(0),
156 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool
, offsetof(CGroupContext
, delegate
), 0),
157 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool
, offsetof(CGroupContext
, cpu_accounting
), 0),
158 SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64
, offsetof(CGroupContext
, cpu_shares
), 0),
159 SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64
, offsetof(CGroupContext
, startup_cpu_shares
), 0),
160 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec
, offsetof(CGroupContext
, cpu_quota_per_sec_usec
), 0),
161 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool
, offsetof(CGroupContext
, blockio_accounting
), 0),
162 SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64
, offsetof(CGroupContext
, blockio_weight
), 0),
163 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64
, offsetof(CGroupContext
, startup_blockio_weight
), 0),
164 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight
, 0, 0),
165 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths
, 0, 0),
166 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths
, 0, 0),
167 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool
, offsetof(CGroupContext
, memory_accounting
), 0),
168 SD_BUS_PROPERTY("MemoryLimit", "t", NULL
, offsetof(CGroupContext
, memory_limit
), 0),
169 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy
, offsetof(CGroupContext
, device_policy
), 0),
170 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow
, 0, 0),
171 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool
, offsetof(CGroupContext
, tasks_accounting
), 0),
172 SD_BUS_PROPERTY("TasksMax", "t", NULL
, offsetof(CGroupContext
, tasks_max
), 0),
176 static int bus_cgroup_set_transient_property(
180 sd_bus_message
*message
,
181 UnitSetPropertiesMode mode
,
182 sd_bus_error
*error
) {
191 if (streq(name
, "Delegate")) {
194 r
= sd_bus_message_read(message
, "b", &b
);
198 if (mode
!= UNIT_CHECK
) {
200 unit_write_drop_in_private(u
, mode
, name
, b
? "Delegate=yes" : "Delegate=no");
209 int bus_cgroup_set_property(
213 sd_bus_message
*message
,
214 UnitSetPropertiesMode mode
,
215 sd_bus_error
*error
) {
224 if (streq(name
, "CPUAccounting")) {
227 r
= sd_bus_message_read(message
, "b", &b
);
231 if (mode
!= UNIT_CHECK
) {
232 c
->cpu_accounting
= b
;
233 u
->cgroup_realized_mask
&= ~CGROUP_MASK_CPUACCT
;
234 unit_write_drop_in_private(u
, mode
, name
, b
? "CPUAccounting=yes" : "CPUAccounting=no");
239 } else if (streq(name
, "CPUShares")) {
243 r
= sd_bus_message_read(message
, "t", &u64
);
247 if (u64
== (uint64_t) -1)
248 ul
= (unsigned long) -1;
250 ul
= (unsigned long) u64
;
251 if (ul
<= 0 || (uint64_t) ul
!= u64
)
252 return sd_bus_error_set_errnof(error
, EINVAL
, "CPUShares value out of range");
255 if (mode
!= UNIT_CHECK
) {
257 u
->cgroup_realized_mask
&= ~CGROUP_MASK_CPU
;
258 unit_write_drop_in_private_format(u
, mode
, name
, "CPUShares=%lu", ul
);
263 } else if (streq(name
, "StartupCPUShares")) {
267 r
= sd_bus_message_read(message
, "t", &u64
);
271 if (u64
== (uint64_t) -1)
272 ul
= (unsigned long) -1;
274 ul
= (unsigned long) u64
;
275 if (ul
<= 0 || (uint64_t) ul
!= u64
)
276 return sd_bus_error_set_errnof(error
, EINVAL
, "StartupCPUShares value out of range");
279 if (mode
!= UNIT_CHECK
) {
280 c
->startup_cpu_shares
= ul
;
281 u
->cgroup_realized_mask
&= ~CGROUP_MASK_CPU
;
282 unit_write_drop_in_private_format(u
, mode
, name
, "StartupCPUShares=%lu", ul
);
287 } else if (streq(name
, "CPUQuotaPerSecUSec")) {
290 r
= sd_bus_message_read(message
, "t", &u64
);
295 return sd_bus_error_set_errnof(error
, EINVAL
, "CPUQuotaPerSecUSec value out of range");
297 if (mode
!= UNIT_CHECK
) {
298 c
->cpu_quota_per_sec_usec
= u64
;
299 u
->cgroup_realized_mask
&= ~CGROUP_MASK_CPU
;
300 unit_write_drop_in_private_format(u
, mode
, "CPUQuota", "CPUQuota=%0.f%%", (double) (c
->cpu_quota_per_sec_usec
/ 10000));
305 } else if (streq(name
, "BlockIOAccounting")) {
308 r
= sd_bus_message_read(message
, "b", &b
);
312 if (mode
!= UNIT_CHECK
) {
313 c
->blockio_accounting
= b
;
314 u
->cgroup_realized_mask
&= ~CGROUP_MASK_BLKIO
;
315 unit_write_drop_in_private(u
, mode
, name
, b
? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
320 } else if (streq(name
, "BlockIOWeight")) {
324 r
= sd_bus_message_read(message
, "t", &u64
);
328 if (u64
== (uint64_t) -1)
329 ul
= (unsigned long) -1;
331 ul
= (unsigned long) u64
;
332 if (ul
< 10 || ul
> 1000)
333 return sd_bus_error_set_errnof(error
, EINVAL
, "BlockIOWeight value out of range");
336 if (mode
!= UNIT_CHECK
) {
337 c
->blockio_weight
= ul
;
338 u
->cgroup_realized_mask
&= ~CGROUP_MASK_BLKIO
;
339 unit_write_drop_in_private_format(u
, mode
, name
, "BlockIOWeight=%lu", ul
);
344 } else if (streq(name
, "StartupBlockIOWeight")) {
348 r
= sd_bus_message_read(message
, "t", &u64
);
352 if (u64
== (uint64_t) -1)
353 ul
= (unsigned long) -1;
355 ul
= (unsigned long) u64
;
356 if (ul
< 10 || ul
> 1000)
357 return sd_bus_error_set_errnof(error
, EINVAL
, "StartupBlockIOWeight value out of range");
360 if (mode
!= UNIT_CHECK
) {
361 c
->startup_blockio_weight
= ul
;
362 u
->cgroup_realized_mask
&= ~CGROUP_MASK_BLKIO
;
363 unit_write_drop_in_private_format(u
, mode
, name
, "StartupBlockIOWeight=%lu", ul
);
368 } else if (streq(name
, "BlockIOReadBandwidth") || streq(name
, "BlockIOWriteBandwidth")) {
374 if (streq(name
, "BlockIOWriteBandwidth"))
377 r
= sd_bus_message_enter_container(message
, 'a', "(st)");
381 while ((r
= sd_bus_message_read(message
, "(st)", &path
, &u64
)) > 0) {
383 if (mode
!= UNIT_CHECK
) {
384 CGroupBlockIODeviceBandwidth
*a
= NULL
, *b
;
386 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
387 if (path_equal(path
, b
->path
) && read
== b
->read
) {
394 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
399 a
->path
= strdup(path
);
405 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, a
);
416 r
= sd_bus_message_exit_container(message
);
420 if (mode
!= UNIT_CHECK
) {
421 CGroupBlockIODeviceBandwidth
*a
, *next
;
422 _cleanup_free_
char *buf
= NULL
;
423 _cleanup_fclose_
FILE *f
= NULL
;
427 LIST_FOREACH_SAFE(device_bandwidths
, a
, next
, c
->blockio_device_bandwidths
)
429 cgroup_context_free_blockio_device_bandwidth(c
, a
);
432 u
->cgroup_realized_mask
&= ~CGROUP_MASK_BLKIO
;
434 f
= open_memstream(&buf
, &size
);
439 fputs("BlockIOReadBandwidth=\n", f
);
440 LIST_FOREACH(device_bandwidths
, a
, c
->blockio_device_bandwidths
)
442 fprintf(f
, "BlockIOReadBandwidth=%s %" PRIu64
"\n", a
->path
, a
->bandwidth
);
444 fputs("BlockIOWriteBandwidth=\n", f
);
445 LIST_FOREACH(device_bandwidths
, a
, c
->blockio_device_bandwidths
)
447 fprintf(f
, "BlockIOWriteBandwidth=%s %" PRIu64
"\n", a
->path
, a
->bandwidth
);
451 unit_write_drop_in_private(u
, mode
, name
, buf
);
456 } else if (streq(name
, "BlockIODeviceWeight")) {
461 r
= sd_bus_message_enter_container(message
, 'a', "(st)");
465 while ((r
= sd_bus_message_read(message
, "(st)", &path
, &u64
)) > 0) {
466 unsigned long ul
= u64
;
468 if (ul
< 10 || ul
> 1000)
469 return sd_bus_error_set_errnof(error
, EINVAL
, "BlockIODeviceWeight out of range");
471 if (mode
!= UNIT_CHECK
) {
472 CGroupBlockIODeviceWeight
*a
= NULL
, *b
;
474 LIST_FOREACH(device_weights
, b
, c
->blockio_device_weights
) {
475 if (path_equal(b
->path
, path
)) {
482 a
= new0(CGroupBlockIODeviceWeight
, 1);
486 a
->path
= strdup(path
);
491 LIST_PREPEND(device_weights
,c
->blockio_device_weights
, a
);
500 r
= sd_bus_message_exit_container(message
);
504 if (mode
!= UNIT_CHECK
) {
505 _cleanup_free_
char *buf
= NULL
;
506 _cleanup_fclose_
FILE *f
= NULL
;
507 CGroupBlockIODeviceWeight
*a
;
511 while (c
->blockio_device_weights
)
512 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
515 u
->cgroup_realized_mask
&= ~CGROUP_MASK_BLKIO
;
517 f
= open_memstream(&buf
, &size
);
521 fputs("BlockIODeviceWeight=\n", f
);
522 LIST_FOREACH(device_weights
, a
, c
->blockio_device_weights
)
523 fprintf(f
, "BlockIODeviceWeight=%s %lu\n", a
->path
, a
->weight
);
526 unit_write_drop_in_private(u
, mode
, name
, buf
);
531 } else if (streq(name
, "MemoryAccounting")) {
534 r
= sd_bus_message_read(message
, "b", &b
);
538 if (mode
!= UNIT_CHECK
) {
539 c
->memory_accounting
= b
;
540 u
->cgroup_realized_mask
&= ~CGROUP_MASK_MEMORY
;
541 unit_write_drop_in_private(u
, mode
, name
, b
? "MemoryAccounting=yes" : "MemoryAccounting=no");
546 } else if (streq(name
, "MemoryLimit")) {
549 r
= sd_bus_message_read(message
, "t", &limit
);
553 if (mode
!= UNIT_CHECK
) {
554 c
->memory_limit
= limit
;
555 u
->cgroup_realized_mask
&= ~CGROUP_MASK_MEMORY
;
557 if (limit
== (uint64_t) -1)
558 unit_write_drop_in_private(u
, mode
, name
, "MemoryLimit=infinity");
560 unit_write_drop_in_private_format(u
, mode
, name
, "MemoryLimit=%" PRIu64
, limit
);
565 } else if (streq(name
, "DevicePolicy")) {
567 CGroupDevicePolicy p
;
569 r
= sd_bus_message_read(message
, "s", &policy
);
573 p
= cgroup_device_policy_from_string(policy
);
577 if (mode
!= UNIT_CHECK
) {
580 c
->device_policy
= p
;
581 u
->cgroup_realized_mask
&= ~CGROUP_MASK_DEVICES
;
583 buf
= strjoina("DevicePolicy=", policy
);
584 unit_write_drop_in_private(u
, mode
, name
, buf
);
589 } else if (streq(name
, "DeviceAllow")) {
590 const char *path
, *rwm
;
593 r
= sd_bus_message_enter_container(message
, 'a', "(ss)");
597 while ((r
= sd_bus_message_read(message
, "(ss)", &path
, &rwm
)) > 0) {
599 if ((!startswith(path
, "/dev/") &&
600 !startswith(path
, "block-") &&
601 !startswith(path
, "char-")) ||
602 strpbrk(path
, WHITESPACE
))
603 return sd_bus_error_set_errnof(error
, EINVAL
, "DeviceAllow= requires device node");
608 if (!in_charset(rwm
, "rwm"))
609 return sd_bus_error_set_errnof(error
, EINVAL
, "DeviceAllow= requires combination of rwm flags");
611 if (mode
!= UNIT_CHECK
) {
612 CGroupDeviceAllow
*a
= NULL
, *b
;
614 LIST_FOREACH(device_allow
, b
, c
->device_allow
) {
615 if (path_equal(b
->path
, path
)) {
622 a
= new0(CGroupDeviceAllow
, 1);
626 a
->path
= strdup(path
);
632 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
635 a
->r
= !!strchr(rwm
, 'r');
636 a
->w
= !!strchr(rwm
, 'w');
637 a
->m
= !!strchr(rwm
, 'm');
645 r
= sd_bus_message_exit_container(message
);
649 if (mode
!= UNIT_CHECK
) {
650 _cleanup_free_
char *buf
= NULL
;
651 _cleanup_fclose_
FILE *f
= NULL
;
652 CGroupDeviceAllow
*a
;
656 while (c
->device_allow
)
657 cgroup_context_free_device_allow(c
, c
->device_allow
);
660 u
->cgroup_realized_mask
&= ~CGROUP_MASK_DEVICES
;
662 f
= open_memstream(&buf
, &size
);
666 fputs("DeviceAllow=\n", f
);
667 LIST_FOREACH(device_allow
, a
, c
->device_allow
)
668 fprintf(f
, "DeviceAllow=%s %s%s%s\n", a
->path
, a
->r
? "r" : "", a
->w
? "w" : "", a
->m
? "m" : "");
671 unit_write_drop_in_private(u
, mode
, name
, buf
);
676 } else if (streq(name
, "TasksAccounting")) {
679 r
= sd_bus_message_read(message
, "b", &b
);
683 if (mode
!= UNIT_CHECK
) {
684 c
->tasks_accounting
= b
;
685 u
->cgroup_realized_mask
&= ~CGROUP_MASK_PIDS
;
686 unit_write_drop_in_private(u
, mode
, name
, b
? "TasksAccounting=yes" : "TasksAccounting=no");
691 } else if (streq(name
, "TasksMax")) {
694 r
= sd_bus_message_read(message
, "t", &limit
);
698 if (mode
!= UNIT_CHECK
) {
699 c
->tasks_max
= limit
;
700 u
->cgroup_realized_mask
&= ~CGROUP_MASK_PIDS
;
702 if (limit
== (uint64_t) -1)
703 unit_write_drop_in_private(u
, mode
, name
, "TasksMax=infinity");
705 unit_write_drop_in_private_format(u
, mode
, name
, "TasksMax=%" PRIu64
, limit
);
711 if (u
->transient
&& u
->load_state
== UNIT_STUB
) {
712 r
= bus_cgroup_set_transient_property(u
, c
, name
, message
, mode
, error
);