]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
755b66ef8f5ef8965de0539b920074460a340b6b
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <arpa/inet.h>
22 #include <stdio_ext.h>
23
24 #include "af-list.h"
25 #include "alloc-util.h"
26 #include "bpf-firewall.h"
27 #include "bus-util.h"
28 #include "cgroup-util.h"
29 #include "cgroup.h"
30 #include "dbus-cgroup.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "path-util.h"
34
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
36
37 static int property_get_delegate_controllers(
38 sd_bus *bus,
39 const char *path,
40 const char *interface,
41 const char *property,
42 sd_bus_message *reply,
43 void *userdata,
44 sd_bus_error *error) {
45
46 CGroupContext *c = userdata;
47 CGroupController cc;
48 int r;
49
50 assert(bus);
51 assert(reply);
52 assert(c);
53
54 if (!c->delegate)
55 return sd_bus_message_append(reply, "as", 0);
56
57 r = sd_bus_message_open_container(reply, 'a', "s");
58 if (r < 0)
59 return r;
60
61 for (cc = 0; cc < _CGROUP_CONTROLLER_MAX; cc++) {
62 if ((c->delegate_controllers & CGROUP_CONTROLLER_TO_MASK(cc)) == 0)
63 continue;
64
65 r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(cc));
66 if (r < 0)
67 return r;
68 }
69
70 return sd_bus_message_close_container(reply);
71 }
72
73 static int property_get_io_device_weight(
74 sd_bus *bus,
75 const char *path,
76 const char *interface,
77 const char *property,
78 sd_bus_message *reply,
79 void *userdata,
80 sd_bus_error *error) {
81
82 CGroupContext *c = userdata;
83 CGroupIODeviceWeight *w;
84 int r;
85
86 assert(bus);
87 assert(reply);
88 assert(c);
89
90 r = sd_bus_message_open_container(reply, 'a', "(st)");
91 if (r < 0)
92 return r;
93
94 LIST_FOREACH(device_weights, w, c->io_device_weights) {
95 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
96 if (r < 0)
97 return r;
98 }
99
100 return sd_bus_message_close_container(reply);
101 }
102
103 static int property_get_io_device_limits(
104 sd_bus *bus,
105 const char *path,
106 const char *interface,
107 const char *property,
108 sd_bus_message *reply,
109 void *userdata,
110 sd_bus_error *error) {
111
112 CGroupContext *c = userdata;
113 CGroupIODeviceLimit *l;
114 int r;
115
116 assert(bus);
117 assert(reply);
118 assert(c);
119
120 r = sd_bus_message_open_container(reply, 'a', "(st)");
121 if (r < 0)
122 return r;
123
124 LIST_FOREACH(device_limits, l, c->io_device_limits) {
125 CGroupIOLimitType type;
126
127 type = cgroup_io_limit_type_from_string(property);
128 if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
129 continue;
130
131 r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
132 if (r < 0)
133 return r;
134 }
135
136 return sd_bus_message_close_container(reply);
137 }
138
139 static int property_get_blockio_device_weight(
140 sd_bus *bus,
141 const char *path,
142 const char *interface,
143 const char *property,
144 sd_bus_message *reply,
145 void *userdata,
146 sd_bus_error *error) {
147
148 CGroupContext *c = userdata;
149 CGroupBlockIODeviceWeight *w;
150 int r;
151
152 assert(bus);
153 assert(reply);
154 assert(c);
155
156 r = sd_bus_message_open_container(reply, 'a', "(st)");
157 if (r < 0)
158 return r;
159
160 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
161 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
162 if (r < 0)
163 return r;
164 }
165
166 return sd_bus_message_close_container(reply);
167 }
168
169 static int property_get_blockio_device_bandwidths(
170 sd_bus *bus,
171 const char *path,
172 const char *interface,
173 const char *property,
174 sd_bus_message *reply,
175 void *userdata,
176 sd_bus_error *error) {
177
178 CGroupContext *c = userdata;
179 CGroupBlockIODeviceBandwidth *b;
180 int r;
181
182 assert(bus);
183 assert(reply);
184 assert(c);
185
186 r = sd_bus_message_open_container(reply, 'a', "(st)");
187 if (r < 0)
188 return r;
189
190 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
191 uint64_t v;
192
193 if (streq(property, "BlockIOReadBandwidth"))
194 v = b->rbps;
195 else
196 v = b->wbps;
197
198 if (v == CGROUP_LIMIT_MAX)
199 continue;
200
201 r = sd_bus_message_append(reply, "(st)", b->path, v);
202 if (r < 0)
203 return r;
204 }
205
206 return sd_bus_message_close_container(reply);
207 }
208
209 static int property_get_device_allow(
210 sd_bus *bus,
211 const char *path,
212 const char *interface,
213 const char *property,
214 sd_bus_message *reply,
215 void *userdata,
216 sd_bus_error *error) {
217
218 CGroupContext *c = userdata;
219 CGroupDeviceAllow *a;
220 int r;
221
222 assert(bus);
223 assert(reply);
224 assert(c);
225
226 r = sd_bus_message_open_container(reply, 'a', "(ss)");
227 if (r < 0)
228 return r;
229
230 LIST_FOREACH(device_allow, a, c->device_allow) {
231 unsigned k = 0;
232 char rwm[4];
233
234 if (a->r)
235 rwm[k++] = 'r';
236 if (a->w)
237 rwm[k++] = 'w';
238 if (a->m)
239 rwm[k++] = 'm';
240
241 rwm[k] = 0;
242
243 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
244 if (r < 0)
245 return r;
246 }
247
248 return sd_bus_message_close_container(reply);
249 }
250
251 static int property_get_ip_address_access(
252 sd_bus *bus,
253 const char *path,
254 const char *interface,
255 const char *property,
256 sd_bus_message *reply,
257 void *userdata,
258 sd_bus_error *error) {
259
260 IPAddressAccessItem** items = userdata, *i;
261 int r;
262
263 r = sd_bus_message_open_container(reply, 'a', "(iayu)");
264 if (r < 0)
265 return r;
266
267 LIST_FOREACH(items, i, *items) {
268
269 r = sd_bus_message_open_container(reply, 'r', "iayu");
270 if (r < 0)
271 return r;
272
273 r = sd_bus_message_append(reply, "i", i->family);
274 if (r < 0)
275 return r;
276
277 r = sd_bus_message_append_array(reply, 'y', &i->address, FAMILY_ADDRESS_SIZE(i->family));
278 if (r < 0)
279 return r;
280
281 r = sd_bus_message_append(reply, "u", (uint32_t) i->prefixlen);
282 if (r < 0)
283 return r;
284
285 r = sd_bus_message_close_container(reply);
286 if (r < 0)
287 return r;
288 }
289
290 return sd_bus_message_close_container(reply);
291 }
292
293 const sd_bus_vtable bus_cgroup_vtable[] = {
294 SD_BUS_VTABLE_START(0),
295 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
296 SD_BUS_PROPERTY("DelegateControllers", "as", property_get_delegate_controllers, 0, 0),
297 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
298 SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0),
299 SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0),
300 SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
301 SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
302 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
303 SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
304 SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
305 SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
306 SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
307 SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
308 SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
309 SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
310 SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
311 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
312 SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
313 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
314 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
315 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
316 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
317 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
318 SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
319 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
320 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
321 SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
322 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
323 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
324 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
325 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
326 SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
327 SD_BUS_PROPERTY("IPAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, ip_accounting), 0),
328 SD_BUS_PROPERTY("IPAddressAllow", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_allow), 0),
329 SD_BUS_PROPERTY("IPAddressDeny", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_deny), 0),
330 SD_BUS_VTABLE_END
331 };
332
333 static int bus_cgroup_set_transient_property(
334 Unit *u,
335 CGroupContext *c,
336 const char *name,
337 sd_bus_message *message,
338 UnitWriteFlags flags,
339 sd_bus_error *error) {
340
341 int r;
342
343 assert(u);
344 assert(c);
345 assert(name);
346 assert(message);
347
348 flags |= UNIT_PRIVATE;
349
350 if (streq(name, "Delegate")) {
351 int b;
352
353 r = sd_bus_message_read(message, "b", &b);
354 if (r < 0)
355 return r;
356
357 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
358 c->delegate = b;
359 c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
360
361 unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
362 }
363
364 return 1;
365
366 } else if (streq(name, "DelegateControllers")) {
367 CGroupMask mask = 0;
368
369 r = sd_bus_message_enter_container(message, 'a', "s");
370 if (r < 0)
371 return r;
372
373 for (;;) {
374 CGroupController cc;
375 const char *t;
376
377 r = sd_bus_message_read(message, "s", &t);
378 if (r < 0)
379 return r;
380 if (r == 0)
381 break;
382
383 cc = cgroup_controller_from_string(t);
384 if (cc < 0)
385 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup contoller '%s'", t);
386
387 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
388 }
389
390 r = sd_bus_message_exit_container(message);
391 if (r < 0)
392 return r;
393
394 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
395 _cleanup_free_ char *t = NULL;
396
397 r = cg_mask_to_string(mask, &t);
398 if (r < 0)
399 return r;
400
401 c->delegate = true;
402 if (mask == 0)
403 c->delegate_controllers = 0;
404 else
405 c->delegate_controllers |= mask;
406
407 unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
408 }
409
410 return 1;
411 }
412
413 return 0;
414 }
415
416 int bus_cgroup_set_property(
417 Unit *u,
418 CGroupContext *c,
419 const char *name,
420 sd_bus_message *message,
421 UnitWriteFlags flags,
422 sd_bus_error *error) {
423
424 CGroupIOLimitType iol_type;
425 int r;
426
427 assert(u);
428 assert(c);
429 assert(name);
430 assert(message);
431
432 flags |= UNIT_PRIVATE;
433
434 if (streq(name, "CPUAccounting")) {
435 int b;
436
437 r = sd_bus_message_read(message, "b", &b);
438 if (r < 0)
439 return r;
440
441 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
442 c->cpu_accounting = b;
443 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
444 unit_write_settingf(u, flags, name, "CPUAccounting=%s", yes_no(b));
445 }
446
447 return 1;
448
449 } else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight")) {
450 uint64_t weight;
451
452 r = sd_bus_message_read(message, "t", &weight);
453 if (r < 0)
454 return r;
455
456 if (!CGROUP_WEIGHT_IS_OK(weight))
457 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
458
459 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
460 if (streq(name, "CPUWeight"))
461 c->cpu_weight = weight;
462 else /* "StartupCPUWeight" */
463 c->startup_cpu_weight = weight;
464
465 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
466
467 if (weight == CGROUP_WEIGHT_INVALID)
468 unit_write_settingf(u, flags, name, "%s=", name);
469 else
470 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
471 }
472
473 return 1;
474
475 } else if (STR_IN_SET(name, "CPUShares", "StartupCPUShares")) {
476 uint64_t shares;
477
478 r = sd_bus_message_read(message, "t", &shares);
479 if (r < 0)
480 return r;
481
482 if (!CGROUP_CPU_SHARES_IS_OK(shares))
483 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
484
485 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
486 if (streq(name, "CPUShares"))
487 c->cpu_shares = shares;
488 else /* "StartupCPUShares" */
489 c->startup_cpu_shares = shares;
490
491 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
492
493 if (shares == CGROUP_CPU_SHARES_INVALID)
494 unit_write_settingf(u, flags, name, "%s=", name);
495 else
496 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, shares);
497 }
498
499 return 1;
500
501 } else if (streq(name, "CPUQuotaPerSecUSec")) {
502 uint64_t u64;
503
504 r = sd_bus_message_read(message, "t", &u64);
505 if (r < 0)
506 return r;
507
508 if (u64 <= 0)
509 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
510
511 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
512 c->cpu_quota_per_sec_usec = u64;
513 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
514
515 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
516 unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
517 else
518 /* config_parse_cpu_quota() requires an integer, so truncating division is used on
519 * purpose here. */
520 unit_write_settingf(u, flags, "CPUQuota",
521 "CPUQuota=%0.f%%",
522 (double) (c->cpu_quota_per_sec_usec / 10000));
523 }
524
525 return 1;
526
527 } else if (streq(name, "IOAccounting")) {
528 int b;
529
530 r = sd_bus_message_read(message, "b", &b);
531 if (r < 0)
532 return r;
533
534 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
535 c->io_accounting = b;
536 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
537 unit_write_settingf(u, flags, name, "IOAccounting=%s", yes_no(b));
538 }
539
540 return 1;
541
542 } else if (STR_IN_SET(name, "IOWeight", "StartupIOWeight")) {
543 uint64_t weight;
544
545 r = sd_bus_message_read(message, "t", &weight);
546 if (r < 0)
547 return r;
548
549 if (!CGROUP_WEIGHT_IS_OK(weight))
550 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
551
552 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
553 if (streq(name, "IOWeight"))
554 c->io_weight = weight;
555 else /* "StartupIOWeight" */
556 c->startup_io_weight = weight;
557
558 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
559
560 if (weight == CGROUP_WEIGHT_INVALID)
561 unit_write_settingf(u, flags, name, "%s=", name);
562 else
563 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
564 }
565
566 return 1;
567
568 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
569 const char *path;
570 unsigned n = 0;
571 uint64_t u64;
572
573 r = sd_bus_message_enter_container(message, 'a', "(st)");
574 if (r < 0)
575 return r;
576
577 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
578
579 if (!path_startswith(path, "/dev") &&
580 !path_startswith(path, "/run/systemd/inaccessible/"))
581 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
582
583 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
584 CGroupIODeviceLimit *a = NULL, *b;
585
586 LIST_FOREACH(device_limits, b, c->io_device_limits) {
587 if (path_equal(path, b->path)) {
588 a = b;
589 break;
590 }
591 }
592
593 if (!a) {
594 CGroupIOLimitType type;
595
596 a = new0(CGroupIODeviceLimit, 1);
597 if (!a)
598 return -ENOMEM;
599
600 a->path = strdup(path);
601 if (!a->path) {
602 free(a);
603 return -ENOMEM;
604 }
605
606 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
607 a->limits[type] = cgroup_io_limit_defaults[type];
608
609 LIST_PREPEND(device_limits, c->io_device_limits, a);
610 }
611
612 a->limits[iol_type] = u64;
613 }
614
615 n++;
616 }
617 if (r < 0)
618 return r;
619
620 r = sd_bus_message_exit_container(message);
621 if (r < 0)
622 return r;
623
624 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
625 CGroupIODeviceLimit *a;
626 _cleanup_free_ char *buf = NULL;
627 _cleanup_fclose_ FILE *f = NULL;
628 size_t size = 0;
629
630 if (n == 0) {
631 LIST_FOREACH(device_limits, a, c->io_device_limits)
632 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
633 }
634
635 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
636
637 f = open_memstream(&buf, &size);
638 if (!f)
639 return -ENOMEM;
640
641 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
642
643 fprintf(f, "%s=\n", name);
644 LIST_FOREACH(device_limits, a, c->io_device_limits)
645 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
646 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
647
648 r = fflush_and_check(f);
649 if (r < 0)
650 return r;
651 unit_write_setting(u, flags, name, buf);
652 }
653
654 return 1;
655
656 } else if (streq(name, "IODeviceWeight")) {
657 const char *path;
658 uint64_t weight;
659 unsigned n = 0;
660
661 r = sd_bus_message_enter_container(message, 'a', "(st)");
662 if (r < 0)
663 return r;
664
665 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
666
667 if (!path_startswith(path, "/dev") &&
668 !path_startswith(path, "/run/systemd/inaccessible/"))
669 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
670
671 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
672 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
673
674 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
675 CGroupIODeviceWeight *a = NULL, *b;
676
677 LIST_FOREACH(device_weights, b, c->io_device_weights) {
678 if (path_equal(b->path, path)) {
679 a = b;
680 break;
681 }
682 }
683
684 if (!a) {
685 a = new0(CGroupIODeviceWeight, 1);
686 if (!a)
687 return -ENOMEM;
688
689 a->path = strdup(path);
690 if (!a->path) {
691 free(a);
692 return -ENOMEM;
693 }
694 LIST_PREPEND(device_weights,c->io_device_weights, a);
695 }
696
697 a->weight = weight;
698 }
699
700 n++;
701 }
702
703 r = sd_bus_message_exit_container(message);
704 if (r < 0)
705 return r;
706
707 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
708 _cleanup_free_ char *buf = NULL;
709 _cleanup_fclose_ FILE *f = NULL;
710 CGroupIODeviceWeight *a;
711 size_t size = 0;
712
713 if (n == 0) {
714 while (c->io_device_weights)
715 cgroup_context_free_io_device_weight(c, c->io_device_weights);
716 }
717
718 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
719
720 f = open_memstream(&buf, &size);
721 if (!f)
722 return -ENOMEM;
723
724 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
725
726 fputs("IODeviceWeight=\n", f);
727 LIST_FOREACH(device_weights, a, c->io_device_weights)
728 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
729
730 r = fflush_and_check(f);
731 if (r < 0)
732 return r;
733 unit_write_setting(u, flags, name, buf);
734 }
735
736 return 1;
737
738 } else if (streq(name, "BlockIOAccounting")) {
739 int b;
740
741 r = sd_bus_message_read(message, "b", &b);
742 if (r < 0)
743 return r;
744
745 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
746 c->blockio_accounting = b;
747 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
748 unit_write_settingf(u, flags, name, "BlockIOAccounting=%s", yes_no(b));
749 }
750
751 return 1;
752
753 } else if (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight")) {
754 uint64_t weight;
755
756 r = sd_bus_message_read(message, "t", &weight);
757 if (r < 0)
758 return r;
759
760 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
761 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
762
763 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
764 if (streq(name, "BlockIOWeight"))
765 c->blockio_weight = weight;
766 else /* "StartupBlockIOWeight" */
767 c->startup_blockio_weight = weight;
768
769 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
770
771 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
772 unit_write_settingf(u, flags, name, "%s=", name);
773 else
774 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
775 }
776
777 return 1;
778
779 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
780 const char *path;
781 bool read = true;
782 unsigned n = 0;
783 uint64_t u64;
784
785 if (streq(name, "BlockIOWriteBandwidth"))
786 read = false;
787
788 r = sd_bus_message_enter_container(message, 'a', "(st)");
789 if (r < 0)
790 return r;
791
792 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
793
794 if (!path_startswith(path, "/dev") &&
795 !path_startswith(path, "/run/systemd/inaccessible/"))
796 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
797
798 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
799 CGroupBlockIODeviceBandwidth *a = NULL, *b;
800
801 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
802 if (path_equal(path, b->path)) {
803 a = b;
804 break;
805 }
806 }
807
808 if (!a) {
809 a = new0(CGroupBlockIODeviceBandwidth, 1);
810 if (!a)
811 return -ENOMEM;
812
813 a->rbps = CGROUP_LIMIT_MAX;
814 a->wbps = CGROUP_LIMIT_MAX;
815 a->path = strdup(path);
816 if (!a->path) {
817 free(a);
818 return -ENOMEM;
819 }
820
821 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
822 }
823
824 if (read)
825 a->rbps = u64;
826 else
827 a->wbps = u64;
828 }
829
830 n++;
831 }
832 if (r < 0)
833 return r;
834
835 r = sd_bus_message_exit_container(message);
836 if (r < 0)
837 return r;
838
839 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
840 CGroupBlockIODeviceBandwidth *a;
841 _cleanup_free_ char *buf = NULL;
842 _cleanup_fclose_ FILE *f = NULL;
843 size_t size = 0;
844
845 if (n == 0) {
846 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
847 if (read)
848 a->rbps = CGROUP_LIMIT_MAX;
849 else
850 a->wbps = CGROUP_LIMIT_MAX;
851 }
852 }
853
854 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
855
856 f = open_memstream(&buf, &size);
857 if (!f)
858 return -ENOMEM;
859
860 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
861
862 if (read) {
863 fputs("BlockIOReadBandwidth=\n", f);
864 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
865 if (a->rbps != CGROUP_LIMIT_MAX)
866 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
867 } else {
868 fputs("BlockIOWriteBandwidth=\n", f);
869 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
870 if (a->wbps != CGROUP_LIMIT_MAX)
871 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
872 }
873
874 r = fflush_and_check(f);
875 if (r < 0)
876 return r;
877
878 unit_write_setting(u, flags, name, buf);
879 }
880
881 return 1;
882
883 } else if (streq(name, "BlockIODeviceWeight")) {
884 const char *path;
885 uint64_t weight;
886 unsigned n = 0;
887
888 r = sd_bus_message_enter_container(message, 'a', "(st)");
889 if (r < 0)
890 return r;
891
892 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
893
894 if (!path_startswith(path, "/dev") &&
895 !path_startswith(path, "/run/systemd/inaccessible/"))
896 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
897
898 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
899 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
900
901 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
902 CGroupBlockIODeviceWeight *a = NULL, *b;
903
904 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
905 if (path_equal(b->path, path)) {
906 a = b;
907 break;
908 }
909 }
910
911 if (!a) {
912 a = new0(CGroupBlockIODeviceWeight, 1);
913 if (!a)
914 return -ENOMEM;
915
916 a->path = strdup(path);
917 if (!a->path) {
918 free(a);
919 return -ENOMEM;
920 }
921 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
922 }
923
924 a->weight = weight;
925 }
926
927 n++;
928 }
929
930 r = sd_bus_message_exit_container(message);
931 if (r < 0)
932 return r;
933
934 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
935 _cleanup_free_ char *buf = NULL;
936 _cleanup_fclose_ FILE *f = NULL;
937 CGroupBlockIODeviceWeight *a;
938 size_t size = 0;
939
940 if (n == 0) {
941 while (c->blockio_device_weights)
942 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
943 }
944
945 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
946
947 f = open_memstream(&buf, &size);
948 if (!f)
949 return -ENOMEM;
950
951 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
952
953 fputs("BlockIODeviceWeight=\n", f);
954 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
955 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
956
957 r = fflush_and_check(f);
958 if (r < 0)
959 return r;
960
961 unit_write_setting(u, flags, name, buf);
962 }
963
964 return 1;
965
966 } else if (streq(name, "MemoryAccounting")) {
967 int b;
968
969 r = sd_bus_message_read(message, "b", &b);
970 if (r < 0)
971 return r;
972
973 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
974 c->memory_accounting = b;
975 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
976 unit_write_settingf(u, flags, name, "MemoryAccounting=%s", yes_no(b));
977 }
978
979 return 1;
980
981 } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit")) {
982 uint64_t v;
983
984 r = sd_bus_message_read(message, "t", &v);
985 if (r < 0)
986 return r;
987 if (v <= 0)
988 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
989
990 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
991 if (streq(name, "MemoryLow"))
992 c->memory_low = v;
993 else if (streq(name, "MemoryHigh"))
994 c->memory_high = v;
995 else if (streq(name, "MemorySwapMax"))
996 c->memory_swap_max = v;
997 else if (streq(name, "MemoryMax"))
998 c->memory_max = v;
999 else /* "MemoryLimit" */
1000 c->memory_limit = v;
1001
1002 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
1003
1004 if (v == CGROUP_LIMIT_MAX)
1005 unit_write_settingf(u, flags, name, "%s=infinity", name);
1006 else
1007 unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
1008 }
1009
1010 return 1;
1011
1012 } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale", "MemorySwapMaxScale", "MemoryLimitScale")) {
1013 uint32_t raw;
1014 uint64_t v;
1015
1016 r = sd_bus_message_read(message, "u", &raw);
1017 if (r < 0)
1018 return r;
1019
1020 v = physical_memory_scale(raw, UINT32_MAX);
1021 if (v <= 0 || v == UINT64_MAX)
1022 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
1023
1024 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1025 const char *e;
1026
1027 /* Chop off suffix */
1028 assert_se(e = endswith(name, "Scale"));
1029 name = strndupa(name, e - name);
1030
1031 if (streq(name, "MemoryLow"))
1032 c->memory_low = v;
1033 else if (streq(name, "MemoryHigh"))
1034 c->memory_high = v;
1035 else if (streq(name, "MemorySwapMax"))
1036 c->memory_swap_max = v;
1037 else if (streq(name, "MemoryMax"))
1038 c->memory_max = v;
1039 else /* "MemoryLimit" */
1040 c->memory_limit = v;
1041
1042 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
1043 unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name,
1044 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
1045 }
1046
1047 return 1;
1048
1049 } else if (streq(name, "DevicePolicy")) {
1050 const char *policy;
1051 CGroupDevicePolicy p;
1052
1053 r = sd_bus_message_read(message, "s", &policy);
1054 if (r < 0)
1055 return r;
1056
1057 p = cgroup_device_policy_from_string(policy);
1058 if (p < 0)
1059 return -EINVAL;
1060
1061 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1062 c->device_policy = p;
1063 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1064 unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
1065 }
1066
1067 return 1;
1068
1069 } else if (streq(name, "DeviceAllow")) {
1070 const char *path, *rwm;
1071 unsigned n = 0;
1072
1073 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1074 if (r < 0)
1075 return r;
1076
1077 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
1078
1079 if ((!is_deviceallow_pattern(path) &&
1080 !path_startswith(path, "/run/systemd/inaccessible/")) ||
1081 strpbrk(path, WHITESPACE))
1082 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
1083
1084 if (isempty(rwm))
1085 rwm = "rwm";
1086
1087 if (!in_charset(rwm, "rwm"))
1088 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
1089
1090 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1091 CGroupDeviceAllow *a = NULL, *b;
1092
1093 LIST_FOREACH(device_allow, b, c->device_allow) {
1094 if (path_equal(b->path, path)) {
1095 a = b;
1096 break;
1097 }
1098 }
1099
1100 if (!a) {
1101 a = new0(CGroupDeviceAllow, 1);
1102 if (!a)
1103 return -ENOMEM;
1104
1105 a->path = strdup(path);
1106 if (!a->path) {
1107 free(a);
1108 return -ENOMEM;
1109 }
1110
1111 LIST_PREPEND(device_allow, c->device_allow, a);
1112 }
1113
1114 a->r = !!strchr(rwm, 'r');
1115 a->w = !!strchr(rwm, 'w');
1116 a->m = !!strchr(rwm, 'm');
1117 }
1118
1119 n++;
1120 }
1121 if (r < 0)
1122 return r;
1123
1124 r = sd_bus_message_exit_container(message);
1125 if (r < 0)
1126 return r;
1127
1128 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1129 _cleanup_free_ char *buf = NULL;
1130 _cleanup_fclose_ FILE *f = NULL;
1131 CGroupDeviceAllow *a;
1132 size_t size = 0;
1133
1134 if (n == 0) {
1135 while (c->device_allow)
1136 cgroup_context_free_device_allow(c, c->device_allow);
1137 }
1138
1139 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1140
1141 f = open_memstream(&buf, &size);
1142 if (!f)
1143 return -ENOMEM;
1144
1145 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
1146
1147 fputs("DeviceAllow=\n", f);
1148 LIST_FOREACH(device_allow, a, c->device_allow)
1149 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1150
1151 r = fflush_and_check(f);
1152 if (r < 0)
1153 return r;
1154 unit_write_setting(u, flags, name, buf);
1155 }
1156
1157 return 1;
1158
1159 } else if (streq(name, "TasksAccounting")) {
1160 int b;
1161
1162 r = sd_bus_message_read(message, "b", &b);
1163 if (r < 0)
1164 return r;
1165
1166 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1167 c->tasks_accounting = b;
1168 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1169 unit_write_settingf(u, flags, name, "TasksAccounting=%s", yes_no(b));
1170 }
1171
1172 return 1;
1173
1174 } else if (streq(name, "TasksMax")) {
1175 uint64_t limit;
1176
1177 r = sd_bus_message_read(message, "t", &limit);
1178 if (r < 0)
1179 return r;
1180 if (limit <= 0)
1181 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
1182
1183 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1184 c->tasks_max = limit;
1185 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1186
1187 if (limit == (uint64_t) -1)
1188 unit_write_setting(u, flags, name, "TasksMax=infinity");
1189 else
1190 unit_write_settingf(u, flags, name, "TasksMax=%" PRIu64, limit);
1191 }
1192
1193 return 1;
1194
1195 } else if (streq(name, "TasksMaxScale")) {
1196 uint64_t limit;
1197 uint32_t raw;
1198
1199 r = sd_bus_message_read(message, "u", &raw);
1200 if (r < 0)
1201 return r;
1202
1203 limit = system_tasks_max_scale(raw, UINT32_MAX);
1204 if (limit <= 0 || limit >= UINT64_MAX)
1205 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
1206
1207 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1208 c->tasks_max = limit;
1209 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1210 unit_write_settingf(u, flags, name, "TasksMax=%" PRIu32 "%%",
1211 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
1212 }
1213
1214 return 1;
1215
1216 } else if (streq(name, "IPAccounting")) {
1217 int b;
1218
1219 r = sd_bus_message_read(message, "b", &b);
1220 if (r < 0)
1221 return r;
1222
1223 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1224 c->ip_accounting = b;
1225
1226 unit_invalidate_cgroup_bpf(u);
1227 unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
1228 }
1229
1230 return 1;
1231
1232 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1233 IPAddressAccessItem **list;
1234 size_t n = 0;
1235
1236 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1237
1238 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1239 if (r < 0)
1240 return r;
1241
1242 for (;;) {
1243 const void *ap;
1244 int32_t family;
1245 uint32_t prefixlen;
1246 size_t an;
1247
1248 r = sd_bus_message_enter_container(message, 'r', "iayu");
1249 if (r < 0)
1250 return r;
1251 if (r == 0)
1252 break;
1253
1254 r = sd_bus_message_read(message, "i", &family);
1255 if (r < 0)
1256 return r;
1257
1258 if (!IN_SET(family, AF_INET, AF_INET6))
1259 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects IPv4 or IPv6 addresses only.", name);
1260
1261 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1262 if (r < 0)
1263 return r;
1264
1265 if (an != FAMILY_ADDRESS_SIZE(family))
1266 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IP address has wrong size for family (%s, expected %zu, got %zu)",
1267 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1268
1269 r = sd_bus_message_read(message, "u", &prefixlen);
1270 if (r < 0)
1271 return r;
1272
1273 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
1274 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));
1275
1276 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1277 IPAddressAccessItem *item;
1278
1279 item = new0(IPAddressAccessItem, 1);
1280 if (!item)
1281 return -ENOMEM;
1282
1283 item->family = family;
1284 item->prefixlen = prefixlen;
1285 memcpy(&item->address, ap, an);
1286
1287 LIST_PREPEND(items, *list, item);
1288 }
1289
1290 r = sd_bus_message_exit_container(message);
1291 if (r < 0)
1292 return r;
1293
1294 n++;
1295 }
1296
1297 r = sd_bus_message_exit_container(message);
1298 if (r < 0)
1299 return r;
1300
1301 *list = ip_address_access_reduce(*list);
1302
1303 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1304 _cleanup_free_ char *buf = NULL;
1305 _cleanup_fclose_ FILE *f = NULL;
1306 IPAddressAccessItem *item;
1307 size_t size = 0;
1308
1309 if (n == 0)
1310 *list = ip_address_access_free_all(*list);
1311
1312 unit_invalidate_cgroup_bpf(u);
1313 f = open_memstream(&buf, &size);
1314 if (!f)
1315 return -ENOMEM;
1316
1317 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
1318
1319 fputs(name, f);
1320 fputs("=\n", f);
1321
1322 LIST_FOREACH(items, item, *list) {
1323 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1324
1325 errno = 0;
1326 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1327 return errno > 0 ? -errno : -EINVAL;
1328
1329 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1330 }
1331
1332 r = fflush_and_check(f);
1333 if (r < 0)
1334 return r;
1335
1336 unit_write_setting(u, flags, name, buf);
1337
1338 if (*list) {
1339 r = bpf_firewall_supported();
1340 if (r < 0)
1341 return r;
1342 if (r == 0) {
1343 static bool warned = false;
1344
1345 log_full(warned ? LOG_DEBUG : LOG_WARNING,
1346 "Transient unit %s configures an IP firewall, but the local system does not support BPF/cgroup firewalling.\n"
1347 "Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
1348
1349 warned = true;
1350 }
1351 }
1352 }
1353
1354 return 1;
1355 }
1356
1357 if (u->transient && u->load_state == UNIT_STUB)
1358 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
1359
1360 return 0;
1361 }