]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
Merge pull request #11484 from keszybz/udevadm-error-logs
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <arpa/inet.h>
4
5 #include "af-list.h"
6 #include "alloc-util.h"
7 #include "bpf-firewall.h"
8 #include "bus-get-properties.h"
9 #include "cgroup-util.h"
10 #include "cgroup.h"
11 #include "core-varlink.h"
12 #include "dbus-cgroup.h"
13 #include "dbus-util.h"
14 #include "errno-util.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "limits-util.h"
18 #include "path-util.h"
19
20 BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve);
21
22 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
23 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_mode, managed_oom_mode, ManagedOOMMode);
24
25 static int property_get_cgroup_mask(
26 sd_bus *bus,
27 const char *path,
28 const char *interface,
29 const char *property,
30 sd_bus_message *reply,
31 void *userdata,
32 sd_bus_error *error) {
33
34 CGroupMask *mask = userdata;
35 int r;
36
37 assert(bus);
38 assert(reply);
39
40 r = sd_bus_message_open_container(reply, 'a', "s");
41 if (r < 0)
42 return r;
43
44 for (CGroupController ctrl = 0; ctrl < _CGROUP_CONTROLLER_MAX; ctrl++) {
45 if ((*mask & CGROUP_CONTROLLER_TO_MASK(ctrl)) == 0)
46 continue;
47
48 r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(ctrl));
49 if (r < 0)
50 return r;
51 }
52
53 return sd_bus_message_close_container(reply);
54 }
55
56 static int property_get_delegate_controllers(
57 sd_bus *bus,
58 const char *path,
59 const char *interface,
60 const char *property,
61 sd_bus_message *reply,
62 void *userdata,
63 sd_bus_error *error) {
64
65 CGroupContext *c = userdata;
66
67 assert(bus);
68 assert(reply);
69 assert(c);
70
71 if (!c->delegate)
72 return sd_bus_message_append(reply, "as", 0);
73
74 return property_get_cgroup_mask(bus, path, interface, property, reply, &c->delegate_controllers, error);
75 }
76
77 static int property_get_cpuset(
78 sd_bus *bus,
79 const char *path,
80 const char *interface,
81 const char *property,
82 sd_bus_message *reply,
83 void *userdata,
84 sd_bus_error *error) {
85
86 CPUSet *cpus = userdata;
87 _cleanup_free_ uint8_t *array = NULL;
88 size_t allocated;
89
90 assert(bus);
91 assert(reply);
92 assert(cpus);
93
94 (void) cpu_set_to_dbus(cpus, &array, &allocated);
95 return sd_bus_message_append_array(reply, 'y', array, allocated);
96 }
97
98 static int property_get_io_device_weight(
99 sd_bus *bus,
100 const char *path,
101 const char *interface,
102 const char *property,
103 sd_bus_message *reply,
104 void *userdata,
105 sd_bus_error *error) {
106
107 CGroupContext *c = userdata;
108 CGroupIODeviceWeight *w;
109 int r;
110
111 assert(bus);
112 assert(reply);
113 assert(c);
114
115 r = sd_bus_message_open_container(reply, 'a', "(st)");
116 if (r < 0)
117 return r;
118
119 LIST_FOREACH(device_weights, w, c->io_device_weights) {
120 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
121 if (r < 0)
122 return r;
123 }
124
125 return sd_bus_message_close_container(reply);
126 }
127
128 static int property_get_io_device_limits(
129 sd_bus *bus,
130 const char *path,
131 const char *interface,
132 const char *property,
133 sd_bus_message *reply,
134 void *userdata,
135 sd_bus_error *error) {
136
137 CGroupContext *c = userdata;
138 CGroupIODeviceLimit *l;
139 int r;
140
141 assert(bus);
142 assert(reply);
143 assert(c);
144
145 r = sd_bus_message_open_container(reply, 'a', "(st)");
146 if (r < 0)
147 return r;
148
149 LIST_FOREACH(device_limits, l, c->io_device_limits) {
150 CGroupIOLimitType type;
151
152 type = cgroup_io_limit_type_from_string(property);
153 if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
154 continue;
155
156 r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
157 if (r < 0)
158 return r;
159 }
160
161 return sd_bus_message_close_container(reply);
162 }
163
164 static int property_get_io_device_latency(
165 sd_bus *bus,
166 const char *path,
167 const char *interface,
168 const char *property,
169 sd_bus_message *reply,
170 void *userdata,
171 sd_bus_error *error) {
172
173 CGroupContext *c = userdata;
174 CGroupIODeviceLatency *l;
175 int r;
176
177 assert(bus);
178 assert(reply);
179 assert(c);
180
181 r = sd_bus_message_open_container(reply, 'a', "(st)");
182 if (r < 0)
183 return r;
184
185 LIST_FOREACH(device_latencies, l, c->io_device_latencies) {
186 r = sd_bus_message_append(reply, "(st)", l->path, l->target_usec);
187 if (r < 0)
188 return r;
189 }
190
191 return sd_bus_message_close_container(reply);
192 }
193
194 static int property_get_blockio_device_weight(
195 sd_bus *bus,
196 const char *path,
197 const char *interface,
198 const char *property,
199 sd_bus_message *reply,
200 void *userdata,
201 sd_bus_error *error) {
202
203 CGroupContext *c = userdata;
204 CGroupBlockIODeviceWeight *w;
205 int r;
206
207 assert(bus);
208 assert(reply);
209 assert(c);
210
211 r = sd_bus_message_open_container(reply, 'a', "(st)");
212 if (r < 0)
213 return r;
214
215 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
216 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
217 if (r < 0)
218 return r;
219 }
220
221 return sd_bus_message_close_container(reply);
222 }
223
224 static int property_get_blockio_device_bandwidths(
225 sd_bus *bus,
226 const char *path,
227 const char *interface,
228 const char *property,
229 sd_bus_message *reply,
230 void *userdata,
231 sd_bus_error *error) {
232
233 CGroupContext *c = userdata;
234 CGroupBlockIODeviceBandwidth *b;
235 int r;
236
237 assert(bus);
238 assert(reply);
239 assert(c);
240
241 r = sd_bus_message_open_container(reply, 'a', "(st)");
242 if (r < 0)
243 return r;
244
245 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
246 uint64_t v;
247
248 if (streq(property, "BlockIOReadBandwidth"))
249 v = b->rbps;
250 else
251 v = b->wbps;
252
253 if (v == CGROUP_LIMIT_MAX)
254 continue;
255
256 r = sd_bus_message_append(reply, "(st)", b->path, v);
257 if (r < 0)
258 return r;
259 }
260
261 return sd_bus_message_close_container(reply);
262 }
263
264 static int property_get_device_allow(
265 sd_bus *bus,
266 const char *path,
267 const char *interface,
268 const char *property,
269 sd_bus_message *reply,
270 void *userdata,
271 sd_bus_error *error) {
272
273 CGroupContext *c = userdata;
274 CGroupDeviceAllow *a;
275 int r;
276
277 assert(bus);
278 assert(reply);
279 assert(c);
280
281 r = sd_bus_message_open_container(reply, 'a', "(ss)");
282 if (r < 0)
283 return r;
284
285 LIST_FOREACH(device_allow, a, c->device_allow) {
286 unsigned k = 0;
287 char rwm[4];
288
289 if (a->r)
290 rwm[k++] = 'r';
291 if (a->w)
292 rwm[k++] = 'w';
293 if (a->m)
294 rwm[k++] = 'm';
295
296 rwm[k] = 0;
297
298 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
299 if (r < 0)
300 return r;
301 }
302
303 return sd_bus_message_close_container(reply);
304 }
305
306 static int property_get_ip_address_access(
307 sd_bus *bus,
308 const char *path,
309 const char *interface,
310 const char *property,
311 sd_bus_message *reply,
312 void *userdata,
313 sd_bus_error *error) {
314
315 IPAddressAccessItem** items = userdata, *i;
316 int r;
317
318 r = sd_bus_message_open_container(reply, 'a', "(iayu)");
319 if (r < 0)
320 return r;
321
322 LIST_FOREACH(items, i, *items) {
323
324 r = sd_bus_message_open_container(reply, 'r', "iayu");
325 if (r < 0)
326 return r;
327
328 r = sd_bus_message_append(reply, "i", i->family);
329 if (r < 0)
330 return r;
331
332 r = sd_bus_message_append_array(reply, 'y', &i->address, FAMILY_ADDRESS_SIZE(i->family));
333 if (r < 0)
334 return r;
335
336 r = sd_bus_message_append(reply, "u", (uint32_t) i->prefixlen);
337 if (r < 0)
338 return r;
339
340 r = sd_bus_message_close_container(reply);
341 if (r < 0)
342 return r;
343 }
344
345 return sd_bus_message_close_container(reply);
346 }
347
348 const sd_bus_vtable bus_cgroup_vtable[] = {
349 SD_BUS_VTABLE_START(0),
350 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
351 SD_BUS_PROPERTY("DelegateControllers", "as", property_get_delegate_controllers, 0, 0),
352 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
353 SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0),
354 SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0),
355 SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
356 SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
357 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
358 SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
359 SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0),
360 SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0),
361 SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
362 SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
363 SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
364 SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
365 SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
366 SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
367 SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
368 SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
369 SD_BUS_PROPERTY("IODeviceLatencyTargetUSec", "a(st)", property_get_io_device_latency, 0, 0),
370 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
371 SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
372 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
373 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
374 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
375 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
376 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
377 SD_BUS_PROPERTY("DefaultMemoryLow", "t", NULL, offsetof(CGroupContext, default_memory_low), 0),
378 SD_BUS_PROPERTY("DefaultMemoryMin", "t", NULL, offsetof(CGroupContext, default_memory_min), 0),
379 SD_BUS_PROPERTY("MemoryMin", "t", NULL, offsetof(CGroupContext, memory_min), 0),
380 SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
381 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
382 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
383 SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
384 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
385 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
386 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
387 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
388 SD_BUS_PROPERTY("TasksMax", "t", bus_property_get_tasks_max, offsetof(CGroupContext, tasks_max), 0),
389 SD_BUS_PROPERTY("IPAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, ip_accounting), 0),
390 SD_BUS_PROPERTY("IPAddressAllow", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_allow), 0),
391 SD_BUS_PROPERTY("IPAddressDeny", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_deny), 0),
392 SD_BUS_PROPERTY("IPIngressFilterPath", "as", NULL, offsetof(CGroupContext, ip_filters_ingress), 0),
393 SD_BUS_PROPERTY("IPEgressFilterPath", "as", NULL, offsetof(CGroupContext, ip_filters_egress), 0),
394 SD_BUS_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0),
395 SD_BUS_PROPERTY("ManagedOOMSwap", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_swap), 0),
396 SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0),
397 SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPermyriad", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit_permyriad), 0),
398 SD_BUS_VTABLE_END
399 };
400
401 static int bus_cgroup_set_transient_property(
402 Unit *u,
403 CGroupContext *c,
404 const char *name,
405 sd_bus_message *message,
406 UnitWriteFlags flags,
407 sd_bus_error *error) {
408
409 int r;
410
411 assert(u);
412 assert(c);
413 assert(name);
414 assert(message);
415
416 flags |= UNIT_PRIVATE;
417
418 if (streq(name, "Delegate")) {
419 int b;
420
421 if (!UNIT_VTABLE(u)->can_delegate)
422 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
423
424 r = sd_bus_message_read(message, "b", &b);
425 if (r < 0)
426 return r;
427
428 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
429 c->delegate = b;
430 c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
431
432 unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
433 }
434
435 return 1;
436
437 } else if (STR_IN_SET(name, "DelegateControllers", "DisableControllers")) {
438 CGroupMask mask = 0;
439
440 if (streq(name, "DelegateControllers") && !UNIT_VTABLE(u)->can_delegate)
441 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
442
443 r = sd_bus_message_enter_container(message, 'a', "s");
444 if (r < 0)
445 return r;
446
447 for (;;) {
448 CGroupController cc;
449 const char *t;
450
451 r = sd_bus_message_read(message, "s", &t);
452 if (r < 0)
453 return r;
454 if (r == 0)
455 break;
456
457 cc = cgroup_controller_from_string(t);
458 if (cc < 0)
459 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup controller '%s'", t);
460
461 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
462 }
463
464 r = sd_bus_message_exit_container(message);
465 if (r < 0)
466 return r;
467
468 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
469 _cleanup_free_ char *t = NULL;
470
471 r = cg_mask_to_string(mask, &t);
472 if (r < 0)
473 return r;
474
475 if (streq(name, "DelegateControllers")) {
476
477 c->delegate = true;
478 if (mask == 0)
479 c->delegate_controllers = 0;
480 else
481 c->delegate_controllers |= mask;
482
483 unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
484
485 } else if (streq(name, "DisableControllers")) {
486
487 if (mask == 0)
488 c->disable_controllers = 0;
489 else
490 c->disable_controllers |= mask;
491
492 unit_write_settingf(u, flags, name, "%s=%s", name, strempty(t));
493 }
494 }
495
496 return 1;
497 } else if (STR_IN_SET(name, "IPIngressFilterPath", "IPEgressFilterPath")) {
498 char ***filters;
499 size_t n = 0;
500
501 filters = streq(name, "IPIngressFilterPath") ? &c->ip_filters_ingress : &c->ip_filters_egress;
502 r = sd_bus_message_enter_container(message, 'a', "s");
503 if (r < 0)
504 return r;
505
506 for (;;) {
507 const char *path;
508
509 r = sd_bus_message_read(message, "s", &path);
510 if (r < 0)
511 return r;
512 if (r == 0)
513 break;
514
515 if (!path_is_normalized(path) || !path_is_absolute(path))
516 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects a normalized absolute path.", name);
517
518 if (!UNIT_WRITE_FLAGS_NOOP(flags) && !strv_contains(*filters, path)) {
519 r = strv_extend(filters, path);
520 if (r < 0)
521 return log_oom();
522 }
523 n++;
524 }
525 r = sd_bus_message_exit_container(message);
526 if (r < 0)
527 return r;
528
529 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
530 _cleanup_free_ char *buf = NULL;
531 _cleanup_fclose_ FILE *f = NULL;
532 char **entry;
533 size_t size = 0;
534
535 if (n == 0)
536 *filters = strv_free(*filters);
537
538 unit_invalidate_cgroup_bpf(u);
539 f = open_memstream_unlocked(&buf, &size);
540 if (!f)
541 return -ENOMEM;
542
543 fputs(name, f);
544 fputs("=\n", f);
545
546 STRV_FOREACH(entry, *filters)
547 fprintf(f, "%s=%s\n", name, *entry);
548
549 r = fflush_and_check(f);
550 if (r < 0)
551 return r;
552
553 unit_write_setting(u, flags, name, buf);
554
555 if (*filters) {
556 r = bpf_firewall_supported();
557 if (r < 0)
558 return r;
559 if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
560 static bool warned = false;
561
562 log_full(warned ? LOG_DEBUG : LOG_WARNING,
563 "Transient unit %s configures an IP firewall with BPF, but the local system does not support BPF/cgroup firewalling with multiple filters.\n"
564 "Starting this unit will fail! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
565 warned = true;
566 }
567 }
568 }
569
570 return 1;
571 }
572
573 return 0;
574 }
575
576 static int bus_cgroup_set_boolean(
577 Unit *u,
578 const char *name,
579 bool *p,
580 CGroupMask mask,
581 sd_bus_message *message,
582 UnitWriteFlags flags,
583 sd_bus_error *error) {
584
585 int b, r;
586
587 assert(p);
588
589 r = sd_bus_message_read(message, "b", &b);
590 if (r < 0)
591 return r;
592
593 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
594 *p = b;
595 unit_invalidate_cgroup(u, mask);
596 unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b));
597 }
598
599 return 1;
600 }
601
602 #define BUS_DEFINE_SET_CGROUP_WEIGHT(function, mask, check, val) \
603 static int bus_cgroup_set_##function( \
604 Unit *u, \
605 const char *name, \
606 uint64_t *p, \
607 sd_bus_message *message, \
608 UnitWriteFlags flags, \
609 sd_bus_error *error) { \
610 \
611 uint64_t v; \
612 int r; \
613 \
614 assert(p); \
615 \
616 r = sd_bus_message_read(message, "t", &v); \
617 if (r < 0) \
618 return r; \
619 \
620 if (!check(v)) \
621 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
622 "Value specified in %s is out of range", name); \
623 \
624 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
625 *p = v; \
626 unit_invalidate_cgroup(u, mask); \
627 \
628 if (v == (val)) \
629 unit_write_settingf(u, flags, name, \
630 "%s=", name); \
631 else \
632 unit_write_settingf(u, flags, name, \
633 "%s=%" PRIu64, name, v); \
634 } \
635 \
636 return 1; \
637 }
638
639 #define BUS_DEFINE_SET_CGROUP_LIMIT(function, mask, scale, minimum) \
640 static int bus_cgroup_set_##function( \
641 Unit *u, \
642 const char *name, \
643 uint64_t *p, \
644 sd_bus_message *message, \
645 UnitWriteFlags flags, \
646 sd_bus_error *error) { \
647 \
648 uint64_t v; \
649 int r; \
650 \
651 assert(p); \
652 \
653 r = sd_bus_message_read(message, "t", &v); \
654 if (r < 0) \
655 return r; \
656 \
657 if (v < minimum) \
658 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
659 "Value specified in %s is out of range", name); \
660 \
661 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
662 *p = v; \
663 unit_invalidate_cgroup(u, mask); \
664 \
665 if (v == CGROUP_LIMIT_MAX) \
666 unit_write_settingf(u, flags, name, \
667 "%s=infinity", name); \
668 else \
669 unit_write_settingf(u, flags, name, \
670 "%s=%" PRIu64, name, v); \
671 } \
672 \
673 return 1; \
674 } \
675 static int bus_cgroup_set_##function##_scale( \
676 Unit *u, \
677 const char *name, \
678 uint64_t *p, \
679 sd_bus_message *message, \
680 UnitWriteFlags flags, \
681 sd_bus_error *error) { \
682 \
683 uint64_t v; \
684 uint32_t raw; \
685 int r; \
686 \
687 assert(p); \
688 \
689 r = sd_bus_message_read(message, "u", &raw); \
690 if (r < 0) \
691 return r; \
692 \
693 v = scale(raw, UINT32_MAX); \
694 if (v < minimum || v >= UINT64_MAX) \
695 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
696 "Value specified in %s is out of range", name); \
697 \
698 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
699 *p = v; \
700 unit_invalidate_cgroup(u, mask); \
701 \
702 /* Prepare to chop off suffix */ \
703 assert_se(endswith(name, "Scale")); \
704 \
705 uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
706 unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
707 (int)(strlen(name) - strlen("Scale")), name, \
708 scaled / 10, scaled % 10); \
709 } \
710 \
711 return 1; \
712 }
713
714 DISABLE_WARNING_TYPE_LIMITS;
715 BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
716 BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
717 BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
718 BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
719 BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
720 BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
721 BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
722 REENABLE_WARNING;
723
724 static int bus_cgroup_set_tasks_max(
725 Unit *u,
726 const char *name,
727 TasksMax *p,
728 sd_bus_message *message,
729 UnitWriteFlags flags,
730 sd_bus_error *error) {
731
732 uint64_t v;
733 int r;
734
735 assert(p);
736
737 r = sd_bus_message_read(message, "t", &v);
738 if (r < 0)
739 return r;
740
741 if (v < 1)
742 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
743 "Value specified in %s is out of range", name);
744
745 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
746 *p = (TasksMax) { .value = v, .scale = 0 }; /* When .scale==0, .value is the absolute value */
747 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
748
749 if (v == CGROUP_LIMIT_MAX)
750 unit_write_settingf(u, flags, name,
751 "%s=infinity", name);
752 else
753 unit_write_settingf(u, flags, name,
754 "%s=%" PRIu64, name, v);
755 }
756
757 return 1;
758 }
759
760 static int bus_cgroup_set_tasks_max_scale(
761 Unit *u,
762 const char *name,
763 TasksMax *p,
764 sd_bus_message *message,
765 UnitWriteFlags flags,
766 sd_bus_error *error) {
767
768 uint32_t v;
769 int r;
770
771 assert(p);
772
773 r = sd_bus_message_read(message, "u", &v);
774 if (r < 0)
775 return r;
776
777 if (v < 1 || v >= UINT32_MAX)
778 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
779 "Value specified in %s is out of range", name);
780
781 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
782 *p = (TasksMax) { v, UINT32_MAX }; /* .scale is not 0, so this is interpreted as v/UINT32_MAX. */
783 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
784
785 uint32_t scaled = DIV_ROUND_UP((uint64_t) v * 100U, (uint64_t) UINT32_MAX);
786 unit_write_settingf(u, flags, name, "%s=%" PRIu32 ".%" PRIu32 "%%", "TasksMax",
787 scaled / 10, scaled % 10);
788 }
789
790 return 1;
791 }
792
793 int bus_cgroup_set_property(
794 Unit *u,
795 CGroupContext *c,
796 const char *name,
797 sd_bus_message *message,
798 UnitWriteFlags flags,
799 sd_bus_error *error) {
800
801 CGroupIOLimitType iol_type;
802 int r;
803
804 assert(u);
805 assert(c);
806 assert(name);
807 assert(message);
808
809 flags |= UNIT_PRIVATE;
810
811 if (streq(name, "CPUAccounting"))
812 return bus_cgroup_set_boolean(u, name, &c->cpu_accounting, get_cpu_accounting_mask(), message, flags, error);
813
814 if (streq(name, "CPUWeight"))
815 return bus_cgroup_set_cpu_weight(u, name, &c->cpu_weight, message, flags, error);
816
817 if (streq(name, "StartupCPUWeight"))
818 return bus_cgroup_set_cpu_weight(u, name, &c->startup_cpu_weight, message, flags, error);
819
820 if (streq(name, "CPUShares"))
821 return bus_cgroup_set_cpu_shares(u, name, &c->cpu_shares, message, flags, error);
822
823 if (streq(name, "StartupCPUShares"))
824 return bus_cgroup_set_cpu_shares(u, name, &c->startup_cpu_shares, message, flags, error);
825
826 if (streq(name, "IOAccounting"))
827 return bus_cgroup_set_boolean(u, name, &c->io_accounting, CGROUP_MASK_IO, message, flags, error);
828
829 if (streq(name, "IOWeight"))
830 return bus_cgroup_set_io_weight(u, name, &c->io_weight, message, flags, error);
831
832 if (streq(name, "StartupIOWeight"))
833 return bus_cgroup_set_io_weight(u, name, &c->startup_io_weight, message, flags, error);
834
835 if (streq(name, "BlockIOAccounting"))
836 return bus_cgroup_set_boolean(u, name, &c->blockio_accounting, CGROUP_MASK_BLKIO, message, flags, error);
837
838 if (streq(name, "BlockIOWeight"))
839 return bus_cgroup_set_blockio_weight(u, name, &c->blockio_weight, message, flags, error);
840
841 if (streq(name, "StartupBlockIOWeight"))
842 return bus_cgroup_set_blockio_weight(u, name, &c->startup_blockio_weight, message, flags, error);
843
844 if (streq(name, "MemoryAccounting"))
845 return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
846
847 if (streq(name, "MemoryMin")) {
848 r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
849 if (r > 0)
850 c->memory_min_set = true;
851 return r;
852 }
853
854 if (streq(name, "MemoryLow")) {
855 r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
856 if (r > 0)
857 c->memory_low_set = true;
858 return r;
859 }
860
861 if (streq(name, "DefaultMemoryMin")) {
862 r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
863 if (r > 0)
864 c->default_memory_min_set = true;
865 return r;
866 }
867
868 if (streq(name, "DefaultMemoryLow")) {
869 r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
870 if (r > 0)
871 c->default_memory_low_set = true;
872 return r;
873 }
874
875 if (streq(name, "MemoryHigh"))
876 return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
877
878 if (streq(name, "MemorySwapMax"))
879 return bus_cgroup_set_swap(u, name, &c->memory_swap_max, message, flags, error);
880
881 if (streq(name, "MemoryMax"))
882 return bus_cgroup_set_memory(u, name, &c->memory_max, message, flags, error);
883
884 if (streq(name, "MemoryLimit"))
885 return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
886
887 if (streq(name, "MemoryMinScale")) {
888 r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
889 if (r > 0)
890 c->memory_min_set = true;
891 return r;
892 }
893
894 if (streq(name, "MemoryLowScale")) {
895 r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
896 if (r > 0)
897 c->memory_low_set = true;
898 return r;
899 }
900
901 if (streq(name, "DefaultMemoryMinScale")) {
902 r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
903 if (r > 0)
904 c->default_memory_min_set = true;
905 return r;
906 }
907
908 if (streq(name, "DefaultMemoryLowScale")) {
909 r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
910 if (r > 0)
911 c->default_memory_low_set = true;
912 return r;
913 }
914
915 if (streq(name, "MemoryHighScale"))
916 return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
917
918 if (streq(name, "MemorySwapMaxScale"))
919 return bus_cgroup_set_swap_scale(u, name, &c->memory_swap_max, message, flags, error);
920
921 if (streq(name, "MemoryMaxScale"))
922 return bus_cgroup_set_memory_scale(u, name, &c->memory_max, message, flags, error);
923
924 if (streq(name, "MemoryLimitScale"))
925 return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
926
927 if (streq(name, "TasksAccounting"))
928 return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
929
930 if (streq(name, "TasksMax"))
931 return bus_cgroup_set_tasks_max(u, name, &c->tasks_max, message, flags, error);
932
933 if (streq(name, "TasksMaxScale"))
934 return bus_cgroup_set_tasks_max_scale(u, name, &c->tasks_max, message, flags, error);
935
936 if (streq(name, "CPUQuotaPerSecUSec")) {
937 uint64_t u64;
938
939 r = sd_bus_message_read(message, "t", &u64);
940 if (r < 0)
941 return r;
942
943 if (u64 <= 0)
944 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
945
946 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
947 c->cpu_quota_per_sec_usec = u64;
948 u->warned_clamping_cpu_quota_period = false;
949 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
950
951 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
952 unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
953 else
954 /* config_parse_cpu_quota() requires an integer, so truncating division is used on
955 * purpose here. */
956 unit_write_settingf(u, flags, "CPUQuota",
957 "CPUQuota=%0.f%%",
958 (double) (c->cpu_quota_per_sec_usec / 10000));
959 }
960
961 return 1;
962
963 } else if (streq(name, "CPUQuotaPeriodUSec")) {
964 uint64_t u64;
965
966 r = sd_bus_message_read(message, "t", &u64);
967 if (r < 0)
968 return r;
969
970 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
971 c->cpu_quota_period_usec = u64;
972 u->warned_clamping_cpu_quota_period = false;
973 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
974 if (c->cpu_quota_period_usec == USEC_INFINITY)
975 unit_write_setting(u, flags, "CPUQuotaPeriodSec", "CPUQuotaPeriodSec=");
976 else {
977 char v[FORMAT_TIMESPAN_MAX];
978 unit_write_settingf(u, flags, "CPUQuotaPeriodSec",
979 "CPUQuotaPeriodSec=%s",
980 format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1));
981 }
982 }
983
984 return 1;
985
986 } else if (STR_IN_SET(name, "AllowedCPUs", "AllowedMemoryNodes")) {
987 const void *a;
988 size_t n;
989 _cleanup_(cpu_set_reset) CPUSet new_set = {};
990
991 r = sd_bus_message_read_array(message, 'y', &a, &n);
992 if (r < 0)
993 return r;
994
995 r = cpu_set_from_dbus(a, n, &new_set);
996 if (r < 0)
997 return r;
998
999 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1000 _cleanup_free_ char *setstr = NULL;
1001 CPUSet *set;
1002
1003 setstr = cpu_set_to_range_string(&new_set);
1004 if (!setstr)
1005 return -ENOMEM;
1006
1007 if (streq(name, "AllowedCPUs"))
1008 set = &c->cpuset_cpus;
1009 else
1010 set = &c->cpuset_mems;
1011
1012 cpu_set_reset(set);
1013 *set = new_set;
1014 new_set = (CPUSet) {};
1015
1016 unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
1017 unit_write_settingf(u, flags, name, "%s=%s", name, setstr);
1018 }
1019
1020 return 1;
1021
1022 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
1023 const char *path;
1024 unsigned n = 0;
1025 uint64_t u64;
1026
1027 r = sd_bus_message_enter_container(message, 'a', "(st)");
1028 if (r < 0)
1029 return r;
1030
1031 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
1032
1033 if (!path_is_normalized(path))
1034 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1035
1036 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1037 CGroupIODeviceLimit *a = NULL, *b;
1038
1039 LIST_FOREACH(device_limits, b, c->io_device_limits) {
1040 if (path_equal(path, b->path)) {
1041 a = b;
1042 break;
1043 }
1044 }
1045
1046 if (!a) {
1047 CGroupIOLimitType type;
1048
1049 a = new0(CGroupIODeviceLimit, 1);
1050 if (!a)
1051 return -ENOMEM;
1052
1053 a->path = strdup(path);
1054 if (!a->path) {
1055 free(a);
1056 return -ENOMEM;
1057 }
1058
1059 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
1060 a->limits[type] = cgroup_io_limit_defaults[type];
1061
1062 LIST_PREPEND(device_limits, c->io_device_limits, a);
1063 }
1064
1065 a->limits[iol_type] = u64;
1066 }
1067
1068 n++;
1069 }
1070 if (r < 0)
1071 return r;
1072
1073 r = sd_bus_message_exit_container(message);
1074 if (r < 0)
1075 return r;
1076
1077 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1078 CGroupIODeviceLimit *a;
1079 _cleanup_free_ char *buf = NULL;
1080 _cleanup_fclose_ FILE *f = NULL;
1081 size_t size = 0;
1082
1083 if (n == 0) {
1084 LIST_FOREACH(device_limits, a, c->io_device_limits)
1085 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
1086 }
1087
1088 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1089
1090 f = open_memstream_unlocked(&buf, &size);
1091 if (!f)
1092 return -ENOMEM;
1093
1094 fprintf(f, "%s=\n", name);
1095 LIST_FOREACH(device_limits, a, c->io_device_limits)
1096 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
1097 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
1098
1099 r = fflush_and_check(f);
1100 if (r < 0)
1101 return r;
1102 unit_write_setting(u, flags, name, buf);
1103 }
1104
1105 return 1;
1106
1107 } else if (streq(name, "IODeviceWeight")) {
1108 const char *path;
1109 uint64_t weight;
1110 unsigned n = 0;
1111
1112 r = sd_bus_message_enter_container(message, 'a', "(st)");
1113 if (r < 0)
1114 return r;
1115
1116 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
1117
1118 if (!path_is_normalized(path))
1119 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1120
1121 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
1122 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
1123
1124 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1125 CGroupIODeviceWeight *a = NULL, *b;
1126
1127 LIST_FOREACH(device_weights, b, c->io_device_weights) {
1128 if (path_equal(b->path, path)) {
1129 a = b;
1130 break;
1131 }
1132 }
1133
1134 if (!a) {
1135 a = new0(CGroupIODeviceWeight, 1);
1136 if (!a)
1137 return -ENOMEM;
1138
1139 a->path = strdup(path);
1140 if (!a->path) {
1141 free(a);
1142 return -ENOMEM;
1143 }
1144 LIST_PREPEND(device_weights, c->io_device_weights, a);
1145 }
1146
1147 a->weight = weight;
1148 }
1149
1150 n++;
1151 }
1152
1153 r = sd_bus_message_exit_container(message);
1154 if (r < 0)
1155 return r;
1156
1157 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1158 _cleanup_free_ char *buf = NULL;
1159 _cleanup_fclose_ FILE *f = NULL;
1160 CGroupIODeviceWeight *a;
1161 size_t size = 0;
1162
1163 if (n == 0) {
1164 while (c->io_device_weights)
1165 cgroup_context_free_io_device_weight(c, c->io_device_weights);
1166 }
1167
1168 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1169
1170 f = open_memstream_unlocked(&buf, &size);
1171 if (!f)
1172 return -ENOMEM;
1173
1174 fputs("IODeviceWeight=\n", f);
1175 LIST_FOREACH(device_weights, a, c->io_device_weights)
1176 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
1177
1178 r = fflush_and_check(f);
1179 if (r < 0)
1180 return r;
1181 unit_write_setting(u, flags, name, buf);
1182 }
1183
1184 return 1;
1185
1186 } else if (streq(name, "IODeviceLatencyTargetUSec")) {
1187 const char *path;
1188 uint64_t target;
1189 unsigned n = 0;
1190
1191 r = sd_bus_message_enter_container(message, 'a', "(st)");
1192 if (r < 0)
1193 return r;
1194
1195 while ((r = sd_bus_message_read(message, "(st)", &path, &target)) > 0) {
1196
1197 if (!path_is_normalized(path))
1198 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1199
1200 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1201 CGroupIODeviceLatency *a = NULL, *b;
1202
1203 LIST_FOREACH(device_latencies, b, c->io_device_latencies) {
1204 if (path_equal(b->path, path)) {
1205 a = b;
1206 break;
1207 }
1208 }
1209
1210 if (!a) {
1211 a = new0(CGroupIODeviceLatency, 1);
1212 if (!a)
1213 return -ENOMEM;
1214
1215 a->path = strdup(path);
1216 if (!a->path) {
1217 free(a);
1218 return -ENOMEM;
1219 }
1220 LIST_PREPEND(device_latencies, c->io_device_latencies, a);
1221 }
1222
1223 a->target_usec = target;
1224 }
1225
1226 n++;
1227 }
1228
1229 r = sd_bus_message_exit_container(message);
1230 if (r < 0)
1231 return r;
1232
1233 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1234 _cleanup_free_ char *buf = NULL;
1235 _cleanup_fclose_ FILE *f = NULL;
1236 char ts[FORMAT_TIMESPAN_MAX];
1237 CGroupIODeviceLatency *a;
1238 size_t size = 0;
1239
1240 if (n == 0) {
1241 while (c->io_device_latencies)
1242 cgroup_context_free_io_device_latency(c, c->io_device_latencies);
1243 }
1244
1245 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1246
1247 f = open_memstream_unlocked(&buf, &size);
1248 if (!f)
1249 return -ENOMEM;
1250
1251 fputs("IODeviceLatencyTargetSec=\n", f);
1252 LIST_FOREACH(device_latencies, a, c->io_device_latencies)
1253 fprintf(f, "IODeviceLatencyTargetSec=%s %s\n",
1254 a->path, format_timespan(ts, sizeof(ts), a->target_usec, 1));
1255
1256 r = fflush_and_check(f);
1257 if (r < 0)
1258 return r;
1259 unit_write_setting(u, flags, name, buf);
1260 }
1261
1262 return 1;
1263
1264 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1265 const char *path;
1266 bool read = true;
1267 unsigned n = 0;
1268 uint64_t u64;
1269
1270 if (streq(name, "BlockIOWriteBandwidth"))
1271 read = false;
1272
1273 r = sd_bus_message_enter_container(message, 'a', "(st)");
1274 if (r < 0)
1275 return r;
1276
1277 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
1278
1279 if (!path_is_normalized(path))
1280 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1281
1282 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1283 CGroupBlockIODeviceBandwidth *a = NULL, *b;
1284
1285 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
1286 if (path_equal(path, b->path)) {
1287 a = b;
1288 break;
1289 }
1290 }
1291
1292 if (!a) {
1293 a = new0(CGroupBlockIODeviceBandwidth, 1);
1294 if (!a)
1295 return -ENOMEM;
1296
1297 a->rbps = CGROUP_LIMIT_MAX;
1298 a->wbps = CGROUP_LIMIT_MAX;
1299 a->path = strdup(path);
1300 if (!a->path) {
1301 free(a);
1302 return -ENOMEM;
1303 }
1304
1305 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
1306 }
1307
1308 if (read)
1309 a->rbps = u64;
1310 else
1311 a->wbps = u64;
1312 }
1313
1314 n++;
1315 }
1316 if (r < 0)
1317 return r;
1318
1319 r = sd_bus_message_exit_container(message);
1320 if (r < 0)
1321 return r;
1322
1323 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1324 CGroupBlockIODeviceBandwidth *a;
1325 _cleanup_free_ char *buf = NULL;
1326 _cleanup_fclose_ FILE *f = NULL;
1327 size_t size = 0;
1328
1329 if (n == 0) {
1330 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
1331 if (read)
1332 a->rbps = CGROUP_LIMIT_MAX;
1333 else
1334 a->wbps = CGROUP_LIMIT_MAX;
1335 }
1336 }
1337
1338 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
1339
1340 f = open_memstream_unlocked(&buf, &size);
1341 if (!f)
1342 return -ENOMEM;
1343
1344 if (read) {
1345 fputs("BlockIOReadBandwidth=\n", f);
1346 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
1347 if (a->rbps != CGROUP_LIMIT_MAX)
1348 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
1349 } else {
1350 fputs("BlockIOWriteBandwidth=\n", f);
1351 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
1352 if (a->wbps != CGROUP_LIMIT_MAX)
1353 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
1354 }
1355
1356 r = fflush_and_check(f);
1357 if (r < 0)
1358 return r;
1359
1360 unit_write_setting(u, flags, name, buf);
1361 }
1362
1363 return 1;
1364
1365 } else if (streq(name, "BlockIODeviceWeight")) {
1366 const char *path;
1367 uint64_t weight;
1368 unsigned n = 0;
1369
1370 r = sd_bus_message_enter_container(message, 'a', "(st)");
1371 if (r < 0)
1372 return r;
1373
1374 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
1375
1376 if (!path_is_normalized(path))
1377 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1378
1379 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
1380 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
1381
1382 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1383 CGroupBlockIODeviceWeight *a = NULL, *b;
1384
1385 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
1386 if (path_equal(b->path, path)) {
1387 a = b;
1388 break;
1389 }
1390 }
1391
1392 if (!a) {
1393 a = new0(CGroupBlockIODeviceWeight, 1);
1394 if (!a)
1395 return -ENOMEM;
1396
1397 a->path = strdup(path);
1398 if (!a->path) {
1399 free(a);
1400 return -ENOMEM;
1401 }
1402 LIST_PREPEND(device_weights, c->blockio_device_weights, a);
1403 }
1404
1405 a->weight = weight;
1406 }
1407
1408 n++;
1409 }
1410
1411 r = sd_bus_message_exit_container(message);
1412 if (r < 0)
1413 return r;
1414
1415 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1416 _cleanup_free_ char *buf = NULL;
1417 _cleanup_fclose_ FILE *f = NULL;
1418 CGroupBlockIODeviceWeight *a;
1419 size_t size = 0;
1420
1421 if (n == 0) {
1422 while (c->blockio_device_weights)
1423 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
1424 }
1425
1426 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
1427
1428 f = open_memstream_unlocked(&buf, &size);
1429 if (!f)
1430 return -ENOMEM;
1431
1432 fputs("BlockIODeviceWeight=\n", f);
1433 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
1434 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
1435
1436 r = fflush_and_check(f);
1437 if (r < 0)
1438 return r;
1439
1440 unit_write_setting(u, flags, name, buf);
1441 }
1442
1443 return 1;
1444
1445 } else if (streq(name, "DevicePolicy")) {
1446 const char *policy;
1447 CGroupDevicePolicy p;
1448
1449 r = sd_bus_message_read(message, "s", &policy);
1450 if (r < 0)
1451 return r;
1452
1453 p = cgroup_device_policy_from_string(policy);
1454 if (p < 0)
1455 return p;
1456
1457 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1458 c->device_policy = p;
1459 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1460 unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
1461 }
1462
1463 return 1;
1464
1465 } else if (streq(name, "DeviceAllow")) {
1466 const char *path, *rwm;
1467 unsigned n = 0;
1468
1469 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1470 if (r < 0)
1471 return r;
1472
1473 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
1474
1475 if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
1476 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
1477
1478 if (isempty(rwm))
1479 rwm = "rwm";
1480 else if (!in_charset(rwm, "rwm"))
1481 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
1482
1483 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1484 CGroupDeviceAllow *a = NULL, *b;
1485
1486 LIST_FOREACH(device_allow, b, c->device_allow) {
1487 if (path_equal(b->path, path)) {
1488 a = b;
1489 break;
1490 }
1491 }
1492
1493 if (!a) {
1494 a = new0(CGroupDeviceAllow, 1);
1495 if (!a)
1496 return -ENOMEM;
1497
1498 a->path = strdup(path);
1499 if (!a->path) {
1500 free(a);
1501 return -ENOMEM;
1502 }
1503
1504 LIST_PREPEND(device_allow, c->device_allow, a);
1505 }
1506
1507 a->r = strchr(rwm, 'r');
1508 a->w = strchr(rwm, 'w');
1509 a->m = strchr(rwm, 'm');
1510 }
1511
1512 n++;
1513 }
1514 if (r < 0)
1515 return r;
1516
1517 r = sd_bus_message_exit_container(message);
1518 if (r < 0)
1519 return r;
1520
1521 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1522 _cleanup_free_ char *buf = NULL;
1523 _cleanup_fclose_ FILE *f = NULL;
1524 CGroupDeviceAllow *a;
1525 size_t size = 0;
1526
1527 if (n == 0) {
1528 while (c->device_allow)
1529 cgroup_context_free_device_allow(c, c->device_allow);
1530 }
1531
1532 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1533
1534 f = open_memstream_unlocked(&buf, &size);
1535 if (!f)
1536 return -ENOMEM;
1537
1538 fputs("DeviceAllow=\n", f);
1539 LIST_FOREACH(device_allow, a, c->device_allow)
1540 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1541
1542 r = fflush_and_check(f);
1543 if (r < 0)
1544 return r;
1545 unit_write_setting(u, flags, name, buf);
1546 }
1547
1548 return 1;
1549
1550 } else if (streq(name, "IPAccounting")) {
1551 int b;
1552
1553 r = sd_bus_message_read(message, "b", &b);
1554 if (r < 0)
1555 return r;
1556
1557 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1558 c->ip_accounting = b;
1559
1560 unit_invalidate_cgroup_bpf(u);
1561 unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
1562 }
1563
1564 return 1;
1565
1566 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1567 IPAddressAccessItem **list;
1568 size_t n = 0;
1569
1570 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1571
1572 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1573 if (r < 0)
1574 return r;
1575
1576 for (;;) {
1577 const void *ap;
1578 int32_t family;
1579 uint32_t prefixlen;
1580 size_t an;
1581
1582 r = sd_bus_message_enter_container(message, 'r', "iayu");
1583 if (r < 0)
1584 return r;
1585 if (r == 0)
1586 break;
1587
1588 r = sd_bus_message_read(message, "i", &family);
1589 if (r < 0)
1590 return r;
1591
1592 if (!IN_SET(family, AF_INET, AF_INET6))
1593 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects IPv4 or IPv6 addresses only.", name);
1594
1595 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1596 if (r < 0)
1597 return r;
1598
1599 if (an != FAMILY_ADDRESS_SIZE(family))
1600 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IP address has wrong size for family (%s, expected %zu, got %zu)",
1601 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1602
1603 r = sd_bus_message_read(message, "u", &prefixlen);
1604 if (r < 0)
1605 return r;
1606
1607 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
1608 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));
1609
1610 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1611 IPAddressAccessItem *item;
1612
1613 item = new0(IPAddressAccessItem, 1);
1614 if (!item)
1615 return -ENOMEM;
1616
1617 item->family = family;
1618 item->prefixlen = prefixlen;
1619 memcpy(&item->address, ap, an);
1620
1621 LIST_PREPEND(items, *list, item);
1622 }
1623
1624 r = sd_bus_message_exit_container(message);
1625 if (r < 0)
1626 return r;
1627
1628 n++;
1629 }
1630
1631 r = sd_bus_message_exit_container(message);
1632 if (r < 0)
1633 return r;
1634
1635 *list = ip_address_access_reduce(*list);
1636
1637 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1638 _cleanup_free_ char *buf = NULL;
1639 _cleanup_fclose_ FILE *f = NULL;
1640 IPAddressAccessItem *item;
1641 size_t size = 0;
1642
1643 if (n == 0)
1644 *list = ip_address_access_free_all(*list);
1645
1646 unit_invalidate_cgroup_bpf(u);
1647 f = open_memstream_unlocked(&buf, &size);
1648 if (!f)
1649 return -ENOMEM;
1650
1651 fputs(name, f);
1652 fputs("=\n", f);
1653
1654 LIST_FOREACH(items, item, *list) {
1655 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1656
1657 errno = 0;
1658 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1659 return errno_or_else(EINVAL);
1660
1661 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1662 }
1663
1664 r = fflush_and_check(f);
1665 if (r < 0)
1666 return r;
1667
1668 unit_write_setting(u, flags, name, buf);
1669 }
1670
1671 return 1;
1672 }
1673
1674 if (STR_IN_SET(name, "ManagedOOMSwap", "ManagedOOMMemoryPressure")) {
1675 ManagedOOMMode *cgroup_mode = streq(name, "ManagedOOMSwap") ? &c->moom_swap : &c->moom_mem_pressure;
1676 ManagedOOMMode m;
1677 const char *mode;
1678
1679 if (!UNIT_VTABLE(u)->can_set_managed_oom)
1680 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name);
1681
1682 r = sd_bus_message_read(message, "s", &mode);
1683 if (r < 0)
1684 return r;
1685
1686 m = managed_oom_mode_from_string(mode);
1687 if (m < 0)
1688 return -EINVAL;
1689
1690 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1691 *cgroup_mode = m;
1692 unit_write_settingf(u, flags, name, "%s=%s", name, mode);
1693 }
1694
1695 (void) manager_varlink_send_managed_oom_update(u);
1696 return 1;
1697 }
1698
1699 if (streq(name, "ManagedOOMMemoryPressureLimitPermyriad")) {
1700 uint32_t v;
1701
1702 if (!UNIT_VTABLE(u)->can_set_managed_oom)
1703 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name);
1704
1705 r = sd_bus_message_read(message, "u", &v);
1706 if (r < 0)
1707 return r;
1708
1709 if (v > 10000)
1710 return -ERANGE;
1711
1712 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1713 c->moom_mem_pressure_limit_permyriad = v;
1714 unit_write_settingf(u, flags, name, "ManagedOOMMemoryPressureLimit=%" PRIu32 ".%02" PRIu32 "%%", v / 100, v % 100);
1715 }
1716
1717 if (c->moom_mem_pressure == MANAGED_OOM_KILL)
1718 (void) manager_varlink_send_managed_oom_update(u);
1719
1720 return 1;
1721 }
1722
1723 if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
1724 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
1725
1726 return 0;
1727 }