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