]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
Add SPDX license identifiers to source files under the LGPL
[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,
337 UnitSetPropertiesMode mode,
338 sd_bus_error *error) {
339
340 int r;
341
342 assert(u);
343 assert(c);
344 assert(name);
345 assert(message);
346
347 if (streq(name, "Delegate")) {
348 int b;
349
350 r = sd_bus_message_read(message, "b", &b);
351 if (r < 0)
352 return r;
353
354 if (mode != UNIT_CHECK) {
355 c->delegate = b;
02638280
LP
356 c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
357
b27b4b51 358 unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
a931ad47
LP
359 }
360
02638280
LP
361 return 1;
362
363 } else if (streq(name, "DelegateControllers")) {
364 CGroupMask mask = 0;
365
366 r = sd_bus_message_enter_container(message, 'a', "s");
367 if (r < 0)
368 return r;
369
370 for (;;) {
371 CGroupController cc;
372 const char *t;
373
374 r = sd_bus_message_read(message, "s", &t);
375 if (r < 0)
376 return r;
377 if (r == 0)
378 break;
379
380 cc = cgroup_controller_from_string(t);
381 if (cc < 0)
382 return sd_bus_error_set_errnof(error, EINVAL, "Unknown cgroup contoller '%s'", t);
383
384 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
385 }
386
387 r = sd_bus_message_exit_container(message);
388 if (r < 0)
389 return r;
390
391 if (mode != UNIT_CHECK) {
392 _cleanup_free_ char *t = NULL;
393
394 r = cg_mask_to_string(mask, &t);
395 if (r < 0)
396 return r;
397
398 c->delegate = true;
1bdfc7b9
YW
399 if (mask == 0)
400 c->delegate_controllers = 0;
401 else
402 c->delegate_controllers |= mask;
02638280 403
1bdfc7b9 404 unit_write_drop_in_private_format(u, mode, name, "Delegate=%s", strempty(t));
02638280
LP
405 }
406
a931ad47
LP
407 return 1;
408 }
409
410 return 0;
411}
412
8e2af478
LP
413int bus_cgroup_set_property(
414 Unit *u,
415 CGroupContext *c,
416 const char *name,
718db961 417 sd_bus_message *message,
8e2af478 418 UnitSetPropertiesMode mode,
718db961
LP
419 sd_bus_error *error) {
420
9be57249 421 CGroupIOLimitType iol_type;
718db961 422 int r;
8e2af478 423
8e2af478
LP
424 assert(u);
425 assert(c);
718db961
LP
426 assert(name);
427 assert(message);
8e2af478
LP
428
429 if (streq(name, "CPUAccounting")) {
718db961 430 int b;
8e2af478 431
718db961
LP
432 r = sd_bus_message_read(message, "b", &b);
433 if (r < 0)
434 return r;
8e2af478
LP
435
436 if (mode != UNIT_CHECK) {
8e2af478 437 c->cpu_accounting = b;
e7ab4d1a 438 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
b27b4b51 439 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
b42defe3
LP
440 }
441
442 return 1;
443
66ebf6c0
TH
444 } else if (streq(name, "CPUWeight")) {
445 uint64_t weight;
446
447 r = sd_bus_message_read(message, "t", &weight);
448 if (r < 0)
449 return r;
450
451 if (!CGROUP_WEIGHT_IS_OK(weight))
452 return sd_bus_error_set_errnof(error, EINVAL, "CPUWeight value out of range");
453
454 if (mode != UNIT_CHECK) {
455 c->cpu_weight = weight;
456 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
457
458 if (weight == CGROUP_WEIGHT_INVALID)
459 unit_write_drop_in_private(u, mode, name, "CPUWeight=");
460 else
461 unit_write_drop_in_private_format(u, mode, name, "CPUWeight=%" PRIu64, weight);
462 }
463
464 return 1;
465
466 } else if (streq(name, "StartupCPUWeight")) {
467 uint64_t weight;
468
469 r = sd_bus_message_read(message, "t", &weight);
470 if (r < 0)
471 return r;
472
473 if (!CGROUP_WEIGHT_IS_OK(weight))
474 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUWeight value out of range");
475
476 if (mode != UNIT_CHECK) {
477 c->startup_cpu_weight = weight;
478 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
479
480 if (weight == CGROUP_CPU_SHARES_INVALID)
481 unit_write_drop_in_private(u, mode, name, "StartupCPUWeight=");
482 else
483 unit_write_drop_in_private_format(u, mode, name, "StartupCPUWeight=%" PRIu64, weight);
484 }
485
486 return 1;
487
b42defe3 488 } else if (streq(name, "CPUShares")) {
d53d9474 489 uint64_t shares;
b42defe3 490
d53d9474 491 r = sd_bus_message_read(message, "t", &shares);
718db961
LP
492 if (r < 0)
493 return r;
b42defe3 494
d53d9474
LP
495 if (!CGROUP_CPU_SHARES_IS_OK(shares))
496 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
b42defe3
LP
497
498 if (mode != UNIT_CHECK) {
d53d9474 499 c->cpu_shares = shares;
e7ab4d1a 500 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
501
502 if (shares == CGROUP_CPU_SHARES_INVALID)
b27b4b51 503 unit_write_drop_in_private(u, mode, name, "CPUShares=");
d53d9474 504 else
b27b4b51 505 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
8e2af478
LP
506 }
507
508 return 1;
509
95ae05c0 510 } else if (streq(name, "StartupCPUShares")) {
d53d9474 511 uint64_t shares;
95ae05c0 512
d53d9474 513 r = sd_bus_message_read(message, "t", &shares);
95ae05c0
WC
514 if (r < 0)
515 return r;
516
d53d9474
LP
517 if (!CGROUP_CPU_SHARES_IS_OK(shares))
518 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
95ae05c0
WC
519
520 if (mode != UNIT_CHECK) {
d53d9474 521 c->startup_cpu_shares = shares;
e7ab4d1a 522 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
523
524 if (shares == CGROUP_CPU_SHARES_INVALID)
b27b4b51 525 unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
d53d9474 526 else
b27b4b51 527 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
95ae05c0
WC
528 }
529
530 return 1;
531
b2f8b02e
LP
532 } else if (streq(name, "CPUQuotaPerSecUSec")) {
533 uint64_t u64;
534
535 r = sd_bus_message_read(message, "t", &u64);
536 if (r < 0)
537 return r;
538
539 if (u64 <= 0)
540 return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
541
542 if (mode != UNIT_CHECK) {
543 c->cpu_quota_per_sec_usec = u64;
e7ab4d1a 544 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d4bf82fc
ZJS
545 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
546 unit_write_drop_in_private_format(u, mode, "CPUQuota",
547 "CPUQuota=");
548 else
549 /* config_parse_cpu_quota() requires an integer, so
550 * truncating division is used on purpose here. */
551 unit_write_drop_in_private_format(u, mode, "CPUQuota",
552 "CPUQuota=%0.f%%",
553 (double) (c->cpu_quota_per_sec_usec / 10000));
b2f8b02e
LP
554 }
555
556 return 1;
557
13c31542
TH
558 } else if (streq(name, "IOAccounting")) {
559 int b;
560
561 r = sd_bus_message_read(message, "b", &b);
562 if (r < 0)
563 return r;
564
565 if (mode != UNIT_CHECK) {
566 c->io_accounting = b;
567 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
b27b4b51 568 unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
13c31542
TH
569 }
570
571 return 1;
572
573 } else if (streq(name, "IOWeight")) {
574 uint64_t weight;
575
576 r = sd_bus_message_read(message, "t", &weight);
577 if (r < 0)
578 return r;
579
580 if (!CGROUP_WEIGHT_IS_OK(weight))
581 return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
582
583 if (mode != UNIT_CHECK) {
584 c->io_weight = weight;
585 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
586
587 if (weight == CGROUP_WEIGHT_INVALID)
b27b4b51 588 unit_write_drop_in_private(u, mode, name, "IOWeight=");
13c31542 589 else
b27b4b51 590 unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
13c31542
TH
591 }
592
593 return 1;
594
595 } else if (streq(name, "StartupIOWeight")) {
596 uint64_t weight;
597
598 r = sd_bus_message_read(message, "t", &weight);
599 if (r < 0)
600 return r;
601
602 if (CGROUP_WEIGHT_IS_OK(weight))
603 return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
604
605 if (mode != UNIT_CHECK) {
606 c->startup_io_weight = weight;
607 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
608
609 if (weight == CGROUP_WEIGHT_INVALID)
b27b4b51 610 unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
13c31542 611 else
b27b4b51 612 unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
13c31542
TH
613 }
614
615 return 1;
616
9be57249 617 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
13c31542 618 const char *path;
13c31542
TH
619 unsigned n = 0;
620 uint64_t u64;
621
13c31542
TH
622 r = sd_bus_message_enter_container(message, 'a', "(st)");
623 if (r < 0)
624 return r;
625
626 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
627
628 if (mode != UNIT_CHECK) {
629 CGroupIODeviceLimit *a = NULL, *b;
630
631 LIST_FOREACH(device_limits, b, c->io_device_limits) {
632 if (path_equal(path, b->path)) {
633 a = b;
634 break;
635 }
636 }
637
638 if (!a) {
9be57249
TH
639 CGroupIOLimitType type;
640
13c31542
TH
641 a = new0(CGroupIODeviceLimit, 1);
642 if (!a)
643 return -ENOMEM;
644
645 a->path = strdup(path);
646 if (!a->path) {
647 free(a);
648 return -ENOMEM;
649 }
650
9be57249
TH
651 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
652 a->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
653
654 LIST_PREPEND(device_limits, c->io_device_limits, a);
655 }
656
9be57249 657 a->limits[iol_type] = u64;
13c31542
TH
658 }
659
660 n++;
661 }
662 if (r < 0)
663 return r;
664
665 r = sd_bus_message_exit_container(message);
666 if (r < 0)
667 return r;
668
669 if (mode != UNIT_CHECK) {
670 CGroupIODeviceLimit *a;
671 _cleanup_free_ char *buf = NULL;
672 _cleanup_fclose_ FILE *f = NULL;
673 size_t size = 0;
674
675 if (n == 0) {
676 LIST_FOREACH(device_limits, a, c->io_device_limits)
9be57249 677 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
13c31542
TH
678 }
679
680 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
681
682 f = open_memstream(&buf, &size);
683 if (!f)
684 return -ENOMEM;
685
9be57249
TH
686 fprintf(f, "%s=\n", name);
687 LIST_FOREACH(device_limits, a, c->io_device_limits)
688 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
689 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
13c31542
TH
690
691 r = fflush_and_check(f);
692 if (r < 0)
693 return r;
694 unit_write_drop_in_private(u, mode, name, buf);
695 }
696
697 return 1;
698
699 } else if (streq(name, "IODeviceWeight")) {
700 const char *path;
701 uint64_t weight;
702 unsigned n = 0;
703
704 r = sd_bus_message_enter_container(message, 'a', "(st)");
705 if (r < 0)
706 return r;
707
708 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
709
710 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
711 return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
712
713 if (mode != UNIT_CHECK) {
714 CGroupIODeviceWeight *a = NULL, *b;
715
716 LIST_FOREACH(device_weights, b, c->io_device_weights) {
717 if (path_equal(b->path, path)) {
718 a = b;
719 break;
720 }
721 }
722
723 if (!a) {
724 a = new0(CGroupIODeviceWeight, 1);
725 if (!a)
726 return -ENOMEM;
727
728 a->path = strdup(path);
729 if (!a->path) {
730 free(a);
731 return -ENOMEM;
732 }
733 LIST_PREPEND(device_weights,c->io_device_weights, a);
734 }
735
736 a->weight = weight;
737 }
738
739 n++;
740 }
741
742 r = sd_bus_message_exit_container(message);
743 if (r < 0)
744 return r;
745
746 if (mode != UNIT_CHECK) {
747 _cleanup_free_ char *buf = NULL;
748 _cleanup_fclose_ FILE *f = NULL;
749 CGroupIODeviceWeight *a;
750 size_t size = 0;
751
752 if (n == 0) {
753 while (c->io_device_weights)
754 cgroup_context_free_io_device_weight(c, c->io_device_weights);
755 }
756
757 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
758
759 f = open_memstream(&buf, &size);
760 if (!f)
761 return -ENOMEM;
762
4b61c875 763 fputs_unlocked("IODeviceWeight=\n", f);
13c31542
TH
764 LIST_FOREACH(device_weights, a, c->io_device_weights)
765 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
766
767 r = fflush_and_check(f);
768 if (r < 0)
769 return r;
770 unit_write_drop_in_private(u, mode, name, buf);
771 }
772
773 return 1;
774
8e2af478 775 } else if (streq(name, "BlockIOAccounting")) {
718db961 776 int b;
8e2af478 777
718db961
LP
778 r = sd_bus_message_read(message, "b", &b);
779 if (r < 0)
780 return r;
8e2af478
LP
781
782 if (mode != UNIT_CHECK) {
8e2af478 783 c->blockio_accounting = b;
e7ab4d1a 784 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
b27b4b51 785 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
786 }
787
788 return 1;
b42defe3
LP
789
790 } else if (streq(name, "BlockIOWeight")) {
d53d9474 791 uint64_t weight;
b42defe3 792
d53d9474 793 r = sd_bus_message_read(message, "t", &weight);
718db961
LP
794 if (r < 0)
795 return r;
b42defe3 796
d53d9474
LP
797 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
798 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
b42defe3
LP
799
800 if (mode != UNIT_CHECK) {
d53d9474 801 c->blockio_weight = weight;
e7ab4d1a 802 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
803
804 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
b27b4b51 805 unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
d53d9474 806 else
b27b4b51 807 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
b42defe3
LP
808 }
809
810 return 1;
95ae05c0
WC
811
812 } else if (streq(name, "StartupBlockIOWeight")) {
d53d9474 813 uint64_t weight;
95ae05c0 814
d53d9474 815 r = sd_bus_message_read(message, "t", &weight);
95ae05c0
WC
816 if (r < 0)
817 return r;
818
6fb09269 819 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
d53d9474 820 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
95ae05c0
WC
821
822 if (mode != UNIT_CHECK) {
d53d9474 823 c->startup_blockio_weight = weight;
e7ab4d1a 824 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
825
826 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
b27b4b51 827 unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
d53d9474 828 else
b27b4b51 829 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
95ae05c0
WC
830 }
831
832 return 1;
b42defe3 833
cd0a7a8e 834 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
718db961 835 const char *path;
f004c2ca 836 bool read = true;
718db961
LP
837 unsigned n = 0;
838 uint64_t u64;
f004c2ca
G
839
840 if (streq(name, "BlockIOWriteBandwidth"))
841 read = false;
842
718db961
LP
843 r = sd_bus_message_enter_container(message, 'a', "(st)");
844 if (r < 0)
845 return r;
f004c2ca 846
718db961 847 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca
G
848
849 if (mode != UNIT_CHECK) {
718db961 850 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
851
852 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
979d0311 853 if (path_equal(path, b->path)) {
f004c2ca 854 a = b;
f004c2ca
G
855 break;
856 }
857 }
858
718db961 859 if (!a) {
f004c2ca
G
860 a = new0(CGroupBlockIODeviceBandwidth, 1);
861 if (!a)
862 return -ENOMEM;
863
979d0311
TH
864 a->rbps = CGROUP_LIMIT_MAX;
865 a->wbps = CGROUP_LIMIT_MAX;
f004c2ca
G
866 a->path = strdup(path);
867 if (!a->path) {
868 free(a);
869 return -ENOMEM;
870 }
718db961
LP
871
872 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
873 }
874
979d0311
TH
875 if (read)
876 a->rbps = u64;
877 else
878 a->wbps = u64;
f004c2ca
G
879 }
880
881 n++;
f004c2ca 882 }
718db961
LP
883 if (r < 0)
884 return r;
f004c2ca 885
9c96019d
LP
886 r = sd_bus_message_exit_container(message);
887 if (r < 0)
888 return r;
889
f004c2ca 890 if (mode != UNIT_CHECK) {
979d0311 891 CGroupBlockIODeviceBandwidth *a;
f004c2ca
G
892 _cleanup_free_ char *buf = NULL;
893 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
894 size_t size = 0;
895
896 if (n == 0) {
979d0311
TH
897 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
898 if (read)
899 a->rbps = CGROUP_LIMIT_MAX;
900 else
901 a->wbps = CGROUP_LIMIT_MAX;
902 }
f004c2ca
G
903 }
904
e7ab4d1a 905 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 906
f004c2ca
G
907 f = open_memstream(&buf, &size);
908 if (!f)
909 return -ENOMEM;
910
7d6884b6 911 if (read) {
4b61c875 912 fputs_unlocked("BlockIOReadBandwidth=\n", f);
7d6884b6 913 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
914 if (a->rbps != CGROUP_LIMIT_MAX)
915 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
f004c2ca 916 } else {
4b61c875 917 fputs_unlocked("BlockIOWriteBandwidth=\n", f);
f004c2ca 918 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
919 if (a->wbps != CGROUP_LIMIT_MAX)
920 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
f004c2ca
G
921 }
922
1f2f874c
NC
923 r = fflush_and_check(f);
924 if (r < 0)
925 return r;
6f68ecb4
G
926 unit_write_drop_in_private(u, mode, name, buf);
927 }
928
929 return 1;
930
931 } else if (streq(name, "BlockIODeviceWeight")) {
718db961 932 const char *path;
d53d9474 933 uint64_t weight;
6f68ecb4
G
934 unsigned n = 0;
935
718db961
LP
936 r = sd_bus_message_enter_container(message, 'a', "(st)");
937 if (r < 0)
938 return r;
6f68ecb4 939
d53d9474 940 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
6f68ecb4 941
d53d9474 942 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
718db961 943 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
6f68ecb4
G
944
945 if (mode != UNIT_CHECK) {
718db961 946 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
947
948 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
949 if (path_equal(b->path, path)) {
950 a = b;
6f68ecb4
G
951 break;
952 }
953 }
954
718db961 955 if (!a) {
6f68ecb4
G
956 a = new0(CGroupBlockIODeviceWeight, 1);
957 if (!a)
958 return -ENOMEM;
959
960 a->path = strdup(path);
961 if (!a->path) {
962 free(a);
963 return -ENOMEM;
964 }
718db961 965 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
966 }
967
d53d9474 968 a->weight = weight;
6f68ecb4
G
969 }
970
971 n++;
6f68ecb4
G
972 }
973
9c96019d
LP
974 r = sd_bus_message_exit_container(message);
975 if (r < 0)
976 return r;
977
6f68ecb4
G
978 if (mode != UNIT_CHECK) {
979 _cleanup_free_ char *buf = NULL;
980 _cleanup_fclose_ FILE *f = NULL;
981 CGroupBlockIODeviceWeight *a;
982 size_t size = 0;
983
984 if (n == 0) {
985 while (c->blockio_device_weights)
986 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
987 }
988
e7ab4d1a 989 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 990
6f68ecb4
G
991 f = open_memstream(&buf, &size);
992 if (!f)
993 return -ENOMEM;
994
4b61c875 995 fputs_unlocked("BlockIODeviceWeight=\n", f);
6f68ecb4 996 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
d53d9474 997 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
6f68ecb4 998
1f2f874c
NC
999 r = fflush_and_check(f);
1000 if (r < 0)
1001 return r;
f004c2ca
G
1002 unit_write_drop_in_private(u, mode, name, buf);
1003 }
1004
1005 return 1;
1006
8e2af478 1007 } else if (streq(name, "MemoryAccounting")) {
718db961 1008 int b;
8e2af478 1009
718db961
LP
1010 r = sd_bus_message_read(message, "b", &b);
1011 if (r < 0)
1012 return r;
8e2af478
LP
1013
1014 if (mode != UNIT_CHECK) {
b42defe3 1015 c->memory_accounting = b;
e7ab4d1a 1016 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
b27b4b51 1017 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
1018 }
1019
1020 return 1;
8e2af478 1021
96e131ea 1022 } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax")) {
da4d897e
TH
1023 uint64_t v;
1024
1025 r = sd_bus_message_read(message, "t", &v);
1026 if (r < 0)
1027 return r;
cd0a7a8e
LP
1028 if (v <= 0)
1029 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
da4d897e
TH
1030
1031 if (mode != UNIT_CHECK) {
1032 if (streq(name, "MemoryLow"))
1033 c->memory_low = v;
1034 else if (streq(name, "MemoryHigh"))
1035 c->memory_high = v;
96e131ea
WC
1036 else if (streq(name, "MemorySwapMax"))
1037 c->memory_swap_max = v;
da4d897e
TH
1038 else
1039 c->memory_max = v;
1040
1041 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
1042
1043 if (v == CGROUP_LIMIT_MAX)
799ec134 1044 unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name);
da4d897e 1045 else
b27b4b51 1046 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v);
da4d897e
TH
1047 }
1048
1049 return 1;
1050
f7903e8d 1051 } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale")) {
d58d600e
LP
1052 uint32_t raw;
1053 uint64_t v;
1054
1055 r = sd_bus_message_read(message, "u", &raw);
1056 if (r < 0)
1057 return r;
1058
1059 v = physical_memory_scale(raw, UINT32_MAX);
1060 if (v <= 0 || v == UINT64_MAX)
1061 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
1062
1063 if (mode != UNIT_CHECK) {
1064 const char *e;
1065
1066 /* Chop off suffix */
f7903e8d 1067 assert_se(e = endswith(name, "Scale"));
d58d600e
LP
1068 name = strndupa(name, e - name);
1069
1070 if (streq(name, "MemoryLow"))
1071 c->memory_low = v;
1072 else if (streq(name, "MemoryHigh"))
1073 c->memory_high = v;
1074 else
1075 c->memory_max = v;
1076
1077 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
f7903e8d
LP
1078 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name,
1079 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
d58d600e
LP
1080 }
1081
1082 return 1;
1083
ddca82ac 1084 } else if (streq(name, "MemoryLimit")) {
718db961 1085 uint64_t limit;
b42defe3 1086
718db961
LP
1087 r = sd_bus_message_read(message, "t", &limit);
1088 if (r < 0)
1089 return r;
cd0a7a8e
LP
1090 if (limit <= 0)
1091 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
b42defe3
LP
1092
1093 if (mode != UNIT_CHECK) {
ddca82ac 1094 c->memory_limit = limit;
e7ab4d1a 1095 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
03a7b521
LP
1096
1097 if (limit == (uint64_t) -1)
b27b4b51 1098 unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
03a7b521 1099 else
b27b4b51 1100 unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
b42defe3
LP
1101 }
1102
7041efe9
LP
1103 return 1;
1104
f7903e8d 1105 } else if (streq(name, "MemoryLimitScale")) {
d58d600e
LP
1106 uint64_t limit;
1107 uint32_t raw;
1108
1109 r = sd_bus_message_read(message, "u", &raw);
1110 if (r < 0)
1111 return r;
1112
1113 limit = physical_memory_scale(raw, UINT32_MAX);
1114 if (limit <= 0 || limit == UINT64_MAX)
1115 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
1116
1117 if (mode != UNIT_CHECK) {
1118 c->memory_limit = limit;
1119 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
f7903e8d
LP
1120 unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
1121 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
d58d600e
LP
1122 }
1123
1124 return 1;
1125
7041efe9
LP
1126 } else if (streq(name, "DevicePolicy")) {
1127 const char *policy;
1128 CGroupDevicePolicy p;
1129
718db961
LP
1130 r = sd_bus_message_read(message, "s", &policy);
1131 if (r < 0)
1132 return r;
7041efe9 1133
7041efe9
LP
1134 p = cgroup_device_policy_from_string(policy);
1135 if (p < 0)
1136 return -EINVAL;
1137
1138 if (mode != UNIT_CHECK) {
7041efe9 1139 c->device_policy = p;
e7ab4d1a 1140 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
b27b4b51 1141 unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy);
7041efe9
LP
1142 }
1143
1144 return 1;
1145
1146 } else if (streq(name, "DeviceAllow")) {
718db961 1147 const char *path, *rwm;
7041efe9
LP
1148 unsigned n = 0;
1149
718db961
LP
1150 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1151 if (r < 0)
1152 return r;
7041efe9 1153
718db961 1154 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 1155
27458ed6
LP
1156 if ((!path_startswith(path, "/dev/") &&
1157 !path_startswith(path, "/run/systemd/inaccessible/") &&
90060676
LP
1158 !startswith(path, "block-") &&
1159 !startswith(path, "char-")) ||
1160 strpbrk(path, WHITESPACE))
1161 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
7041efe9
LP
1162
1163 if (isempty(rwm))
1164 rwm = "rwm";
1165
718db961
LP
1166 if (!in_charset(rwm, "rwm"))
1167 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
7041efe9 1168
7041efe9 1169 if (mode != UNIT_CHECK) {
718db961 1170 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
1171
1172 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 1173 if (path_equal(b->path, path)) {
ad7bfffd 1174 a = b;
ad7bfffd
G
1175 break;
1176 }
1177 }
1178
718db961 1179 if (!a) {
ad7bfffd
G
1180 a = new0(CGroupDeviceAllow, 1);
1181 if (!a)
1182 return -ENOMEM;
1183
1184 a->path = strdup(path);
1185 if (!a->path) {
1186 free(a);
1187 return -ENOMEM;
1188 }
718db961
LP
1189
1190 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
1191 }
1192
1193 a->r = !!strchr(rwm, 'r');
1194 a->w = !!strchr(rwm, 'w');
1195 a->m = !!strchr(rwm, 'm');
7041efe9
LP
1196 }
1197
c2756a68 1198 n++;
7041efe9 1199 }
43a99a7a
LP
1200 if (r < 0)
1201 return r;
7041efe9 1202
9c96019d
LP
1203 r = sd_bus_message_exit_container(message);
1204 if (r < 0)
1205 return r;
1206
7041efe9
LP
1207 if (mode != UNIT_CHECK) {
1208 _cleanup_free_ char *buf = NULL;
1209 _cleanup_fclose_ FILE *f = NULL;
1210 CGroupDeviceAllow *a;
1211 size_t size = 0;
1212
1213 if (n == 0) {
1214 while (c->device_allow)
1215 cgroup_context_free_device_allow(c, c->device_allow);
1216 }
1217
e7ab4d1a 1218 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
3051f187 1219
7041efe9
LP
1220 f = open_memstream(&buf, &size);
1221 if (!f)
1222 return -ENOMEM;
1223
4b61c875 1224 fputs_unlocked("DeviceAllow=\n", f);
7041efe9
LP
1225 LIST_FOREACH(device_allow, a, c->device_allow)
1226 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1227
1f2f874c
NC
1228 r = fflush_and_check(f);
1229 if (r < 0)
1230 return r;
b9ec9359 1231 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
1232 }
1233
b42defe3 1234 return 1;
a931ad47 1235
03a7b521
LP
1236 } else if (streq(name, "TasksAccounting")) {
1237 int b;
1238
1239 r = sd_bus_message_read(message, "b", &b);
1240 if (r < 0)
1241 return r;
1242
1243 if (mode != UNIT_CHECK) {
1244 c->tasks_accounting = b;
e7ab4d1a 1245 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
b27b4b51 1246 unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
03a7b521
LP
1247 }
1248
1249 return 1;
1250
1251 } else if (streq(name, "TasksMax")) {
1252 uint64_t limit;
1253
1254 r = sd_bus_message_read(message, "t", &limit);
1255 if (r < 0)
1256 return r;
83f8e808
LP
1257 if (limit <= 0)
1258 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
03a7b521
LP
1259
1260 if (mode != UNIT_CHECK) {
1261 c->tasks_max = limit;
e7ab4d1a 1262 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
03a7b521
LP
1263
1264 if (limit == (uint64_t) -1)
b27b4b51 1265 unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
03a7b521 1266 else
b27b4b51 1267 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
03a7b521
LP
1268 }
1269
83f8e808 1270 return 1;
3dc5ca97 1271
83f8e808
LP
1272 } else if (streq(name, "TasksMaxScale")) {
1273 uint64_t limit;
1274 uint32_t raw;
1275
1276 r = sd_bus_message_read(message, "u", &raw);
1277 if (r < 0)
1278 return r;
1279
1280 limit = system_tasks_max_scale(raw, UINT32_MAX);
1281 if (limit <= 0 || limit >= UINT64_MAX)
1282 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
1283
1284 if (mode != UNIT_CHECK) {
1285 c->tasks_max = limit;
1286 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1287 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%",
1288 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
1289 }
1290
3dc5ca97
LP
1291 return 1;
1292
1293 } else if (streq(name, "IPAccounting")) {
1294 int b;
1295
1296 r = sd_bus_message_read(message, "b", &b);
1297 if (r < 0)
1298 return r;
1299
1300 if (mode != UNIT_CHECK) {
1301 c->ip_accounting = b;
1302
1303 unit_invalidate_cgroup_bpf(u);
1304 unit_write_drop_in_private(u, mode, name, b ? "IPAccounting=yes" : "IPAccounting=no");
1305 }
1306
1307 return 1;
1308
1309 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1310 IPAddressAccessItem **list;
1311 size_t n = 0;
1312
1313 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1314
1315 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1316 if (r < 0)
1317 return r;
1318
1319 for (;;) {
1320 const void *ap;
1321 int32_t family;
1322 uint32_t prefixlen;
1323 size_t an;
1324
1325 r = sd_bus_message_enter_container(message, 'r', "iayu");
1326 if (r < 0)
1327 return r;
1328 if (r == 0)
1329 break;
1330
1331 r = sd_bus_message_read(message, "i", &family);
1332 if (r < 0)
1333 return r;
1334
1335 if (!IN_SET(family, AF_INET, AF_INET6))
4fe66c86 1336 return sd_bus_error_set_errnof(error, EINVAL, "%s= expects IPv4 or IPv6 addresses only.", name);
3dc5ca97
LP
1337
1338 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1339 if (r < 0)
1340 return r;
1341
1342 if (an != FAMILY_ADDRESS_SIZE(family))
1343 return sd_bus_error_set_errnof(error, EINVAL, "IP address has wrong size for family (%s, expected %zu, got %zu)",
1344 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1345
1346 r = sd_bus_message_read(message, "u", &prefixlen);
1347 if (r < 0)
1348 return r;
1349
1350 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
4fe66c86 1351 return sd_bus_error_set_errnof(error, EINVAL, "Prefix length %" PRIu32 " too large for address family %s.", prefixlen, af_to_name(family));
3dc5ca97
LP
1352
1353 if (mode != UNIT_CHECK) {
1354 IPAddressAccessItem *item;
1355
1356 item = new0(IPAddressAccessItem, 1);
1357 if (!item)
1358 return -ENOMEM;
1359
1360 item->family = family;
1361 item->prefixlen = prefixlen;
1362 memcpy(&item->address, ap, an);
1363
1364 LIST_PREPEND(items, *list, item);
1365 }
1366
1367 r = sd_bus_message_exit_container(message);
1368 if (r < 0)
1369 return r;
1370
1371 n++;
1372 }
1373
1374 r = sd_bus_message_exit_container(message);
1375 if (r < 0)
1376 return r;
1377
1274b6c6
LP
1378 *list = ip_address_access_reduce(*list);
1379
3dc5ca97
LP
1380 if (mode != UNIT_CHECK) {
1381 _cleanup_free_ char *buf = NULL;
1382 _cleanup_fclose_ FILE *f = NULL;
1383 IPAddressAccessItem *item;
1384 size_t size = 0;
1385
1386 if (n == 0)
1387 *list = ip_address_access_free_all(*list);
1388
1389 unit_invalidate_cgroup_bpf(u);
1390 f = open_memstream(&buf, &size);
1391 if (!f)
1392 return -ENOMEM;
1393
1394 fputs_unlocked(name, f);
1395 fputs_unlocked("=\n", f);
1396
1397 LIST_FOREACH(items, item, *list) {
1398 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1399
1400 errno = 0;
1401 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1402 return errno > 0 ? -errno : -EINVAL;
1403
1404 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1405 }
1406
1407 r = fflush_and_check(f);
1408 if (r < 0)
1409 return r;
1410 unit_write_drop_in_private(u, mode, name, buf);
078ba556
LP
1411
1412 if (*list) {
1413 r = bpf_firewall_supported();
1414 if (r < 0)
1415 return r;
ab8519c2
LP
1416 if (r == 0) {
1417 static bool warned = false;
1418
1419 log_full(warned ? LOG_DEBUG : LOG_WARNING,
1420 "Transient unit %s configures an IP firewall, but the local system does not support BPF/cgroup firewalling.\n"
1421 "Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
1422
1423 warned = true;
1424 }
078ba556 1425 }
3dc5ca97
LP
1426 }
1427
03a7b521 1428 return 1;
a931ad47
LP
1429 }
1430
1431 if (u->transient && u->load_state == UNIT_STUB) {
1432 r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
1433 if (r != 0)
1434 return r;
1435
b42defe3 1436 }
8e2af478
LP
1437
1438 return 0;
1439}