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