]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
Merge pull request #7481 from poettering/bpf-test-fix
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4ad49000
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
3dc5ca97
LP
21#include <arpa/inet.h>
22
23#include "af-list.h"
b5efdb8a 24#include "alloc-util.h"
078ba556 25#include "bpf-firewall.h"
718db961 26#include "bus-util.h"
718db961
LP
27#include "cgroup-util.h"
28#include "cgroup.h"
4ad49000 29#include "dbus-cgroup.h"
3ffd4af2 30#include "fd-util.h"
0d39fa9c 31#include "fileio.h"
3ffd4af2 32#include "path-util.h"
4ad49000 33
718db961
LP
34static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
35
02638280
LP
36static int property_get_delegate_controllers(
37 sd_bus *bus,
38 const char *path,
39 const char *interface,
40 const char *property,
41 sd_bus_message *reply,
42 void *userdata,
43 sd_bus_error *error) {
44
45 CGroupContext *c = userdata;
46 CGroupController cc;
47 int r;
48
49 assert(bus);
50 assert(reply);
51 assert(c);
52
53 if (!c->delegate)
54 return sd_bus_message_append(reply, "as", 0);
55
56 r = sd_bus_message_open_container(reply, 'a', "s");
57 if (r < 0)
58 return r;
59
60 for (cc = 0; cc < _CGROUP_CONTROLLER_MAX; cc++) {
61 if ((c->delegate_controllers & CGROUP_CONTROLLER_TO_MASK(cc)) == 0)
62 continue;
63
64 r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(cc));
65 if (r < 0)
66 return r;
67 }
68
69 return sd_bus_message_close_container(reply);
70}
71
13c31542
TH
72static int property_get_io_device_weight(
73 sd_bus *bus,
74 const char *path,
75 const char *interface,
76 const char *property,
77 sd_bus_message *reply,
78 void *userdata,
79 sd_bus_error *error) {
80
81 CGroupContext *c = userdata;
82 CGroupIODeviceWeight *w;
83 int r;
84
85 assert(bus);
86 assert(reply);
87 assert(c);
88
89 r = sd_bus_message_open_container(reply, 'a', "(st)");
90 if (r < 0)
91 return r;
92
93 LIST_FOREACH(device_weights, w, c->io_device_weights) {
94 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
95 if (r < 0)
96 return r;
97 }
98
99 return sd_bus_message_close_container(reply);
100}
101
102static int property_get_io_device_limits(
103 sd_bus *bus,
104 const char *path,
105 const char *interface,
106 const char *property,
107 sd_bus_message *reply,
108 void *userdata,
109 sd_bus_error *error) {
110
111 CGroupContext *c = userdata;
112 CGroupIODeviceLimit *l;
113 int r;
114
115 assert(bus);
116 assert(reply);
117 assert(c);
118
119 r = sd_bus_message_open_container(reply, 'a', "(st)");
120 if (r < 0)
121 return r;
122
123 LIST_FOREACH(device_limits, l, c->io_device_limits) {
9be57249 124 CGroupIOLimitType type;
13c31542 125
9be57249
TH
126 type = cgroup_io_limit_type_from_string(property);
127 if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
13c31542
TH
128 continue;
129
9be57249 130 r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
13c31542
TH
131 if (r < 0)
132 return r;
133 }
134
135 return sd_bus_message_close_container(reply);
136}
137
718db961
LP
138static int property_get_blockio_device_weight(
139 sd_bus *bus,
140 const char *path,
141 const char *interface,
142 const char *property,
143 sd_bus_message *reply,
ebcf1f97
LP
144 void *userdata,
145 sd_bus_error *error) {
4ad49000 146
718db961 147 CGroupContext *c = userdata;
4ad49000 148 CGroupBlockIODeviceWeight *w;
718db961 149 int r;
4ad49000 150
718db961
LP
151 assert(bus);
152 assert(reply);
4ad49000
LP
153 assert(c);
154
718db961
LP
155 r = sd_bus_message_open_container(reply, 'a', "(st)");
156 if (r < 0)
157 return r;
4ad49000
LP
158
159 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
718db961
LP
160 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
161 if (r < 0)
162 return r;
4ad49000
LP
163 }
164
718db961 165 return sd_bus_message_close_container(reply);
4ad49000
LP
166}
167
718db961
LP
168static int property_get_blockio_device_bandwidths(
169 sd_bus *bus,
170 const char *path,
171 const char *interface,
172 const char *property,
173 sd_bus_message *reply,
ebcf1f97
LP
174 void *userdata,
175 sd_bus_error *error) {
718db961
LP
176
177 CGroupContext *c = userdata;
4ad49000 178 CGroupBlockIODeviceBandwidth *b;
718db961 179 int r;
4ad49000 180
718db961
LP
181 assert(bus);
182 assert(reply);
4ad49000
LP
183 assert(c);
184
718db961
LP
185 r = sd_bus_message_open_container(reply, 'a', "(st)");
186 if (r < 0)
187 return r;
4ad49000
LP
188
189 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
979d0311 190 uint64_t v;
4ad49000 191
979d0311
TH
192 if (streq(property, "BlockIOReadBandwidth"))
193 v = b->rbps;
194 else
195 v = b->wbps;
196
197 if (v == CGROUP_LIMIT_MAX)
4ad49000
LP
198 continue;
199
979d0311 200 r = sd_bus_message_append(reply, "(st)", b->path, v);
718db961
LP
201 if (r < 0)
202 return r;
4ad49000
LP
203 }
204
718db961 205 return sd_bus_message_close_container(reply);
4ad49000
LP
206}
207
718db961
LP
208static int property_get_device_allow(
209 sd_bus *bus,
210 const char *path,
211 const char *interface,
212 const char *property,
213 sd_bus_message *reply,
ebcf1f97
LP
214 void *userdata,
215 sd_bus_error *error) {
718db961
LP
216
217 CGroupContext *c = userdata;
4ad49000 218 CGroupDeviceAllow *a;
718db961 219 int r;
4ad49000 220
718db961
LP
221 assert(bus);
222 assert(reply);
4ad49000
LP
223 assert(c);
224
718db961
LP
225 r = sd_bus_message_open_container(reply, 'a', "(ss)");
226 if (r < 0)
227 return r;
4ad49000
LP
228
229 LIST_FOREACH(device_allow, a, c->device_allow) {
4ad49000 230 unsigned k = 0;
718db961 231 char rwm[4];
4ad49000
LP
232
233 if (a->r)
718db961 234 rwm[k++] = 'r';
4ad49000 235 if (a->w)
718db961 236 rwm[k++] = 'w';
4ad49000 237 if (a->m)
718db961 238 rwm[k++] = 'm';
4ad49000 239
718db961 240 rwm[k] = 0;
4ad49000 241
718db961
LP
242 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
243 if (r < 0)
244 return r;
4ad49000
LP
245 }
246
718db961 247 return sd_bus_message_close_container(reply);
4ad49000
LP
248}
249
3dc5ca97
LP
250static int property_get_ip_address_access(
251 sd_bus *bus,
252 const char *path,
253 const char *interface,
254 const char *property,
255 sd_bus_message *reply,
256 void *userdata,
257 sd_bus_error *error) {
258
259 IPAddressAccessItem** items = userdata, *i;
260 int r;
261
262 r = sd_bus_message_open_container(reply, 'a', "(iayu)");
263 if (r < 0)
264 return r;
265
266 LIST_FOREACH(items, i, *items) {
267
268 r = sd_bus_message_open_container(reply, 'r', "iayu");
269 if (r < 0)
270 return r;
271
272 r = sd_bus_message_append(reply, "i", i->family);
273 if (r < 0)
274 return r;
275
276 r = sd_bus_message_append_array(reply, 'y', &i->address, FAMILY_ADDRESS_SIZE(i->family));
277 if (r < 0)
278 return r;
279
280 r = sd_bus_message_append(reply, "u", (uint32_t) i->prefixlen);
281 if (r < 0)
282 return r;
283
284 r = sd_bus_message_close_container(reply);
285 if (r < 0)
286 return r;
287 }
288
289 return sd_bus_message_close_container(reply);
290}
291
718db961
LP
292const sd_bus_vtable bus_cgroup_vtable[] = {
293 SD_BUS_VTABLE_START(0),
a931ad47 294 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
02638280 295 SD_BUS_PROPERTY("DelegateControllers", "as", property_get_delegate_controllers, 0, 0),
610f780c 296 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
66ebf6c0
TH
297 SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0),
298 SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0),
d53d9474
LP
299 SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
300 SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
ee26bcc0 301 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
13c31542
TH
302 SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
303 SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
304 SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
305 SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
306 SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
307 SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
ac06a0cf
TH
308 SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
309 SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
610f780c 310 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
d53d9474
LP
311 SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
312 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
610f780c
LP
313 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
314 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
315 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
316 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
da4d897e
TH
317 SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
318 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
319 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
96e131ea 320 SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
610f780c
LP
321 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
322 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
323 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
03a7b521
LP
324 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
325 SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
3dc5ca97
LP
326 SD_BUS_PROPERTY("IPAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, ip_accounting), 0),
327 SD_BUS_PROPERTY("IPAddressAllow", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_allow), 0),
328 SD_BUS_PROPERTY("IPAddressDeny", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_deny), 0),
718db961 329 SD_BUS_VTABLE_END
4ad49000 330};
8e2af478 331
a931ad47
LP
332static int bus_cgroup_set_transient_property(
333 Unit *u,
334 CGroupContext *c,
335 const char *name,
336 sd_bus_message *message,
2e59b241 337 UnitWriteFlags flags,
a931ad47
LP
338 sd_bus_error *error) {
339
340 int r;
341
342 assert(u);
343 assert(c);
344 assert(name);
345 assert(message);
346
2e59b241
LP
347 flags |= UNIT_PRIVATE;
348
a931ad47
LP
349 if (streq(name, "Delegate")) {
350 int b;
351
352 r = sd_bus_message_read(message, "b", &b);
353 if (r < 0)
354 return r;
355
2e59b241 356 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
a931ad47 357 c->delegate = b;
02638280
LP
358 c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
359
2e59b241 360 unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
a931ad47
LP
361 }
362
02638280
LP
363 return 1;
364
365 } else if (streq(name, "DelegateControllers")) {
366 CGroupMask mask = 0;
367
368 r = sd_bus_message_enter_container(message, 'a', "s");
369 if (r < 0)
370 return r;
371
372 for (;;) {
373 CGroupController cc;
374 const char *t;
375
376 r = sd_bus_message_read(message, "s", &t);
377 if (r < 0)
378 return r;
379 if (r == 0)
380 break;
381
382 cc = cgroup_controller_from_string(t);
383 if (cc < 0)
e74f76ca 384 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup contoller '%s'", t);
02638280
LP
385
386 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
387 }
388
389 r = sd_bus_message_exit_container(message);
390 if (r < 0)
391 return r;
392
2e59b241 393 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
02638280
LP
394 _cleanup_free_ char *t = NULL;
395
396 r = cg_mask_to_string(mask, &t);
397 if (r < 0)
398 return r;
399
400 c->delegate = true;
1bdfc7b9
YW
401 if (mask == 0)
402 c->delegate_controllers = 0;
403 else
404 c->delegate_controllers |= mask;
02638280 405
2e59b241 406 unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
02638280
LP
407 }
408
a931ad47
LP
409 return 1;
410 }
411
412 return 0;
413}
414
8e2af478
LP
415int bus_cgroup_set_property(
416 Unit *u,
417 CGroupContext *c,
418 const char *name,
718db961 419 sd_bus_message *message,
2e59b241 420 UnitWriteFlags flags,
718db961
LP
421 sd_bus_error *error) {
422
9be57249 423 CGroupIOLimitType iol_type;
718db961 424 int r;
8e2af478 425
8e2af478
LP
426 assert(u);
427 assert(c);
718db961
LP
428 assert(name);
429 assert(message);
8e2af478 430
2e59b241
LP
431 flags |= UNIT_PRIVATE;
432
8e2af478 433 if (streq(name, "CPUAccounting")) {
718db961 434 int b;
8e2af478 435
718db961
LP
436 r = sd_bus_message_read(message, "b", &b);
437 if (r < 0)
438 return r;
8e2af478 439
2e59b241 440 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
8e2af478 441 c->cpu_accounting = b;
e7ab4d1a 442 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
2e59b241 443 unit_write_settingf(u, flags, name, "CPUAccounting=%s", yes_no(b));
b42defe3
LP
444 }
445
446 return 1;
447
66ebf6c0
TH
448 } else if (streq(name, "CPUWeight")) {
449 uint64_t weight;
450
451 r = sd_bus_message_read(message, "t", &weight);
452 if (r < 0)
453 return r;
454
455 if (!CGROUP_WEIGHT_IS_OK(weight))
e74f76ca 456 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUWeight= value out of range");
66ebf6c0 457
2e59b241 458 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
66ebf6c0
TH
459 c->cpu_weight = weight;
460 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
461
462 if (weight == CGROUP_WEIGHT_INVALID)
2e59b241 463 unit_write_setting(u, flags, name, "CPUWeight=");
66ebf6c0 464 else
2e59b241 465 unit_write_settingf(u, flags, name, "CPUWeight=%" PRIu64, weight);
66ebf6c0
TH
466 }
467
468 return 1;
469
470 } else if (streq(name, "StartupCPUWeight")) {
471 uint64_t weight;
472
473 r = sd_bus_message_read(message, "t", &weight);
474 if (r < 0)
475 return r;
476
477 if (!CGROUP_WEIGHT_IS_OK(weight))
e74f76ca 478 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupCPUWeight= value out of range");
66ebf6c0 479
2e59b241 480 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
66ebf6c0
TH
481 c->startup_cpu_weight = weight;
482 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
483
484 if (weight == CGROUP_CPU_SHARES_INVALID)
2e59b241 485 unit_write_setting(u, flags, name, "StartupCPUWeight=");
66ebf6c0 486 else
2e59b241 487 unit_write_settingf(u, flags, name, "StartupCPUWeight=%" PRIu64, weight);
66ebf6c0
TH
488 }
489
490 return 1;
491
b42defe3 492 } else if (streq(name, "CPUShares")) {
d53d9474 493 uint64_t shares;
b42defe3 494
d53d9474 495 r = sd_bus_message_read(message, "t", &shares);
718db961
LP
496 if (r < 0)
497 return r;
b42defe3 498
d53d9474 499 if (!CGROUP_CPU_SHARES_IS_OK(shares))
e74f76ca 500 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUShares= value out of range");
b42defe3 501
2e59b241 502 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d53d9474 503 c->cpu_shares = shares;
e7ab4d1a 504 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
505
506 if (shares == CGROUP_CPU_SHARES_INVALID)
2e59b241 507 unit_write_setting(u, flags, name, "CPUShares=");
d53d9474 508 else
2e59b241 509 unit_write_settingf(u, flags, name, "CPUShares=%" PRIu64, shares);
8e2af478
LP
510 }
511
512 return 1;
513
95ae05c0 514 } else if (streq(name, "StartupCPUShares")) {
d53d9474 515 uint64_t shares;
95ae05c0 516
d53d9474 517 r = sd_bus_message_read(message, "t", &shares);
95ae05c0
WC
518 if (r < 0)
519 return r;
520
d53d9474 521 if (!CGROUP_CPU_SHARES_IS_OK(shares))
e74f76ca 522 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupCPUShares= value out of range");
95ae05c0 523
2e59b241 524 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d53d9474 525 c->startup_cpu_shares = shares;
e7ab4d1a 526 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
527
528 if (shares == CGROUP_CPU_SHARES_INVALID)
2e59b241 529 unit_write_setting(u, flags, name, "StartupCPUShares=");
d53d9474 530 else
2e59b241 531 unit_write_settingf(u, flags, name, "StartupCPUShares=%" PRIu64, shares);
95ae05c0
WC
532 }
533
534 return 1;
535
b2f8b02e
LP
536 } else if (streq(name, "CPUQuotaPerSecUSec")) {
537 uint64_t u64;
538
539 r = sd_bus_message_read(message, "t", &u64);
540 if (r < 0)
541 return r;
542
543 if (u64 <= 0)
e74f76ca 544 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
b2f8b02e 545
2e59b241 546 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
b2f8b02e 547 c->cpu_quota_per_sec_usec = u64;
e7ab4d1a 548 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
2e59b241 549
d4bf82fc 550 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
2e59b241 551 unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
d4bf82fc 552 else
2e59b241
LP
553 /* config_parse_cpu_quota() requires an integer, so truncating division is used on
554 * purpose here. */
555 unit_write_settingf(u, flags, "CPUQuota",
556 "CPUQuota=%0.f%%",
557 (double) (c->cpu_quota_per_sec_usec / 10000));
b2f8b02e
LP
558 }
559
560 return 1;
561
13c31542
TH
562 } else if (streq(name, "IOAccounting")) {
563 int b;
564
565 r = sd_bus_message_read(message, "b", &b);
566 if (r < 0)
567 return r;
568
2e59b241 569 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
570 c->io_accounting = b;
571 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
2e59b241 572 unit_write_settingf(u, flags, name, "IOAccounting=%s", yes_no(b));
13c31542
TH
573 }
574
575 return 1;
576
577 } else if (streq(name, "IOWeight")) {
578 uint64_t weight;
579
580 r = sd_bus_message_read(message, "t", &weight);
581 if (r < 0)
582 return r;
583
584 if (!CGROUP_WEIGHT_IS_OK(weight))
e74f76ca 585 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IOWeight= value out of range");
13c31542 586
2e59b241 587 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
588 c->io_weight = weight;
589 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
590
591 if (weight == CGROUP_WEIGHT_INVALID)
2e59b241 592 unit_write_setting(u, flags, name, "IOWeight=");
13c31542 593 else
2e59b241 594 unit_write_settingf(u, flags, name, "IOWeight=%" PRIu64, weight);
13c31542
TH
595 }
596
597 return 1;
598
599 } else if (streq(name, "StartupIOWeight")) {
600 uint64_t weight;
601
602 r = sd_bus_message_read(message, "t", &weight);
603 if (r < 0)
604 return r;
605
606 if (CGROUP_WEIGHT_IS_OK(weight))
e74f76ca 607 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupIOWeight= value out of range");
13c31542 608
2e59b241 609 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
610 c->startup_io_weight = weight;
611 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
612
613 if (weight == CGROUP_WEIGHT_INVALID)
2e59b241 614 unit_write_setting(u, flags, name, "StartupIOWeight=");
13c31542 615 else
2e59b241 616 unit_write_settingf(u, flags, name, "StartupIOWeight=%" PRIu64, weight);
13c31542
TH
617 }
618
619 return 1;
620
9be57249 621 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
13c31542 622 const char *path;
13c31542
TH
623 unsigned n = 0;
624 uint64_t u64;
625
13c31542
TH
626 r = sd_bus_message_enter_container(message, 'a', "(st)");
627 if (r < 0)
628 return r;
629
630 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
631
2e59b241 632 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
633 CGroupIODeviceLimit *a = NULL, *b;
634
635 LIST_FOREACH(device_limits, b, c->io_device_limits) {
636 if (path_equal(path, b->path)) {
637 a = b;
638 break;
639 }
640 }
641
642 if (!a) {
9be57249
TH
643 CGroupIOLimitType type;
644
13c31542
TH
645 a = new0(CGroupIODeviceLimit, 1);
646 if (!a)
647 return -ENOMEM;
648
649 a->path = strdup(path);
650 if (!a->path) {
651 free(a);
652 return -ENOMEM;
653 }
654
9be57249
TH
655 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
656 a->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
657
658 LIST_PREPEND(device_limits, c->io_device_limits, a);
659 }
660
9be57249 661 a->limits[iol_type] = u64;
13c31542
TH
662 }
663
664 n++;
665 }
666 if (r < 0)
667 return r;
668
669 r = sd_bus_message_exit_container(message);
670 if (r < 0)
671 return r;
672
2e59b241 673 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
674 CGroupIODeviceLimit *a;
675 _cleanup_free_ char *buf = NULL;
676 _cleanup_fclose_ FILE *f = NULL;
677 size_t size = 0;
678
679 if (n == 0) {
680 LIST_FOREACH(device_limits, a, c->io_device_limits)
9be57249 681 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
13c31542
TH
682 }
683
684 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
685
686 f = open_memstream(&buf, &size);
687 if (!f)
688 return -ENOMEM;
689
9be57249
TH
690 fprintf(f, "%s=\n", name);
691 LIST_FOREACH(device_limits, a, c->io_device_limits)
692 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
693 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
13c31542
TH
694
695 r = fflush_and_check(f);
696 if (r < 0)
697 return r;
2e59b241 698 unit_write_setting(u, flags, name, buf);
13c31542
TH
699 }
700
701 return 1;
702
703 } else if (streq(name, "IODeviceWeight")) {
704 const char *path;
705 uint64_t weight;
706 unsigned n = 0;
707
708 r = sd_bus_message_enter_container(message, 'a', "(st)");
709 if (r < 0)
710 return r;
711
712 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
713
714 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
e74f76ca 715 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
13c31542 716
2e59b241 717 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
718 CGroupIODeviceWeight *a = NULL, *b;
719
720 LIST_FOREACH(device_weights, b, c->io_device_weights) {
721 if (path_equal(b->path, path)) {
722 a = b;
723 break;
724 }
725 }
726
727 if (!a) {
728 a = new0(CGroupIODeviceWeight, 1);
729 if (!a)
730 return -ENOMEM;
731
732 a->path = strdup(path);
733 if (!a->path) {
734 free(a);
735 return -ENOMEM;
736 }
737 LIST_PREPEND(device_weights,c->io_device_weights, a);
738 }
739
740 a->weight = weight;
741 }
742
743 n++;
744 }
745
746 r = sd_bus_message_exit_container(message);
747 if (r < 0)
748 return r;
749
2e59b241 750 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
13c31542
TH
751 _cleanup_free_ char *buf = NULL;
752 _cleanup_fclose_ FILE *f = NULL;
753 CGroupIODeviceWeight *a;
754 size_t size = 0;
755
756 if (n == 0) {
757 while (c->io_device_weights)
758 cgroup_context_free_io_device_weight(c, c->io_device_weights);
759 }
760
761 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
762
763 f = open_memstream(&buf, &size);
764 if (!f)
765 return -ENOMEM;
766
4b61c875 767 fputs_unlocked("IODeviceWeight=\n", f);
13c31542
TH
768 LIST_FOREACH(device_weights, a, c->io_device_weights)
769 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
770
771 r = fflush_and_check(f);
772 if (r < 0)
773 return r;
2e59b241 774 unit_write_setting(u, flags, name, buf);
13c31542
TH
775 }
776
777 return 1;
778
8e2af478 779 } else if (streq(name, "BlockIOAccounting")) {
718db961 780 int b;
8e2af478 781
718db961
LP
782 r = sd_bus_message_read(message, "b", &b);
783 if (r < 0)
784 return r;
8e2af478 785
2e59b241 786 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
8e2af478 787 c->blockio_accounting = b;
e7ab4d1a 788 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
2e59b241 789 unit_write_settingf(u, flags, name, "BlockIOAccounting=%s", yes_no(b));
8e2af478
LP
790 }
791
792 return 1;
b42defe3
LP
793
794 } else if (streq(name, "BlockIOWeight")) {
d53d9474 795 uint64_t weight;
b42defe3 796
d53d9474 797 r = sd_bus_message_read(message, "t", &weight);
718db961
LP
798 if (r < 0)
799 return r;
b42defe3 800
d53d9474 801 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
e74f76ca 802 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIOWeight= value out of range");
b42defe3 803
2e59b241 804 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d53d9474 805 c->blockio_weight = weight;
e7ab4d1a 806 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
807
808 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
2e59b241 809 unit_write_setting(u, flags, name, "BlockIOWeight=");
d53d9474 810 else
2e59b241 811 unit_write_settingf(u, flags, name, "BlockIOWeight=%" PRIu64, weight);
b42defe3
LP
812 }
813
814 return 1;
95ae05c0
WC
815
816 } else if (streq(name, "StartupBlockIOWeight")) {
d53d9474 817 uint64_t weight;
95ae05c0 818
d53d9474 819 r = sd_bus_message_read(message, "t", &weight);
95ae05c0
WC
820 if (r < 0)
821 return r;
822
6fb09269 823 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
e74f76ca 824 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupBlockIOWeight= value out of range");
95ae05c0 825
2e59b241 826 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d53d9474 827 c->startup_blockio_weight = weight;
e7ab4d1a 828 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
829
830 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
2e59b241 831 unit_write_setting(u, flags, name, "StartupBlockIOWeight=");
d53d9474 832 else
2e59b241 833 unit_write_settingf(u, flags, name, "StartupBlockIOWeight=%" PRIu64, weight);
95ae05c0
WC
834 }
835
836 return 1;
b42defe3 837
cd0a7a8e 838 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
718db961 839 const char *path;
f004c2ca 840 bool read = true;
718db961
LP
841 unsigned n = 0;
842 uint64_t u64;
f004c2ca
G
843
844 if (streq(name, "BlockIOWriteBandwidth"))
845 read = false;
846
718db961
LP
847 r = sd_bus_message_enter_container(message, 'a', "(st)");
848 if (r < 0)
849 return r;
f004c2ca 850
718db961 851 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca 852
2e59b241 853 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
718db961 854 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
855
856 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
979d0311 857 if (path_equal(path, b->path)) {
f004c2ca 858 a = b;
f004c2ca
G
859 break;
860 }
861 }
862
718db961 863 if (!a) {
f004c2ca
G
864 a = new0(CGroupBlockIODeviceBandwidth, 1);
865 if (!a)
866 return -ENOMEM;
867
979d0311
TH
868 a->rbps = CGROUP_LIMIT_MAX;
869 a->wbps = CGROUP_LIMIT_MAX;
f004c2ca
G
870 a->path = strdup(path);
871 if (!a->path) {
872 free(a);
873 return -ENOMEM;
874 }
718db961
LP
875
876 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
877 }
878
979d0311
TH
879 if (read)
880 a->rbps = u64;
881 else
882 a->wbps = u64;
f004c2ca
G
883 }
884
885 n++;
f004c2ca 886 }
718db961
LP
887 if (r < 0)
888 return r;
f004c2ca 889
9c96019d
LP
890 r = sd_bus_message_exit_container(message);
891 if (r < 0)
892 return r;
893
2e59b241 894 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
979d0311 895 CGroupBlockIODeviceBandwidth *a;
f004c2ca
G
896 _cleanup_free_ char *buf = NULL;
897 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
898 size_t size = 0;
899
900 if (n == 0) {
979d0311
TH
901 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
902 if (read)
903 a->rbps = CGROUP_LIMIT_MAX;
904 else
905 a->wbps = CGROUP_LIMIT_MAX;
906 }
f004c2ca
G
907 }
908
e7ab4d1a 909 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 910
f004c2ca
G
911 f = open_memstream(&buf, &size);
912 if (!f)
913 return -ENOMEM;
914
7d6884b6 915 if (read) {
4b61c875 916 fputs_unlocked("BlockIOReadBandwidth=\n", f);
7d6884b6 917 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
918 if (a->rbps != CGROUP_LIMIT_MAX)
919 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
f004c2ca 920 } else {
4b61c875 921 fputs_unlocked("BlockIOWriteBandwidth=\n", f);
f004c2ca 922 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
923 if (a->wbps != CGROUP_LIMIT_MAX)
924 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
f004c2ca
G
925 }
926
1f2f874c
NC
927 r = fflush_and_check(f);
928 if (r < 0)
929 return r;
2e59b241
LP
930
931 unit_write_setting(u, flags, name, buf);
6f68ecb4
G
932 }
933
934 return 1;
935
936 } else if (streq(name, "BlockIODeviceWeight")) {
718db961 937 const char *path;
d53d9474 938 uint64_t weight;
6f68ecb4
G
939 unsigned n = 0;
940
718db961
LP
941 r = sd_bus_message_enter_container(message, 'a', "(st)");
942 if (r < 0)
943 return r;
6f68ecb4 944
d53d9474 945 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
6f68ecb4 946
d53d9474 947 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
e74f76ca 948 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
6f68ecb4 949
2e59b241 950 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
718db961 951 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
952
953 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
954 if (path_equal(b->path, path)) {
955 a = b;
6f68ecb4
G
956 break;
957 }
958 }
959
718db961 960 if (!a) {
6f68ecb4
G
961 a = new0(CGroupBlockIODeviceWeight, 1);
962 if (!a)
963 return -ENOMEM;
964
965 a->path = strdup(path);
966 if (!a->path) {
967 free(a);
968 return -ENOMEM;
969 }
718db961 970 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
971 }
972
d53d9474 973 a->weight = weight;
6f68ecb4
G
974 }
975
976 n++;
6f68ecb4
G
977 }
978
9c96019d
LP
979 r = sd_bus_message_exit_container(message);
980 if (r < 0)
981 return r;
982
2e59b241 983 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
6f68ecb4
G
984 _cleanup_free_ char *buf = NULL;
985 _cleanup_fclose_ FILE *f = NULL;
986 CGroupBlockIODeviceWeight *a;
987 size_t size = 0;
988
989 if (n == 0) {
990 while (c->blockio_device_weights)
991 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
992 }
993
e7ab4d1a 994 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 995
6f68ecb4
G
996 f = open_memstream(&buf, &size);
997 if (!f)
998 return -ENOMEM;
999
4b61c875 1000 fputs_unlocked("BlockIODeviceWeight=\n", f);
6f68ecb4 1001 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
d53d9474 1002 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
6f68ecb4 1003
1f2f874c
NC
1004 r = fflush_and_check(f);
1005 if (r < 0)
1006 return r;
2e59b241
LP
1007
1008 unit_write_setting(u, flags, name, buf);
f004c2ca
G
1009 }
1010
1011 return 1;
1012
8e2af478 1013 } else if (streq(name, "MemoryAccounting")) {
718db961 1014 int b;
8e2af478 1015
718db961
LP
1016 r = sd_bus_message_read(message, "b", &b);
1017 if (r < 0)
1018 return r;
8e2af478 1019
2e59b241 1020 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
b42defe3 1021 c->memory_accounting = b;
e7ab4d1a 1022 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
2e59b241 1023 unit_write_settingf(u, flags, name, "MemoryAccounting=%s", yes_no(b));
8e2af478
LP
1024 }
1025
1026 return 1;
8e2af478 1027
96e131ea 1028 } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax")) {
da4d897e
TH
1029 uint64_t v;
1030
1031 r = sd_bus_message_read(message, "t", &v);
1032 if (r < 0)
1033 return r;
cd0a7a8e 1034 if (v <= 0)
e74f76ca 1035 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
da4d897e 1036
2e59b241 1037 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
da4d897e
TH
1038 if (streq(name, "MemoryLow"))
1039 c->memory_low = v;
1040 else if (streq(name, "MemoryHigh"))
1041 c->memory_high = v;
96e131ea
WC
1042 else if (streq(name, "MemorySwapMax"))
1043 c->memory_swap_max = v;
da4d897e
TH
1044 else
1045 c->memory_max = v;
1046
1047 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
1048
1049 if (v == CGROUP_LIMIT_MAX)
2e59b241 1050 unit_write_settingf(u, flags, name, "%s=infinity", name);
da4d897e 1051 else
2e59b241 1052 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
da4d897e
TH
1053 }
1054
1055 return 1;
1056
66a892ae 1057 } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale", "MemorySwapMaxScale")) {
d58d600e
LP
1058 uint32_t raw;
1059 uint64_t v;
1060
1061 r = sd_bus_message_read(message, "u", &raw);
1062 if (r < 0)
1063 return r;
1064
1065 v = physical_memory_scale(raw, UINT32_MAX);
1066 if (v <= 0 || v == UINT64_MAX)
e74f76ca 1067 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
d58d600e 1068
2e59b241 1069 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d58d600e
LP
1070 const char *e;
1071
1072 /* Chop off suffix */
f7903e8d 1073 assert_se(e = endswith(name, "Scale"));
d58d600e
LP
1074 name = strndupa(name, e - name);
1075
1076 if (streq(name, "MemoryLow"))
1077 c->memory_low = v;
1078 else if (streq(name, "MemoryHigh"))
1079 c->memory_high = v;
66a892ae
LP
1080 else if (streq(name, "MemorySwapMaxScale"))
1081 c->memory_swap_max = v;
1082 else /* MemoryMax */
d58d600e
LP
1083 c->memory_max = v;
1084
1085 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
2e59b241
LP
1086 unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name,
1087 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
d58d600e
LP
1088 }
1089
1090 return 1;
1091
ddca82ac 1092 } else if (streq(name, "MemoryLimit")) {
718db961 1093 uint64_t limit;
b42defe3 1094
718db961
LP
1095 r = sd_bus_message_read(message, "t", &limit);
1096 if (r < 0)
1097 return r;
cd0a7a8e 1098 if (limit <= 0)
e74f76ca 1099 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
b42defe3 1100
2e59b241 1101 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
ddca82ac 1102 c->memory_limit = limit;
e7ab4d1a 1103 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
03a7b521 1104
66a892ae 1105 if (limit == CGROUP_LIMIT_MAX)
2e59b241 1106 unit_write_setting(u, flags, name, "MemoryLimit=infinity");
03a7b521 1107 else
2e59b241 1108 unit_write_settingf(u, flags, name, "MemoryLimit=%" PRIu64, limit);
b42defe3
LP
1109 }
1110
7041efe9
LP
1111 return 1;
1112
f7903e8d 1113 } else if (streq(name, "MemoryLimitScale")) {
d58d600e
LP
1114 uint64_t limit;
1115 uint32_t raw;
1116
1117 r = sd_bus_message_read(message, "u", &raw);
1118 if (r < 0)
1119 return r;
1120
1121 limit = physical_memory_scale(raw, UINT32_MAX);
1122 if (limit <= 0 || limit == UINT64_MAX)
e74f76ca 1123 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
d58d600e 1124
2e59b241 1125 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
d58d600e
LP
1126 c->memory_limit = limit;
1127 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
2e59b241 1128 unit_write_settingf(u, flags, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
f7903e8d 1129 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
d58d600e
LP
1130 }
1131
1132 return 1;
1133
7041efe9
LP
1134 } else if (streq(name, "DevicePolicy")) {
1135 const char *policy;
1136 CGroupDevicePolicy p;
1137
718db961
LP
1138 r = sd_bus_message_read(message, "s", &policy);
1139 if (r < 0)
1140 return r;
7041efe9 1141
7041efe9
LP
1142 p = cgroup_device_policy_from_string(policy);
1143 if (p < 0)
1144 return -EINVAL;
1145
2e59b241 1146 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
7041efe9 1147 c->device_policy = p;
e7ab4d1a 1148 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
2e59b241 1149 unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
7041efe9
LP
1150 }
1151
1152 return 1;
1153
1154 } else if (streq(name, "DeviceAllow")) {
718db961 1155 const char *path, *rwm;
7041efe9
LP
1156 unsigned n = 0;
1157
718db961
LP
1158 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1159 if (r < 0)
1160 return r;
7041efe9 1161
718db961 1162 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 1163
27458ed6
LP
1164 if ((!path_startswith(path, "/dev/") &&
1165 !path_startswith(path, "/run/systemd/inaccessible/") &&
90060676
LP
1166 !startswith(path, "block-") &&
1167 !startswith(path, "char-")) ||
1168 strpbrk(path, WHITESPACE))
e74f76ca 1169 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
7041efe9
LP
1170
1171 if (isempty(rwm))
1172 rwm = "rwm";
1173
718db961 1174 if (!in_charset(rwm, "rwm"))
e74f76ca 1175 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
7041efe9 1176
2e59b241 1177 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
718db961 1178 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
1179
1180 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 1181 if (path_equal(b->path, path)) {
ad7bfffd 1182 a = b;
ad7bfffd
G
1183 break;
1184 }
1185 }
1186
718db961 1187 if (!a) {
ad7bfffd
G
1188 a = new0(CGroupDeviceAllow, 1);
1189 if (!a)
1190 return -ENOMEM;
1191
1192 a->path = strdup(path);
1193 if (!a->path) {
1194 free(a);
1195 return -ENOMEM;
1196 }
718db961
LP
1197
1198 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
1199 }
1200
1201 a->r = !!strchr(rwm, 'r');
1202 a->w = !!strchr(rwm, 'w');
1203 a->m = !!strchr(rwm, 'm');
7041efe9
LP
1204 }
1205
c2756a68 1206 n++;
7041efe9 1207 }
43a99a7a
LP
1208 if (r < 0)
1209 return r;
7041efe9 1210
9c96019d
LP
1211 r = sd_bus_message_exit_container(message);
1212 if (r < 0)
1213 return r;
1214
2e59b241 1215 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
7041efe9
LP
1216 _cleanup_free_ char *buf = NULL;
1217 _cleanup_fclose_ FILE *f = NULL;
1218 CGroupDeviceAllow *a;
1219 size_t size = 0;
1220
1221 if (n == 0) {
1222 while (c->device_allow)
1223 cgroup_context_free_device_allow(c, c->device_allow);
1224 }
1225
e7ab4d1a 1226 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
3051f187 1227
7041efe9
LP
1228 f = open_memstream(&buf, &size);
1229 if (!f)
1230 return -ENOMEM;
1231
4b61c875 1232 fputs_unlocked("DeviceAllow=\n", f);
7041efe9
LP
1233 LIST_FOREACH(device_allow, a, c->device_allow)
1234 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1235
1f2f874c
NC
1236 r = fflush_and_check(f);
1237 if (r < 0)
1238 return r;
2e59b241 1239 unit_write_setting(u, flags, name, buf);
7041efe9
LP
1240 }
1241
b42defe3 1242 return 1;
a931ad47 1243
03a7b521
LP
1244 } else if (streq(name, "TasksAccounting")) {
1245 int b;
1246
1247 r = sd_bus_message_read(message, "b", &b);
1248 if (r < 0)
1249 return r;
1250
2e59b241 1251 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
03a7b521 1252 c->tasks_accounting = b;
e7ab4d1a 1253 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
2e59b241 1254 unit_write_settingf(u, flags, name, "TasksAccounting=%s", yes_no(b));
03a7b521
LP
1255 }
1256
1257 return 1;
1258
1259 } else if (streq(name, "TasksMax")) {
1260 uint64_t limit;
1261
1262 r = sd_bus_message_read(message, "t", &limit);
1263 if (r < 0)
1264 return r;
83f8e808 1265 if (limit <= 0)
e74f76ca 1266 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
03a7b521 1267
2e59b241 1268 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
03a7b521 1269 c->tasks_max = limit;
e7ab4d1a 1270 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
03a7b521
LP
1271
1272 if (limit == (uint64_t) -1)
2e59b241 1273 unit_write_setting(u, flags, name, "TasksMax=infinity");
03a7b521 1274 else
2e59b241 1275 unit_write_settingf(u, flags, name, "TasksMax=%" PRIu64, limit);
03a7b521
LP
1276 }
1277
83f8e808 1278 return 1;
3dc5ca97 1279
83f8e808
LP
1280 } else if (streq(name, "TasksMaxScale")) {
1281 uint64_t limit;
1282 uint32_t raw;
1283
1284 r = sd_bus_message_read(message, "u", &raw);
1285 if (r < 0)
1286 return r;
1287
1288 limit = system_tasks_max_scale(raw, UINT32_MAX);
1289 if (limit <= 0 || limit >= UINT64_MAX)
e74f76ca 1290 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
83f8e808 1291
2e59b241 1292 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
83f8e808
LP
1293 c->tasks_max = limit;
1294 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
2e59b241
LP
1295 unit_write_settingf(u, flags, name, "TasksMax=%" PRIu32 "%%",
1296 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
83f8e808
LP
1297 }
1298
3dc5ca97
LP
1299 return 1;
1300
1301 } else if (streq(name, "IPAccounting")) {
1302 int b;
1303
1304 r = sd_bus_message_read(message, "b", &b);
1305 if (r < 0)
1306 return r;
1307
2e59b241 1308 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3dc5ca97
LP
1309 c->ip_accounting = b;
1310
1311 unit_invalidate_cgroup_bpf(u);
2e59b241 1312 unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
3dc5ca97
LP
1313 }
1314
1315 return 1;
1316
1317 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1318 IPAddressAccessItem **list;
1319 size_t n = 0;
1320
1321 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1322
1323 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1324 if (r < 0)
1325 return r;
1326
1327 for (;;) {
1328 const void *ap;
1329 int32_t family;
1330 uint32_t prefixlen;
1331 size_t an;
1332
1333 r = sd_bus_message_enter_container(message, 'r', "iayu");
1334 if (r < 0)
1335 return r;
1336 if (r == 0)
1337 break;
1338
1339 r = sd_bus_message_read(message, "i", &family);
1340 if (r < 0)
1341 return r;
1342
1343 if (!IN_SET(family, AF_INET, AF_INET6))
e74f76ca 1344 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects IPv4 or IPv6 addresses only.", name);
3dc5ca97
LP
1345
1346 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1347 if (r < 0)
1348 return r;
1349
1350 if (an != FAMILY_ADDRESS_SIZE(family))
e74f76ca 1351 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IP address has wrong size for family (%s, expected %zu, got %zu)",
3dc5ca97
LP
1352 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1353
1354 r = sd_bus_message_read(message, "u", &prefixlen);
1355 if (r < 0)
1356 return r;
1357
1358 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
e74f76ca 1359 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Prefix length %" PRIu32 " too large for address family %s.", prefixlen, af_to_name(family));
3dc5ca97 1360
2e59b241 1361 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3dc5ca97
LP
1362 IPAddressAccessItem *item;
1363
1364 item = new0(IPAddressAccessItem, 1);
1365 if (!item)
1366 return -ENOMEM;
1367
1368 item->family = family;
1369 item->prefixlen = prefixlen;
1370 memcpy(&item->address, ap, an);
1371
1372 LIST_PREPEND(items, *list, item);
1373 }
1374
1375 r = sd_bus_message_exit_container(message);
1376 if (r < 0)
1377 return r;
1378
1379 n++;
1380 }
1381
1382 r = sd_bus_message_exit_container(message);
1383 if (r < 0)
1384 return r;
1385
1274b6c6
LP
1386 *list = ip_address_access_reduce(*list);
1387
2e59b241 1388 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3dc5ca97
LP
1389 _cleanup_free_ char *buf = NULL;
1390 _cleanup_fclose_ FILE *f = NULL;
1391 IPAddressAccessItem *item;
1392 size_t size = 0;
1393
1394 if (n == 0)
1395 *list = ip_address_access_free_all(*list);
1396
1397 unit_invalidate_cgroup_bpf(u);
1398 f = open_memstream(&buf, &size);
1399 if (!f)
1400 return -ENOMEM;
1401
1402 fputs_unlocked(name, f);
1403 fputs_unlocked("=\n", f);
1404
1405 LIST_FOREACH(items, item, *list) {
1406 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1407
1408 errno = 0;
1409 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1410 return errno > 0 ? -errno : -EINVAL;
1411
1412 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1413 }
1414
1415 r = fflush_and_check(f);
1416 if (r < 0)
1417 return r;
2e59b241
LP
1418
1419 unit_write_setting(u, flags, name, buf);
078ba556
LP
1420
1421 if (*list) {
1422 r = bpf_firewall_supported();
1423 if (r < 0)
1424 return r;
ab8519c2
LP
1425 if (r == 0) {
1426 static bool warned = false;
1427
1428 log_full(warned ? LOG_DEBUG : LOG_WARNING,
1429 "Transient unit %s configures an IP firewall, but the local system does not support BPF/cgroup firewalling.\n"
1430 "Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
1431
1432 warned = true;
1433 }
078ba556 1434 }
3dc5ca97
LP
1435 }
1436
03a7b521 1437 return 1;
a931ad47
LP
1438 }
1439
1440 if (u->transient && u->load_state == UNIT_STUB) {
2e59b241 1441 r = bus_cgroup_set_transient_property(u, c, name, message, flags, error);
a931ad47
LP
1442 if (r != 0)
1443 return r;
1444
b42defe3 1445 }
8e2af478
LP
1446
1447 return 0;
1448}