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