]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
Merge the "boot loader specification" wiki page
[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("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
302 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
303 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
304 SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
305 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
306 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
307 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
308 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
309 SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
310 SD_BUS_PROPERTY("IPAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, ip_accounting), 0),
311 SD_BUS_PROPERTY("IPAddressAllow", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_allow), 0),
312 SD_BUS_PROPERTY("IPAddressDeny", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_deny), 0),
313 SD_BUS_VTABLE_END
314 };
315
316 static int bus_cgroup_set_transient_property(
317 Unit *u,
318 CGroupContext *c,
319 const char *name,
320 sd_bus_message *message,
321 UnitWriteFlags flags,
322 sd_bus_error *error) {
323
324 int r;
325
326 assert(u);
327 assert(c);
328 assert(name);
329 assert(message);
330
331 flags |= UNIT_PRIVATE;
332
333 if (streq(name, "Delegate")) {
334 int b;
335
336 if (!UNIT_VTABLE(u)->can_delegate)
337 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
338
339 r = sd_bus_message_read(message, "b", &b);
340 if (r < 0)
341 return r;
342
343 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
344 c->delegate = b;
345 c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
346
347 unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
348 }
349
350 return 1;
351
352 } else if (streq(name, "DelegateControllers")) {
353 CGroupMask mask = 0;
354
355 if (!UNIT_VTABLE(u)->can_delegate)
356 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
357
358 r = sd_bus_message_enter_container(message, 'a', "s");
359 if (r < 0)
360 return r;
361
362 for (;;) {
363 CGroupController cc;
364 const char *t;
365
366 r = sd_bus_message_read(message, "s", &t);
367 if (r < 0)
368 return r;
369 if (r == 0)
370 break;
371
372 cc = cgroup_controller_from_string(t);
373 if (cc < 0)
374 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup controller '%s'", t);
375
376 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
377 }
378
379 r = sd_bus_message_exit_container(message);
380 if (r < 0)
381 return r;
382
383 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
384 _cleanup_free_ char *t = NULL;
385
386 r = cg_mask_to_string(mask, &t);
387 if (r < 0)
388 return r;
389
390 c->delegate = true;
391 if (mask == 0)
392 c->delegate_controllers = 0;
393 else
394 c->delegate_controllers |= mask;
395
396 unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
397 }
398
399 return 1;
400 }
401
402 return 0;
403 }
404
405 static int bus_cgroup_set_boolean(
406 Unit *u,
407 const char *name,
408 bool *p,
409 CGroupMask mask,
410 sd_bus_message *message,
411 UnitWriteFlags flags,
412 sd_bus_error *error) {
413
414 int b, r;
415
416 assert(p);
417
418 r = sd_bus_message_read(message, "b", &b);
419 if (r < 0)
420 return r;
421
422 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
423 *p = b;
424 unit_invalidate_cgroup(u, mask);
425 unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b));
426 }
427
428 return 1;
429 }
430
431 #define BUS_DEFINE_SET_CGROUP_WEIGHT(function, mask, check, val) \
432 static int bus_cgroup_set_##function( \
433 Unit *u, \
434 const char *name, \
435 uint64_t *p, \
436 sd_bus_message *message, \
437 UnitWriteFlags flags, \
438 sd_bus_error *error) { \
439 \
440 uint64_t v; \
441 int r; \
442 \
443 assert(p); \
444 \
445 r = sd_bus_message_read(message, "t", &v); \
446 if (r < 0) \
447 return r; \
448 \
449 if (!check(v)) \
450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
451 "Value specified in %s is out of range", name); \
452 \
453 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
454 *p = v; \
455 unit_invalidate_cgroup(u, (mask)); \
456 \
457 if (v == (val)) \
458 unit_write_settingf(u, flags, name, \
459 "%s=", name); \
460 else \
461 unit_write_settingf(u, flags, name, \
462 "%s=%" PRIu64, name, v); \
463 } \
464 \
465 return 1; \
466 }
467
468 #define BUS_DEFINE_SET_CGROUP_LIMIT(function, mask, scale, minimum) \
469 static int bus_cgroup_set_##function( \
470 Unit *u, \
471 const char *name, \
472 uint64_t *p, \
473 sd_bus_message *message, \
474 UnitWriteFlags flags, \
475 sd_bus_error *error) { \
476 \
477 uint64_t v; \
478 int r; \
479 \
480 assert(p); \
481 \
482 r = sd_bus_message_read(message, "t", &v); \
483 if (r < 0) \
484 return r; \
485 \
486 if (v < minimum) \
487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
488 "Value specified in %s is out of range", name); \
489 \
490 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
491 *p = v; \
492 unit_invalidate_cgroup(u, (mask)); \
493 \
494 if (v == CGROUP_LIMIT_MAX) \
495 unit_write_settingf(u, flags, name, \
496 "%s=infinity", name); \
497 else \
498 unit_write_settingf(u, flags, name, \
499 "%s=%" PRIu64, name, v); \
500 } \
501 \
502 return 1; \
503 } \
504 static int bus_cgroup_set_##function##_scale( \
505 Unit *u, \
506 const char *name, \
507 uint64_t *p, \
508 sd_bus_message *message, \
509 UnitWriteFlags flags, \
510 sd_bus_error *error) { \
511 \
512 uint64_t v; \
513 uint32_t raw; \
514 int r; \
515 \
516 assert(p); \
517 \
518 r = sd_bus_message_read(message, "u", &raw); \
519 if (r < 0) \
520 return r; \
521 \
522 v = scale(raw, UINT32_MAX); \
523 if (v < minimum || v >= UINT64_MAX) \
524 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
525 "Value specified in %s is out of range", name); \
526 \
527 if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
528 const char *e; \
529 \
530 *p = v; \
531 unit_invalidate_cgroup(u, (mask)); \
532 \
533 /* Chop off suffix */ \
534 assert_se(e = endswith(name, "Scale")); \
535 name = strndupa(name, e - name); \
536 \
537 unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name, \
538 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); \
539 } \
540 \
541 return 1; \
542 }
543
544 #pragma GCC diagnostic push
545 #pragma GCC diagnostic ignored "-Wtype-limits"
546 BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
547 BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
548 BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
549 BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
550 BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
551 BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
552 BUS_DEFINE_SET_CGROUP_LIMIT(tasks_max, CGROUP_MASK_PIDS, system_tasks_max_scale, 1);
553 #pragma GCC diagnostic pop
554
555 int bus_cgroup_set_property(
556 Unit *u,
557 CGroupContext *c,
558 const char *name,
559 sd_bus_message *message,
560 UnitWriteFlags flags,
561 sd_bus_error *error) {
562
563 CGroupIOLimitType iol_type;
564 int r;
565
566 assert(u);
567 assert(c);
568 assert(name);
569 assert(message);
570
571 flags |= UNIT_PRIVATE;
572
573 if (streq(name, "CPUAccounting"))
574 return bus_cgroup_set_boolean(u, name, &c->cpu_accounting, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU, message, flags, error);
575
576 if (streq(name, "CPUWeight"))
577 return bus_cgroup_set_cpu_weight(u, name, &c->cpu_weight, message, flags, error);
578
579 if (streq(name, "StartupCPUWeight"))
580 return bus_cgroup_set_cpu_weight(u, name, &c->startup_cpu_weight, message, flags, error);
581
582 if (streq(name, "CPUShares"))
583 return bus_cgroup_set_cpu_shares(u, name, &c->cpu_shares, message, flags, error);
584
585 if (streq(name, "StartupCPUShares"))
586 return bus_cgroup_set_cpu_shares(u, name, &c->startup_cpu_shares, message, flags, error);
587
588 if (streq(name, "IOAccounting"))
589 return bus_cgroup_set_boolean(u, name, &c->io_accounting, CGROUP_MASK_IO, message, flags, error);
590
591 if (streq(name, "IOWeight"))
592 return bus_cgroup_set_io_weight(u, name, &c->io_weight, message, flags, error);
593
594 if (streq(name, "StartupIOWeight"))
595 return bus_cgroup_set_io_weight(u, name, &c->startup_io_weight, message, flags, error);
596
597 if (streq(name, "BlockIOAccounting"))
598 return bus_cgroup_set_boolean(u, name, &c->blockio_accounting, CGROUP_MASK_BLKIO, message, flags, error);
599
600 if (streq(name, "BlockIOWeight"))
601 return bus_cgroup_set_blockio_weight(u, name, &c->blockio_weight, message, flags, error);
602
603 if (streq(name, "StartupBlockIOWeight"))
604 return bus_cgroup_set_blockio_weight(u, name, &c->startup_blockio_weight, message, flags, error);
605
606 if (streq(name, "MemoryAccounting"))
607 return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
608
609 if (streq(name, "MemoryLow"))
610 return bus_cgroup_set_memory(u, name, &c->memory_low, message, flags, error);
611
612 if (streq(name, "MemoryHigh"))
613 return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
614
615 if (streq(name, "MemorySwapMax"))
616 return bus_cgroup_set_swap(u, name, &c->memory_swap_max, message, flags, error);
617
618 if (streq(name, "MemoryMax"))
619 return bus_cgroup_set_memory(u, name, &c->memory_max, message, flags, error);
620
621 if (streq(name, "MemoryLimit"))
622 return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
623
624 if (streq(name, "MemoryLowScale"))
625 return bus_cgroup_set_memory_scale(u, name, &c->memory_low, message, flags, error);
626
627 if (streq(name, "MemoryHighScale"))
628 return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
629
630 if (streq(name, "MemorySwapMaxScale"))
631 return bus_cgroup_set_swap_scale(u, name, &c->memory_swap_max, message, flags, error);
632
633 if (streq(name, "MemoryMaxScale"))
634 return bus_cgroup_set_memory_scale(u, name, &c->memory_max, message, flags, error);
635
636 if (streq(name, "MemoryLimitScale"))
637 return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
638
639 if (streq(name, "TasksAccounting"))
640 return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
641
642 if (streq(name, "TasksMax"))
643 return bus_cgroup_set_tasks_max(u, name, &c->tasks_max, message, flags, error);
644
645 if (streq(name, "TasksMaxScale"))
646 return bus_cgroup_set_tasks_max_scale(u, name, &c->tasks_max, message, flags, error);
647
648 if (streq(name, "CPUQuotaPerSecUSec")) {
649 uint64_t u64;
650
651 r = sd_bus_message_read(message, "t", &u64);
652 if (r < 0)
653 return r;
654
655 if (u64 <= 0)
656 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
657
658 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
659 c->cpu_quota_per_sec_usec = u64;
660 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
661
662 if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
663 unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
664 else
665 /* config_parse_cpu_quota() requires an integer, so truncating division is used on
666 * purpose here. */
667 unit_write_settingf(u, flags, "CPUQuota",
668 "CPUQuota=%0.f%%",
669 (double) (c->cpu_quota_per_sec_usec / 10000));
670 }
671
672 return 1;
673
674 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
675 const char *path;
676 unsigned n = 0;
677 uint64_t u64;
678
679 r = sd_bus_message_enter_container(message, 'a', "(st)");
680 if (r < 0)
681 return r;
682
683 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
684
685 if (!path_is_normalized(path))
686 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
687
688 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
689 CGroupIODeviceLimit *a = NULL, *b;
690
691 LIST_FOREACH(device_limits, b, c->io_device_limits) {
692 if (path_equal(path, b->path)) {
693 a = b;
694 break;
695 }
696 }
697
698 if (!a) {
699 CGroupIOLimitType type;
700
701 a = new0(CGroupIODeviceLimit, 1);
702 if (!a)
703 return -ENOMEM;
704
705 a->path = strdup(path);
706 if (!a->path) {
707 free(a);
708 return -ENOMEM;
709 }
710
711 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
712 a->limits[type] = cgroup_io_limit_defaults[type];
713
714 LIST_PREPEND(device_limits, c->io_device_limits, a);
715 }
716
717 a->limits[iol_type] = u64;
718 }
719
720 n++;
721 }
722 if (r < 0)
723 return r;
724
725 r = sd_bus_message_exit_container(message);
726 if (r < 0)
727 return r;
728
729 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
730 CGroupIODeviceLimit *a;
731 _cleanup_free_ char *buf = NULL;
732 _cleanup_fclose_ FILE *f = NULL;
733 size_t size = 0;
734
735 if (n == 0) {
736 LIST_FOREACH(device_limits, a, c->io_device_limits)
737 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
738 }
739
740 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
741
742 f = open_memstream(&buf, &size);
743 if (!f)
744 return -ENOMEM;
745
746 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
747
748 fprintf(f, "%s=\n", name);
749 LIST_FOREACH(device_limits, a, c->io_device_limits)
750 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
751 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
752
753 r = fflush_and_check(f);
754 if (r < 0)
755 return r;
756 unit_write_setting(u, flags, name, buf);
757 }
758
759 return 1;
760
761 } else if (streq(name, "IODeviceWeight")) {
762 const char *path;
763 uint64_t weight;
764 unsigned n = 0;
765
766 r = sd_bus_message_enter_container(message, 'a', "(st)");
767 if (r < 0)
768 return r;
769
770 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
771
772 if (!path_is_normalized(path))
773 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
774
775 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
776 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
777
778 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
779 CGroupIODeviceWeight *a = NULL, *b;
780
781 LIST_FOREACH(device_weights, b, c->io_device_weights) {
782 if (path_equal(b->path, path)) {
783 a = b;
784 break;
785 }
786 }
787
788 if (!a) {
789 a = new0(CGroupIODeviceWeight, 1);
790 if (!a)
791 return -ENOMEM;
792
793 a->path = strdup(path);
794 if (!a->path) {
795 free(a);
796 return -ENOMEM;
797 }
798 LIST_PREPEND(device_weights, c->io_device_weights, a);
799 }
800
801 a->weight = weight;
802 }
803
804 n++;
805 }
806
807 r = sd_bus_message_exit_container(message);
808 if (r < 0)
809 return r;
810
811 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
812 _cleanup_free_ char *buf = NULL;
813 _cleanup_fclose_ FILE *f = NULL;
814 CGroupIODeviceWeight *a;
815 size_t size = 0;
816
817 if (n == 0) {
818 while (c->io_device_weights)
819 cgroup_context_free_io_device_weight(c, c->io_device_weights);
820 }
821
822 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
823
824 f = open_memstream(&buf, &size);
825 if (!f)
826 return -ENOMEM;
827
828 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
829
830 fputs("IODeviceWeight=\n", f);
831 LIST_FOREACH(device_weights, a, c->io_device_weights)
832 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
833
834 r = fflush_and_check(f);
835 if (r < 0)
836 return r;
837 unit_write_setting(u, flags, name, buf);
838 }
839
840 return 1;
841
842 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
843 const char *path;
844 bool read = true;
845 unsigned n = 0;
846 uint64_t u64;
847
848 if (streq(name, "BlockIOWriteBandwidth"))
849 read = false;
850
851 r = sd_bus_message_enter_container(message, 'a', "(st)");
852 if (r < 0)
853 return r;
854
855 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
856
857 if (!path_is_normalized(path))
858 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
859
860 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
861 CGroupBlockIODeviceBandwidth *a = NULL, *b;
862
863 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
864 if (path_equal(path, b->path)) {
865 a = b;
866 break;
867 }
868 }
869
870 if (!a) {
871 a = new0(CGroupBlockIODeviceBandwidth, 1);
872 if (!a)
873 return -ENOMEM;
874
875 a->rbps = CGROUP_LIMIT_MAX;
876 a->wbps = CGROUP_LIMIT_MAX;
877 a->path = strdup(path);
878 if (!a->path) {
879 free(a);
880 return -ENOMEM;
881 }
882
883 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
884 }
885
886 if (read)
887 a->rbps = u64;
888 else
889 a->wbps = u64;
890 }
891
892 n++;
893 }
894 if (r < 0)
895 return r;
896
897 r = sd_bus_message_exit_container(message);
898 if (r < 0)
899 return r;
900
901 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
902 CGroupBlockIODeviceBandwidth *a;
903 _cleanup_free_ char *buf = NULL;
904 _cleanup_fclose_ FILE *f = NULL;
905 size_t size = 0;
906
907 if (n == 0) {
908 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
909 if (read)
910 a->rbps = CGROUP_LIMIT_MAX;
911 else
912 a->wbps = CGROUP_LIMIT_MAX;
913 }
914 }
915
916 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
917
918 f = open_memstream(&buf, &size);
919 if (!f)
920 return -ENOMEM;
921
922 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
923
924 if (read) {
925 fputs("BlockIOReadBandwidth=\n", f);
926 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
927 if (a->rbps != CGROUP_LIMIT_MAX)
928 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
929 } else {
930 fputs("BlockIOWriteBandwidth=\n", f);
931 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
932 if (a->wbps != CGROUP_LIMIT_MAX)
933 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
934 }
935
936 r = fflush_and_check(f);
937 if (r < 0)
938 return r;
939
940 unit_write_setting(u, flags, name, buf);
941 }
942
943 return 1;
944
945 } else if (streq(name, "BlockIODeviceWeight")) {
946 const char *path;
947 uint64_t weight;
948 unsigned n = 0;
949
950 r = sd_bus_message_enter_container(message, 'a', "(st)");
951 if (r < 0)
952 return r;
953
954 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
955
956 if (!path_is_normalized(path))
957 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
958
959 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
960 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
961
962 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
963 CGroupBlockIODeviceWeight *a = NULL, *b;
964
965 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
966 if (path_equal(b->path, path)) {
967 a = b;
968 break;
969 }
970 }
971
972 if (!a) {
973 a = new0(CGroupBlockIODeviceWeight, 1);
974 if (!a)
975 return -ENOMEM;
976
977 a->path = strdup(path);
978 if (!a->path) {
979 free(a);
980 return -ENOMEM;
981 }
982 LIST_PREPEND(device_weights, c->blockio_device_weights, a);
983 }
984
985 a->weight = weight;
986 }
987
988 n++;
989 }
990
991 r = sd_bus_message_exit_container(message);
992 if (r < 0)
993 return r;
994
995 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
996 _cleanup_free_ char *buf = NULL;
997 _cleanup_fclose_ FILE *f = NULL;
998 CGroupBlockIODeviceWeight *a;
999 size_t size = 0;
1000
1001 if (n == 0) {
1002 while (c->blockio_device_weights)
1003 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
1004 }
1005
1006 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
1007
1008 f = open_memstream(&buf, &size);
1009 if (!f)
1010 return -ENOMEM;
1011
1012 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
1013
1014 fputs("BlockIODeviceWeight=\n", f);
1015 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
1016 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
1017
1018 r = fflush_and_check(f);
1019 if (r < 0)
1020 return r;
1021
1022 unit_write_setting(u, flags, name, buf);
1023 }
1024
1025 return 1;
1026
1027 } else if (streq(name, "DevicePolicy")) {
1028 const char *policy;
1029 CGroupDevicePolicy p;
1030
1031 r = sd_bus_message_read(message, "s", &policy);
1032 if (r < 0)
1033 return r;
1034
1035 p = cgroup_device_policy_from_string(policy);
1036 if (p < 0)
1037 return -EINVAL;
1038
1039 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1040 c->device_policy = p;
1041 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1042 unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
1043 }
1044
1045 return 1;
1046
1047 } else if (streq(name, "DeviceAllow")) {
1048 const char *path, *rwm;
1049 unsigned n = 0;
1050
1051 r = sd_bus_message_enter_container(message, 'a', "(ss)");
1052 if (r < 0)
1053 return r;
1054
1055 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
1056
1057 if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
1058 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
1059
1060 if (isempty(rwm))
1061 rwm = "rwm";
1062 else if (!in_charset(rwm, "rwm"))
1063 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
1064
1065 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1066 CGroupDeviceAllow *a = NULL, *b;
1067
1068 LIST_FOREACH(device_allow, b, c->device_allow) {
1069 if (path_equal(b->path, path)) {
1070 a = b;
1071 break;
1072 }
1073 }
1074
1075 if (!a) {
1076 a = new0(CGroupDeviceAllow, 1);
1077 if (!a)
1078 return -ENOMEM;
1079
1080 a->path = strdup(path);
1081 if (!a->path) {
1082 free(a);
1083 return -ENOMEM;
1084 }
1085
1086 LIST_PREPEND(device_allow, c->device_allow, a);
1087 }
1088
1089 a->r = !!strchr(rwm, 'r');
1090 a->w = !!strchr(rwm, 'w');
1091 a->m = !!strchr(rwm, 'm');
1092 }
1093
1094 n++;
1095 }
1096 if (r < 0)
1097 return r;
1098
1099 r = sd_bus_message_exit_container(message);
1100 if (r < 0)
1101 return r;
1102
1103 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1104 _cleanup_free_ char *buf = NULL;
1105 _cleanup_fclose_ FILE *f = NULL;
1106 CGroupDeviceAllow *a;
1107 size_t size = 0;
1108
1109 if (n == 0) {
1110 while (c->device_allow)
1111 cgroup_context_free_device_allow(c, c->device_allow);
1112 }
1113
1114 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1115
1116 f = open_memstream(&buf, &size);
1117 if (!f)
1118 return -ENOMEM;
1119
1120 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
1121
1122 fputs("DeviceAllow=\n", f);
1123 LIST_FOREACH(device_allow, a, c->device_allow)
1124 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1125
1126 r = fflush_and_check(f);
1127 if (r < 0)
1128 return r;
1129 unit_write_setting(u, flags, name, buf);
1130 }
1131
1132 return 1;
1133
1134 } else if (streq(name, "IPAccounting")) {
1135 int b;
1136
1137 r = sd_bus_message_read(message, "b", &b);
1138 if (r < 0)
1139 return r;
1140
1141 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1142 c->ip_accounting = b;
1143
1144 unit_invalidate_cgroup_bpf(u);
1145 unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
1146 }
1147
1148 return 1;
1149
1150 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1151 IPAddressAccessItem **list;
1152 size_t n = 0;
1153
1154 list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
1155
1156 r = sd_bus_message_enter_container(message, 'a', "(iayu)");
1157 if (r < 0)
1158 return r;
1159
1160 for (;;) {
1161 const void *ap;
1162 int32_t family;
1163 uint32_t prefixlen;
1164 size_t an;
1165
1166 r = sd_bus_message_enter_container(message, 'r', "iayu");
1167 if (r < 0)
1168 return r;
1169 if (r == 0)
1170 break;
1171
1172 r = sd_bus_message_read(message, "i", &family);
1173 if (r < 0)
1174 return r;
1175
1176 if (!IN_SET(family, AF_INET, AF_INET6))
1177 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= expects IPv4 or IPv6 addresses only.", name);
1178
1179 r = sd_bus_message_read_array(message, 'y', &ap, &an);
1180 if (r < 0)
1181 return r;
1182
1183 if (an != FAMILY_ADDRESS_SIZE(family))
1184 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IP address has wrong size for family (%s, expected %zu, got %zu)",
1185 af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
1186
1187 r = sd_bus_message_read(message, "u", &prefixlen);
1188 if (r < 0)
1189 return r;
1190
1191 if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
1192 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));
1193
1194 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1195 IPAddressAccessItem *item;
1196
1197 item = new0(IPAddressAccessItem, 1);
1198 if (!item)
1199 return -ENOMEM;
1200
1201 item->family = family;
1202 item->prefixlen = prefixlen;
1203 memcpy(&item->address, ap, an);
1204
1205 LIST_PREPEND(items, *list, item);
1206 }
1207
1208 r = sd_bus_message_exit_container(message);
1209 if (r < 0)
1210 return r;
1211
1212 n++;
1213 }
1214
1215 r = sd_bus_message_exit_container(message);
1216 if (r < 0)
1217 return r;
1218
1219 *list = ip_address_access_reduce(*list);
1220
1221 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1222 _cleanup_free_ char *buf = NULL;
1223 _cleanup_fclose_ FILE *f = NULL;
1224 IPAddressAccessItem *item;
1225 size_t size = 0;
1226
1227 if (n == 0)
1228 *list = ip_address_access_free_all(*list);
1229
1230 unit_invalidate_cgroup_bpf(u);
1231 f = open_memstream(&buf, &size);
1232 if (!f)
1233 return -ENOMEM;
1234
1235 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
1236
1237 fputs(name, f);
1238 fputs("=\n", f);
1239
1240 LIST_FOREACH(items, item, *list) {
1241 char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1242
1243 errno = 0;
1244 if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
1245 return errno > 0 ? -errno : -EINVAL;
1246
1247 fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
1248 }
1249
1250 r = fflush_and_check(f);
1251 if (r < 0)
1252 return r;
1253
1254 unit_write_setting(u, flags, name, buf);
1255
1256 if (*list) {
1257 r = bpf_firewall_supported();
1258 if (r < 0)
1259 return r;
1260 if (r == BPF_FIREWALL_UNSUPPORTED) {
1261 static bool warned = false;
1262
1263 log_full(warned ? LOG_DEBUG : LOG_WARNING,
1264 "Transient unit %s configures an IP firewall, but the local system does not support BPF/cgroup firewalling.\n"
1265 "Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
1266
1267 warned = true;
1268 }
1269 }
1270 }
1271
1272 return 1;
1273 }
1274
1275 if (u->transient && u->load_state == UNIT_STUB)
1276 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
1277
1278 return 0;
1279 }