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