]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
tree-wide: assorted coccinelle fixes
[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-get-properties.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 uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
702 unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
703 (int)(strlen(name) - strlen("Scale")), name, \
704 scaled / 10, scaled % 10); \
705 } \
706 \
707 return 1; \
708 }
709
710 DISABLE_WARNING_TYPE_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 REENABLE_WARNING;
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 uint32_t scaled = DIV_ROUND_UP((uint64_t) v * 100U, (uint64_t) UINT32_MAX);
782 unit_write_settingf(u, flags, name, "%s=%" PRIu32 ".%" PRIu32 "%%", "TasksMax",
783 scaled / 10, scaled % 10);
784 }
785
786 return 1;
787 }
788
789 int bus_cgroup_set_property(
790 Unit *u,
791 CGroupContext *c,
792 const char *name,
793 sd_bus_message *message,
794 UnitWriteFlags flags,
795 sd_bus_error *error) {
796
797 CGroupIOLimitType iol_type;
798 int r;
799
800 assert(u);
801 assert(c);
802 assert(name);
803 assert(message);
804
805 flags |= UNIT_PRIVATE;
806
807 if (streq(name, "CPUAccounting"))
808 return bus_cgroup_set_boolean(u, name, &c->cpu_accounting, get_cpu_accounting_mask(), message, flags, error);
809
810 if (streq(name, "CPUWeight"))
811 return bus_cgroup_set_cpu_weight(u, name, &c->cpu_weight, message, flags, error);
812
813 if (streq(name, "StartupCPUWeight"))
814 return bus_cgroup_set_cpu_weight(u, name, &c->startup_cpu_weight, message, flags, error);
815
816 if (streq(name, "CPUShares"))
817 return bus_cgroup_set_cpu_shares(u, name, &c->cpu_shares, message, flags, error);
818
819 if (streq(name, "StartupCPUShares"))
820 return bus_cgroup_set_cpu_shares(u, name, &c->startup_cpu_shares, message, flags, error);
821
822 if (streq(name, "IOAccounting"))
823 return bus_cgroup_set_boolean(u, name, &c->io_accounting, CGROUP_MASK_IO, message, flags, error);
824
825 if (streq(name, "IOWeight"))
826 return bus_cgroup_set_io_weight(u, name, &c->io_weight, message, flags, error);
827
828 if (streq(name, "StartupIOWeight"))
829 return bus_cgroup_set_io_weight(u, name, &c->startup_io_weight, message, flags, error);
830
831 if (streq(name, "BlockIOAccounting"))
832 return bus_cgroup_set_boolean(u, name, &c->blockio_accounting, CGROUP_MASK_BLKIO, message, flags, error);
833
834 if (streq(name, "BlockIOWeight"))
835 return bus_cgroup_set_blockio_weight(u, name, &c->blockio_weight, message, flags, error);
836
837 if (streq(name, "StartupBlockIOWeight"))
838 return bus_cgroup_set_blockio_weight(u, name, &c->startup_blockio_weight, message, flags, error);
839
840 if (streq(name, "MemoryAccounting"))
841 return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
842
843 if (streq(name, "MemoryMin")) {
844 r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
845 if (r > 0)
846 c->memory_min_set = true;
847 return r;
848 }
849
850 if (streq(name, "MemoryLow")) {
851 r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
852 if (r > 0)
853 c->memory_low_set = true;
854 return r;
855 }
856
857 if (streq(name, "DefaultMemoryMin")) {
858 r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
859 if (r > 0)
860 c->default_memory_min_set = true;
861 return r;
862 }
863
864 if (streq(name, "DefaultMemoryLow")) {
865 r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
866 if (r > 0)
867 c->default_memory_low_set = true;
868 return r;
869 }
870
871 if (streq(name, "MemoryHigh"))
872 return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
873
874 if (streq(name, "MemorySwapMax"))
875 return bus_cgroup_set_swap(u, name, &c->memory_swap_max, message, flags, error);
876
877 if (streq(name, "MemoryMax"))
878 return bus_cgroup_set_memory(u, name, &c->memory_max, message, flags, error);
879
880 if (streq(name, "MemoryLimit"))
881 return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
882
883 if (streq(name, "MemoryMinScale")) {
884 r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
885 if (r > 0)
886 c->memory_min_set = true;
887 return r;
888 }
889
890 if (streq(name, "MemoryLowScale")) {
891 r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
892 if (r > 0)
893 c->memory_low_set = true;
894 return r;
895 }
896
897 if (streq(name, "DefaultMemoryMinScale")) {
898 r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
899 if (r > 0)
900 c->default_memory_min_set = true;
901 return r;
902 }
903
904 if (streq(name, "DefaultMemoryLowScale")) {
905 r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
906 if (r > 0)
907 c->default_memory_low_set = true;
908 return r;
909 }
910
911 if (streq(name, "MemoryHighScale"))
912 return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
913
914 if (streq(name, "MemorySwapMaxScale"))
915 return bus_cgroup_set_swap_scale(u, name, &c->memory_swap_max, message, flags, error);
916
917 if (streq(name, "MemoryMaxScale"))
918 return bus_cgroup_set_memory_scale(u, name, &c->memory_max, message, flags, error);
919
920 if (streq(name, "MemoryLimitScale"))
921 return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
922
923 if (streq(name, "TasksAccounting"))
924 return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
925
926 if (streq(name, "TasksMax"))
927 return bus_cgroup_set_tasks_max(u, name, &c->tasks_max, message, flags, error);
928
929 if (streq(name, "TasksMaxScale"))
930 return bus_cgroup_set_tasks_max_scale(u, name, &c->tasks_max, message, flags, error);
931
932 if (streq(name, "CPUQuotaPerSecUSec")) {
933 uint64_t u64;
934
935 r = sd_bus_message_read(message, "t", &u64);
936 if (r < 0)
937 return r;
938
939 if (u64 <= 0)
940 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
941
942 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
943 c->cpu_quota_per_sec_usec = u64;
944 u->warned_clamping_cpu_quota_period = false;
945 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
946
947 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
948 unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
949 else
950 /* config_parse_cpu_quota() requires an integer, so truncating division is used on
951 * purpose here. */
952 unit_write_settingf(u, flags, "CPUQuota",
953 "CPUQuota=%0.f%%",
954 (double) (c->cpu_quota_per_sec_usec / 10000));
955 }
956
957 return 1;
958
959 } else if (streq(name, "CPUQuotaPeriodUSec")) {
960 uint64_t u64;
961
962 r = sd_bus_message_read(message, "t", &u64);
963 if (r < 0)
964 return r;
965
966 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
967 c->cpu_quota_period_usec = u64;
968 u->warned_clamping_cpu_quota_period = false;
969 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
970 if (c->cpu_quota_period_usec == USEC_INFINITY)
971 unit_write_setting(u, flags, "CPUQuotaPeriodSec", "CPUQuotaPeriodSec=");
972 else {
973 char v[FORMAT_TIMESPAN_MAX];
974 unit_write_settingf(u, flags, "CPUQuotaPeriodSec",
975 "CPUQuotaPeriodSec=%s",
976 format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1));
977 }
978 }
979
980 return 1;
981
982 } else if (STR_IN_SET(name, "AllowedCPUs", "AllowedMemoryNodes")) {
983 const void *a;
984 size_t n;
985 _cleanup_(cpu_set_reset) CPUSet new_set = {};
986
987 r = sd_bus_message_read_array(message, 'y', &a, &n);
988 if (r < 0)
989 return r;
990
991 r = cpu_set_from_dbus(a, n, &new_set);
992 if (r < 0)
993 return r;
994
995 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
996 _cleanup_free_ char *setstr = NULL;
997 CPUSet *set;
998
999 setstr = cpu_set_to_range_string(&new_set);
1000 if (!setstr)
1001 return -ENOMEM;
1002
1003 if (streq(name, "AllowedCPUs"))
1004 set = &c->cpuset_cpus;
1005 else
1006 set = &c->cpuset_mems;
1007
1008 cpu_set_reset(set);
1009 *set = new_set;
1010 new_set = (CPUSet) {};
1011
1012 unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
1013 unit_write_settingf(u, flags, name, "%s=%s", name, setstr);
1014 }
1015
1016 return 1;
1017
1018 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
1019 const char *path;
1020 unsigned n = 0;
1021 uint64_t u64;
1022
1023 r = sd_bus_message_enter_container(message, 'a', "(st)");
1024 if (r < 0)
1025 return r;
1026
1027 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
1028
1029 if (!path_is_normalized(path))
1030 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1031
1032 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1033 CGroupIODeviceLimit *a = NULL, *b;
1034
1035 LIST_FOREACH(device_limits, b, c->io_device_limits) {
1036 if (path_equal(path, b->path)) {
1037 a = b;
1038 break;
1039 }
1040 }
1041
1042 if (!a) {
1043 CGroupIOLimitType type;
1044
1045 a = new0(CGroupIODeviceLimit, 1);
1046 if (!a)
1047 return -ENOMEM;
1048
1049 a->path = strdup(path);
1050 if (!a->path) {
1051 free(a);
1052 return -ENOMEM;
1053 }
1054
1055 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
1056 a->limits[type] = cgroup_io_limit_defaults[type];
1057
1058 LIST_PREPEND(device_limits, c->io_device_limits, a);
1059 }
1060
1061 a->limits[iol_type] = u64;
1062 }
1063
1064 n++;
1065 }
1066 if (r < 0)
1067 return r;
1068
1069 r = sd_bus_message_exit_container(message);
1070 if (r < 0)
1071 return r;
1072
1073 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1074 CGroupIODeviceLimit *a;
1075 _cleanup_free_ char *buf = NULL;
1076 _cleanup_fclose_ FILE *f = NULL;
1077 size_t size = 0;
1078
1079 if (n == 0) {
1080 LIST_FOREACH(device_limits, a, c->io_device_limits)
1081 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
1082 }
1083
1084 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1085
1086 f = open_memstream_unlocked(&buf, &size);
1087 if (!f)
1088 return -ENOMEM;
1089
1090 fprintf(f, "%s=\n", name);
1091 LIST_FOREACH(device_limits, a, c->io_device_limits)
1092 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
1093 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
1094
1095 r = fflush_and_check(f);
1096 if (r < 0)
1097 return r;
1098 unit_write_setting(u, flags, name, buf);
1099 }
1100
1101 return 1;
1102
1103 } else if (streq(name, "IODeviceWeight")) {
1104 const char *path;
1105 uint64_t weight;
1106 unsigned n = 0;
1107
1108 r = sd_bus_message_enter_container(message, 'a', "(st)");
1109 if (r < 0)
1110 return r;
1111
1112 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
1113
1114 if (!path_is_normalized(path))
1115 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1116
1117 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
1118 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
1119
1120 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1121 CGroupIODeviceWeight *a = NULL, *b;
1122
1123 LIST_FOREACH(device_weights, b, c->io_device_weights) {
1124 if (path_equal(b->path, path)) {
1125 a = b;
1126 break;
1127 }
1128 }
1129
1130 if (!a) {
1131 a = new0(CGroupIODeviceWeight, 1);
1132 if (!a)
1133 return -ENOMEM;
1134
1135 a->path = strdup(path);
1136 if (!a->path) {
1137 free(a);
1138 return -ENOMEM;
1139 }
1140 LIST_PREPEND(device_weights, c->io_device_weights, a);
1141 }
1142
1143 a->weight = weight;
1144 }
1145
1146 n++;
1147 }
1148
1149 r = sd_bus_message_exit_container(message);
1150 if (r < 0)
1151 return r;
1152
1153 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1154 _cleanup_free_ char *buf = NULL;
1155 _cleanup_fclose_ FILE *f = NULL;
1156 CGroupIODeviceWeight *a;
1157 size_t size = 0;
1158
1159 if (n == 0) {
1160 while (c->io_device_weights)
1161 cgroup_context_free_io_device_weight(c, c->io_device_weights);
1162 }
1163
1164 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1165
1166 f = open_memstream_unlocked(&buf, &size);
1167 if (!f)
1168 return -ENOMEM;
1169
1170 fputs("IODeviceWeight=\n", f);
1171 LIST_FOREACH(device_weights, a, c->io_device_weights)
1172 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
1173
1174 r = fflush_and_check(f);
1175 if (r < 0)
1176 return r;
1177 unit_write_setting(u, flags, name, buf);
1178 }
1179
1180 return 1;
1181
1182 } else if (streq(name, "IODeviceLatencyTargetUSec")) {
1183 const char *path;
1184 uint64_t target;
1185 unsigned n = 0;
1186
1187 r = sd_bus_message_enter_container(message, 'a', "(st)");
1188 if (r < 0)
1189 return r;
1190
1191 while ((r = sd_bus_message_read(message, "(st)", &path, &target)) > 0) {
1192
1193 if (!path_is_normalized(path))
1194 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1195
1196 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1197 CGroupIODeviceLatency *a = NULL, *b;
1198
1199 LIST_FOREACH(device_latencies, b, c->io_device_latencies) {
1200 if (path_equal(b->path, path)) {
1201 a = b;
1202 break;
1203 }
1204 }
1205
1206 if (!a) {
1207 a = new0(CGroupIODeviceLatency, 1);
1208 if (!a)
1209 return -ENOMEM;
1210
1211 a->path = strdup(path);
1212 if (!a->path) {
1213 free(a);
1214 return -ENOMEM;
1215 }
1216 LIST_PREPEND(device_latencies, c->io_device_latencies, a);
1217 }
1218
1219 a->target_usec = target;
1220 }
1221
1222 n++;
1223 }
1224
1225 r = sd_bus_message_exit_container(message);
1226 if (r < 0)
1227 return r;
1228
1229 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1230 _cleanup_free_ char *buf = NULL;
1231 _cleanup_fclose_ FILE *f = NULL;
1232 char ts[FORMAT_TIMESPAN_MAX];
1233 CGroupIODeviceLatency *a;
1234 size_t size = 0;
1235
1236 if (n == 0) {
1237 while (c->io_device_latencies)
1238 cgroup_context_free_io_device_latency(c, c->io_device_latencies);
1239 }
1240
1241 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
1242
1243 f = open_memstream_unlocked(&buf, &size);
1244 if (!f)
1245 return -ENOMEM;
1246
1247 fputs("IODeviceLatencyTargetSec=\n", f);
1248 LIST_FOREACH(device_latencies, a, c->io_device_latencies)
1249 fprintf(f, "IODeviceLatencyTargetSec=%s %s\n",
1250 a->path, format_timespan(ts, sizeof(ts), a->target_usec, 1));
1251
1252 r = fflush_and_check(f);
1253 if (r < 0)
1254 return r;
1255 unit_write_setting(u, flags, name, buf);
1256 }
1257
1258 return 1;
1259
1260 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1261 const char *path;
1262 bool read = true;
1263 unsigned n = 0;
1264 uint64_t u64;
1265
1266 if (streq(name, "BlockIOWriteBandwidth"))
1267 read = false;
1268
1269 r = sd_bus_message_enter_container(message, 'a', "(st)");
1270 if (r < 0)
1271 return r;
1272
1273 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
1274
1275 if (!path_is_normalized(path))
1276 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1277
1278 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1279 CGroupBlockIODeviceBandwidth *a = NULL, *b;
1280
1281 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
1282 if (path_equal(path, b->path)) {
1283 a = b;
1284 break;
1285 }
1286 }
1287
1288 if (!a) {
1289 a = new0(CGroupBlockIODeviceBandwidth, 1);
1290 if (!a)
1291 return -ENOMEM;
1292
1293 a->rbps = CGROUP_LIMIT_MAX;
1294 a->wbps = CGROUP_LIMIT_MAX;
1295 a->path = strdup(path);
1296 if (!a->path) {
1297 free(a);
1298 return -ENOMEM;
1299 }
1300
1301 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
1302 }
1303
1304 if (read)
1305 a->rbps = u64;
1306 else
1307 a->wbps = u64;
1308 }
1309
1310 n++;
1311 }
1312 if (r < 0)
1313 return r;
1314
1315 r = sd_bus_message_exit_container(message);
1316 if (r < 0)
1317 return r;
1318
1319 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1320 CGroupBlockIODeviceBandwidth *a;
1321 _cleanup_free_ char *buf = NULL;
1322 _cleanup_fclose_ FILE *f = NULL;
1323 size_t size = 0;
1324
1325 if (n == 0) {
1326 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
1327 if (read)
1328 a->rbps = CGROUP_LIMIT_MAX;
1329 else
1330 a->wbps = CGROUP_LIMIT_MAX;
1331 }
1332 }
1333
1334 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
1335
1336 f = open_memstream_unlocked(&buf, &size);
1337 if (!f)
1338 return -ENOMEM;
1339
1340 if (read) {
1341 fputs("BlockIOReadBandwidth=\n", f);
1342 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
1343 if (a->rbps != CGROUP_LIMIT_MAX)
1344 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
1345 } else {
1346 fputs("BlockIOWriteBandwidth=\n", f);
1347 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
1348 if (a->wbps != CGROUP_LIMIT_MAX)
1349 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
1350 }
1351
1352 r = fflush_and_check(f);
1353 if (r < 0)
1354 return r;
1355
1356 unit_write_setting(u, flags, name, buf);
1357 }
1358
1359 return 1;
1360
1361 } else if (streq(name, "BlockIODeviceWeight")) {
1362 const char *path;
1363 uint64_t weight;
1364 unsigned n = 0;
1365
1366 r = sd_bus_message_enter_container(message, 'a', "(st)");
1367 if (r < 0)
1368 return r;
1369
1370 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
1371
1372 if (!path_is_normalized(path))
1373 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
1374
1375 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
1376 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
1377
1378 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1379 CGroupBlockIODeviceWeight *a = NULL, *b;
1380
1381 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
1382 if (path_equal(b->path, path)) {
1383 a = b;
1384 break;
1385 }
1386 }
1387
1388 if (!a) {
1389 a = new0(CGroupBlockIODeviceWeight, 1);
1390 if (!a)
1391 return -ENOMEM;
1392
1393 a->path = strdup(path);
1394 if (!a->path) {
1395 free(a);
1396 return -ENOMEM;
1397 }
1398 LIST_PREPEND(device_weights, c->blockio_device_weights, a);
1399 }
1400
1401 a->weight = weight;
1402 }
1403
1404 n++;
1405 }
1406
1407 r = sd_bus_message_exit_container(message);
1408 if (r < 0)
1409 return r;
1410
1411 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1412 _cleanup_free_ char *buf = NULL;
1413 _cleanup_fclose_ FILE *f = NULL;
1414 CGroupBlockIODeviceWeight *a;
1415 size_t size = 0;
1416
1417 if (n == 0) {
1418 while (c->blockio_device_weights)
1419 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
1420 }
1421
1422 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
1423
1424 f = open_memstream_unlocked(&buf, &size);
1425 if (!f)
1426 return -ENOMEM;
1427
1428 fputs("BlockIODeviceWeight=\n", f);
1429 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
1430 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
1431
1432 r = fflush_and_check(f);
1433 if (r < 0)
1434 return r;
1435
1436 unit_write_setting(u, flags, name, buf);
1437 }
1438
1439 return 1;
1440
1441 } else if (streq(name, "DevicePolicy")) {
1442 const char *policy;
1443 CGroupDevicePolicy p;
1444
1445 r = sd_bus_message_read(message, "s", &policy);
1446 if (r < 0)
1447 return r;
1448
1449 p = cgroup_device_policy_from_string(policy);
1450 if (p < 0)
1451 return -EINVAL;
1452
1453 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1454 c->device_policy = p;
1455 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1456 unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
1457 }
1458
1459 return 1;
1460
1461 } else if (streq(name, "DeviceAllow")) {
1462 const char *path, *rwm;
1463 unsigned n = 0;
1464
1465 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1466 if (r < 0)
1467 return r;
1468
1469 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
1470
1471 if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
1472 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
1473
1474 if (isempty(rwm))
1475 rwm = "rwm";
1476 else if (!in_charset(rwm, "rwm"))
1477 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
1478
1479 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1480 CGroupDeviceAllow *a = NULL, *b;
1481
1482 LIST_FOREACH(device_allow, b, c->device_allow) {
1483 if (path_equal(b->path, path)) {
1484 a = b;
1485 break;
1486 }
1487 }
1488
1489 if (!a) {
1490 a = new0(CGroupDeviceAllow, 1);
1491 if (!a)
1492 return -ENOMEM;
1493
1494 a->path = strdup(path);
1495 if (!a->path) {
1496 free(a);
1497 return -ENOMEM;
1498 }
1499
1500 LIST_PREPEND(device_allow, c->device_allow, a);
1501 }
1502
1503 a->r = strchr(rwm, 'r');
1504 a->w = strchr(rwm, 'w');
1505 a->m = strchr(rwm, 'm');
1506 }
1507
1508 n++;
1509 }
1510 if (r < 0)
1511 return r;
1512
1513 r = sd_bus_message_exit_container(message);
1514 if (r < 0)
1515 return r;
1516
1517 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1518 _cleanup_free_ char *buf = NULL;
1519 _cleanup_fclose_ FILE *f = NULL;
1520 CGroupDeviceAllow *a;
1521 size_t size = 0;
1522
1523 if (n == 0) {
1524 while (c->device_allow)
1525 cgroup_context_free_device_allow(c, c->device_allow);
1526 }
1527
1528 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1529
1530 f = open_memstream_unlocked(&buf, &size);
1531 if (!f)
1532 return -ENOMEM;
1533
1534 fputs("DeviceAllow=\n", f);
1535 LIST_FOREACH(device_allow, a, c->device_allow)
1536 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1537
1538 r = fflush_and_check(f);
1539 if (r < 0)
1540 return r;
1541 unit_write_setting(u, flags, name, buf);
1542 }
1543
1544 return 1;
1545
1546 } else if (streq(name, "IPAccounting")) {
1547 int b;
1548
1549 r = sd_bus_message_read(message, "b", &b);
1550 if (r < 0)
1551 return r;
1552
1553 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1554 c->ip_accounting = b;
1555
1556 unit_invalidate_cgroup_bpf(u);
1557 unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
1558 }
1559
1560 return 1;
1561
1562 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1563 IPAddressAccessItem **list;
1564 size_t n = 0;
1565
1566 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1567
1568 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1569 if (r < 0)
1570 return r;
1571
1572 for (;;) {
1573 const void *ap;
1574 int32_t family;
1575 uint32_t prefixlen;
1576 size_t an;
1577
1578 r = sd_bus_message_enter_container(message, 'r', "iayu");
1579 if (r < 0)
1580 return r;
1581 if (r == 0)
1582 break;
1583
1584 r = sd_bus_message_read(message, "i", &family);
1585 if (r < 0)
1586 return r;
1587
1588 if (!IN_SET(family, AF_INET, AF_INET6))
1589 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects IPv4 or IPv6 addresses only.", name);
1590
1591 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1592 if (r < 0)
1593 return r;
1594
1595 if (an != FAMILY_ADDRESS_SIZE(family))
1596 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IP address has wrong size for family (%s, expected %zu, got %zu)",
1597 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1598
1599 r = sd_bus_message_read(message, "u", &prefixlen);
1600 if (r < 0)
1601 return r;
1602
1603 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
1604 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));
1605
1606 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1607 IPAddressAccessItem *item;
1608
1609 item = new0(IPAddressAccessItem, 1);
1610 if (!item)
1611 return -ENOMEM;
1612
1613 item->family = family;
1614 item->prefixlen = prefixlen;
1615 memcpy(&item->address, ap, an);
1616
1617 LIST_PREPEND(items, *list, item);
1618 }
1619
1620 r = sd_bus_message_exit_container(message);
1621 if (r < 0)
1622 return r;
1623
1624 n++;
1625 }
1626
1627 r = sd_bus_message_exit_container(message);
1628 if (r < 0)
1629 return r;
1630
1631 *list = ip_address_access_reduce(*list);
1632
1633 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1634 _cleanup_free_ char *buf = NULL;
1635 _cleanup_fclose_ FILE *f = NULL;
1636 IPAddressAccessItem *item;
1637 size_t size = 0;
1638
1639 if (n == 0)
1640 *list = ip_address_access_free_all(*list);
1641
1642 unit_invalidate_cgroup_bpf(u);
1643 f = open_memstream_unlocked(&buf, &size);
1644 if (!f)
1645 return -ENOMEM;
1646
1647 fputs(name, f);
1648 fputs("=\n", f);
1649
1650 LIST_FOREACH(items, item, *list) {
1651 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1652
1653 errno = 0;
1654 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1655 return errno_or_else(EINVAL);
1656
1657 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1658 }
1659
1660 r = fflush_and_check(f);
1661 if (r < 0)
1662 return r;
1663
1664 unit_write_setting(u, flags, name, buf);
1665 }
1666
1667 return 1;
1668 }
1669
1670 if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
1671 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
1672
1673 return 0;
1674 }