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