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