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