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