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