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