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