]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
Merge pull request #3526 from fbuihuu/fix-console-log-color
[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("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
214 SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
215 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
216 SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
217 SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
218 SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
219 SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
220 SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
221 SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
222 SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
223 SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
224 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
225 SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
226 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
227 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
228 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
229 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
230 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
231 SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
232 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
233 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
234 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
235 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
236 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
237 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
238 SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
239 SD_BUS_VTABLE_END
240 };
241
242 static int bus_cgroup_set_transient_property(
243 Unit *u,
244 CGroupContext *c,
245 const char *name,
246 sd_bus_message *message,
247 UnitSetPropertiesMode mode,
248 sd_bus_error *error) {
249
250 int r;
251
252 assert(u);
253 assert(c);
254 assert(name);
255 assert(message);
256
257 if (streq(name, "Delegate")) {
258 int b;
259
260 r = sd_bus_message_read(message, "b", &b);
261 if (r < 0)
262 return r;
263
264 if (mode != UNIT_CHECK) {
265 c->delegate = b;
266 unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
267 }
268
269 return 1;
270 }
271
272 return 0;
273 }
274
275 int bus_cgroup_set_property(
276 Unit *u,
277 CGroupContext *c,
278 const char *name,
279 sd_bus_message *message,
280 UnitSetPropertiesMode mode,
281 sd_bus_error *error) {
282
283 CGroupIOLimitType iol_type;
284 int r;
285
286 assert(u);
287 assert(c);
288 assert(name);
289 assert(message);
290
291 if (streq(name, "CPUAccounting")) {
292 int b;
293
294 r = sd_bus_message_read(message, "b", &b);
295 if (r < 0)
296 return r;
297
298 if (mode != UNIT_CHECK) {
299 c->cpu_accounting = b;
300 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
301 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
302 }
303
304 return 1;
305
306 } else if (streq(name, "CPUShares")) {
307 uint64_t shares;
308
309 r = sd_bus_message_read(message, "t", &shares);
310 if (r < 0)
311 return r;
312
313 if (!CGROUP_CPU_SHARES_IS_OK(shares))
314 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
315
316 if (mode != UNIT_CHECK) {
317 c->cpu_shares = shares;
318 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
319
320 if (shares == CGROUP_CPU_SHARES_INVALID)
321 unit_write_drop_in_private(u, mode, name, "CPUShares=");
322 else
323 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
324 }
325
326 return 1;
327
328 } else if (streq(name, "StartupCPUShares")) {
329 uint64_t shares;
330
331 r = sd_bus_message_read(message, "t", &shares);
332 if (r < 0)
333 return r;
334
335 if (!CGROUP_CPU_SHARES_IS_OK(shares))
336 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
337
338 if (mode != UNIT_CHECK) {
339 c->startup_cpu_shares = shares;
340 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
341
342 if (shares == CGROUP_CPU_SHARES_INVALID)
343 unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
344 else
345 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
346 }
347
348 return 1;
349
350 } else if (streq(name, "CPUQuotaPerSecUSec")) {
351 uint64_t u64;
352
353 r = sd_bus_message_read(message, "t", &u64);
354 if (r < 0)
355 return r;
356
357 if (u64 <= 0)
358 return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
359
360 if (mode != UNIT_CHECK) {
361 c->cpu_quota_per_sec_usec = u64;
362 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
363 unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
364 }
365
366 return 1;
367
368 } else if (streq(name, "IOAccounting")) {
369 int b;
370
371 r = sd_bus_message_read(message, "b", &b);
372 if (r < 0)
373 return r;
374
375 if (mode != UNIT_CHECK) {
376 c->io_accounting = b;
377 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
378 unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
379 }
380
381 return 1;
382
383 } else if (streq(name, "IOWeight")) {
384 uint64_t weight;
385
386 r = sd_bus_message_read(message, "t", &weight);
387 if (r < 0)
388 return r;
389
390 if (!CGROUP_WEIGHT_IS_OK(weight))
391 return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
392
393 if (mode != UNIT_CHECK) {
394 c->io_weight = weight;
395 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
396
397 if (weight == CGROUP_WEIGHT_INVALID)
398 unit_write_drop_in_private(u, mode, name, "IOWeight=");
399 else
400 unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
401 }
402
403 return 1;
404
405 } else if (streq(name, "StartupIOWeight")) {
406 uint64_t weight;
407
408 r = sd_bus_message_read(message, "t", &weight);
409 if (r < 0)
410 return r;
411
412 if (CGROUP_WEIGHT_IS_OK(weight))
413 return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
414
415 if (mode != UNIT_CHECK) {
416 c->startup_io_weight = weight;
417 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
418
419 if (weight == CGROUP_WEIGHT_INVALID)
420 unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
421 else
422 unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
423 }
424
425 return 1;
426
427 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
428 const char *path;
429 unsigned n = 0;
430 uint64_t u64;
431
432 r = sd_bus_message_enter_container(message, 'a', "(st)");
433 if (r < 0)
434 return r;
435
436 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
437
438 if (mode != UNIT_CHECK) {
439 CGroupIODeviceLimit *a = NULL, *b;
440
441 LIST_FOREACH(device_limits, b, c->io_device_limits) {
442 if (path_equal(path, b->path)) {
443 a = b;
444 break;
445 }
446 }
447
448 if (!a) {
449 CGroupIOLimitType type;
450
451 a = new0(CGroupIODeviceLimit, 1);
452 if (!a)
453 return -ENOMEM;
454
455 a->path = strdup(path);
456 if (!a->path) {
457 free(a);
458 return -ENOMEM;
459 }
460
461 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
462 a->limits[type] = cgroup_io_limit_defaults[type];
463
464 LIST_PREPEND(device_limits, c->io_device_limits, a);
465 }
466
467 a->limits[iol_type] = u64;
468 }
469
470 n++;
471 }
472 if (r < 0)
473 return r;
474
475 r = sd_bus_message_exit_container(message);
476 if (r < 0)
477 return r;
478
479 if (mode != UNIT_CHECK) {
480 CGroupIODeviceLimit *a;
481 _cleanup_free_ char *buf = NULL;
482 _cleanup_fclose_ FILE *f = NULL;
483 size_t size = 0;
484
485 if (n == 0) {
486 LIST_FOREACH(device_limits, a, c->io_device_limits)
487 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
488 }
489
490 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
491
492 f = open_memstream(&buf, &size);
493 if (!f)
494 return -ENOMEM;
495
496 fprintf(f, "%s=\n", name);
497 LIST_FOREACH(device_limits, a, c->io_device_limits)
498 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
499 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
500
501 r = fflush_and_check(f);
502 if (r < 0)
503 return r;
504 unit_write_drop_in_private(u, mode, name, buf);
505 }
506
507 return 1;
508
509 } else if (streq(name, "IODeviceWeight")) {
510 const char *path;
511 uint64_t weight;
512 unsigned n = 0;
513
514 r = sd_bus_message_enter_container(message, 'a', "(st)");
515 if (r < 0)
516 return r;
517
518 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
519
520 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
521 return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
522
523 if (mode != UNIT_CHECK) {
524 CGroupIODeviceWeight *a = NULL, *b;
525
526 LIST_FOREACH(device_weights, b, c->io_device_weights) {
527 if (path_equal(b->path, path)) {
528 a = b;
529 break;
530 }
531 }
532
533 if (!a) {
534 a = new0(CGroupIODeviceWeight, 1);
535 if (!a)
536 return -ENOMEM;
537
538 a->path = strdup(path);
539 if (!a->path) {
540 free(a);
541 return -ENOMEM;
542 }
543 LIST_PREPEND(device_weights,c->io_device_weights, a);
544 }
545
546 a->weight = weight;
547 }
548
549 n++;
550 }
551
552 r = sd_bus_message_exit_container(message);
553 if (r < 0)
554 return r;
555
556 if (mode != UNIT_CHECK) {
557 _cleanup_free_ char *buf = NULL;
558 _cleanup_fclose_ FILE *f = NULL;
559 CGroupIODeviceWeight *a;
560 size_t size = 0;
561
562 if (n == 0) {
563 while (c->io_device_weights)
564 cgroup_context_free_io_device_weight(c, c->io_device_weights);
565 }
566
567 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
568
569 f = open_memstream(&buf, &size);
570 if (!f)
571 return -ENOMEM;
572
573 fputs("IODeviceWeight=\n", f);
574 LIST_FOREACH(device_weights, a, c->io_device_weights)
575 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
576
577 r = fflush_and_check(f);
578 if (r < 0)
579 return r;
580 unit_write_drop_in_private(u, mode, name, buf);
581 }
582
583 return 1;
584
585 } else if (streq(name, "BlockIOAccounting")) {
586 int b;
587
588 r = sd_bus_message_read(message, "b", &b);
589 if (r < 0)
590 return r;
591
592 if (mode != UNIT_CHECK) {
593 c->blockio_accounting = b;
594 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
595 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
596 }
597
598 return 1;
599
600 } else if (streq(name, "BlockIOWeight")) {
601 uint64_t weight;
602
603 r = sd_bus_message_read(message, "t", &weight);
604 if (r < 0)
605 return r;
606
607 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
608 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
609
610 if (mode != UNIT_CHECK) {
611 c->blockio_weight = weight;
612 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
613
614 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
615 unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
616 else
617 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
618 }
619
620 return 1;
621
622 } else if (streq(name, "StartupBlockIOWeight")) {
623 uint64_t weight;
624
625 r = sd_bus_message_read(message, "t", &weight);
626 if (r < 0)
627 return r;
628
629 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
630 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
631
632 if (mode != UNIT_CHECK) {
633 c->startup_blockio_weight = weight;
634 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
635
636 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
637 unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
638 else
639 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
640 }
641
642 return 1;
643
644 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
645 const char *path;
646 bool read = true;
647 unsigned n = 0;
648 uint64_t u64;
649
650 if (streq(name, "BlockIOWriteBandwidth"))
651 read = false;
652
653 r = sd_bus_message_enter_container(message, 'a', "(st)");
654 if (r < 0)
655 return r;
656
657 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
658
659 if (mode != UNIT_CHECK) {
660 CGroupBlockIODeviceBandwidth *a = NULL, *b;
661
662 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
663 if (path_equal(path, b->path)) {
664 a = b;
665 break;
666 }
667 }
668
669 if (!a) {
670 a = new0(CGroupBlockIODeviceBandwidth, 1);
671 if (!a)
672 return -ENOMEM;
673
674 a->rbps = CGROUP_LIMIT_MAX;
675 a->wbps = CGROUP_LIMIT_MAX;
676 a->path = strdup(path);
677 if (!a->path) {
678 free(a);
679 return -ENOMEM;
680 }
681
682 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
683 }
684
685 if (read)
686 a->rbps = u64;
687 else
688 a->wbps = u64;
689 }
690
691 n++;
692 }
693 if (r < 0)
694 return r;
695
696 r = sd_bus_message_exit_container(message);
697 if (r < 0)
698 return r;
699
700 if (mode != UNIT_CHECK) {
701 CGroupBlockIODeviceBandwidth *a;
702 _cleanup_free_ char *buf = NULL;
703 _cleanup_fclose_ FILE *f = NULL;
704 size_t size = 0;
705
706 if (n == 0) {
707 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
708 if (read)
709 a->rbps = CGROUP_LIMIT_MAX;
710 else
711 a->wbps = CGROUP_LIMIT_MAX;
712 }
713 }
714
715 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
716
717 f = open_memstream(&buf, &size);
718 if (!f)
719 return -ENOMEM;
720
721 if (read) {
722 fputs("BlockIOReadBandwidth=\n", f);
723 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
724 if (a->rbps != CGROUP_LIMIT_MAX)
725 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
726 } else {
727 fputs("BlockIOWriteBandwidth=\n", f);
728 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
729 if (a->wbps != CGROUP_LIMIT_MAX)
730 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
731 }
732
733 r = fflush_and_check(f);
734 if (r < 0)
735 return r;
736 unit_write_drop_in_private(u, mode, name, buf);
737 }
738
739 return 1;
740
741 } else if (streq(name, "BlockIODeviceWeight")) {
742 const char *path;
743 uint64_t weight;
744 unsigned n = 0;
745
746 r = sd_bus_message_enter_container(message, 'a', "(st)");
747 if (r < 0)
748 return r;
749
750 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
751
752 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
753 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
754
755 if (mode != UNIT_CHECK) {
756 CGroupBlockIODeviceWeight *a = NULL, *b;
757
758 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
759 if (path_equal(b->path, path)) {
760 a = b;
761 break;
762 }
763 }
764
765 if (!a) {
766 a = new0(CGroupBlockIODeviceWeight, 1);
767 if (!a)
768 return -ENOMEM;
769
770 a->path = strdup(path);
771 if (!a->path) {
772 free(a);
773 return -ENOMEM;
774 }
775 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
776 }
777
778 a->weight = weight;
779 }
780
781 n++;
782 }
783
784 r = sd_bus_message_exit_container(message);
785 if (r < 0)
786 return r;
787
788 if (mode != UNIT_CHECK) {
789 _cleanup_free_ char *buf = NULL;
790 _cleanup_fclose_ FILE *f = NULL;
791 CGroupBlockIODeviceWeight *a;
792 size_t size = 0;
793
794 if (n == 0) {
795 while (c->blockio_device_weights)
796 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
797 }
798
799 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
800
801 f = open_memstream(&buf, &size);
802 if (!f)
803 return -ENOMEM;
804
805 fputs("BlockIODeviceWeight=\n", f);
806 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
807 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
808
809 r = fflush_and_check(f);
810 if (r < 0)
811 return r;
812 unit_write_drop_in_private(u, mode, name, buf);
813 }
814
815 return 1;
816
817 } else if (streq(name, "MemoryAccounting")) {
818 int b;
819
820 r = sd_bus_message_read(message, "b", &b);
821 if (r < 0)
822 return r;
823
824 if (mode != UNIT_CHECK) {
825 c->memory_accounting = b;
826 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
827 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
828 }
829
830 return 1;
831
832 } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) {
833 uint64_t v;
834
835 r = sd_bus_message_read(message, "t", &v);
836 if (r < 0)
837 return r;
838 if (v <= 0)
839 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
840
841 if (mode != UNIT_CHECK) {
842 if (streq(name, "MemoryLow"))
843 c->memory_low = v;
844 else if (streq(name, "MemoryHigh"))
845 c->memory_high = v;
846 else
847 c->memory_max = v;
848
849 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
850
851 if (v == CGROUP_LIMIT_MAX)
852 unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name);
853 else
854 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v);
855 }
856
857 return 1;
858
859 } else if (STR_IN_SET(name, "MemoryLowByPhysicalMemory", "MemoryHighByPhysicalMemory", "MemoryMaxByPhysicalMemory")) {
860 uint32_t raw;
861 uint64_t v;
862
863 r = sd_bus_message_read(message, "u", &raw);
864 if (r < 0)
865 return r;
866
867 v = physical_memory_scale(raw, UINT32_MAX);
868 if (v <= 0 || v == UINT64_MAX)
869 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
870
871 if (mode != UNIT_CHECK) {
872 const char *e;
873
874 /* Chop off suffix */
875 assert_se(e = endswith(name, "ByPhysicalMemory"));
876 name = strndupa(name, e - name);
877
878 if (streq(name, "MemoryLow"))
879 c->memory_low = v;
880 else if (streq(name, "MemoryHigh"))
881 c->memory_high = v;
882 else
883 c->memory_max = v;
884
885 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
886 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX)));
887 }
888
889 return 1;
890
891 } else if (streq(name, "MemoryLimit")) {
892 uint64_t limit;
893
894 r = sd_bus_message_read(message, "t", &limit);
895 if (r < 0)
896 return r;
897 if (limit <= 0)
898 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
899
900 if (mode != UNIT_CHECK) {
901 c->memory_limit = limit;
902 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
903
904 if (limit == (uint64_t) -1)
905 unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
906 else
907 unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
908 }
909
910 return 1;
911
912 } else if (streq(name, "MemoryLimitByPhysicalMemory")) {
913 uint64_t limit;
914 uint32_t raw;
915
916 r = sd_bus_message_read(message, "u", &raw);
917 if (r < 0)
918 return r;
919
920 limit = physical_memory_scale(raw, UINT32_MAX);
921 if (limit <= 0 || limit == UINT64_MAX)
922 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
923
924 if (mode != UNIT_CHECK) {
925 c->memory_limit = limit;
926 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
927 unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX)));
928 }
929
930 return 1;
931
932 } else if (streq(name, "DevicePolicy")) {
933 const char *policy;
934 CGroupDevicePolicy p;
935
936 r = sd_bus_message_read(message, "s", &policy);
937 if (r < 0)
938 return r;
939
940 p = cgroup_device_policy_from_string(policy);
941 if (p < 0)
942 return -EINVAL;
943
944 if (mode != UNIT_CHECK) {
945 c->device_policy = p;
946 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
947 unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy);
948 }
949
950 return 1;
951
952 } else if (streq(name, "DeviceAllow")) {
953 const char *path, *rwm;
954 unsigned n = 0;
955
956 r = sd_bus_message_enter_container(message, 'a', "(ss)");
957 if (r < 0)
958 return r;
959
960 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
961
962 if ((!startswith(path, "/dev/") &&
963 !startswith(path, "block-") &&
964 !startswith(path, "char-")) ||
965 strpbrk(path, WHITESPACE))
966 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
967
968 if (isempty(rwm))
969 rwm = "rwm";
970
971 if (!in_charset(rwm, "rwm"))
972 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
973
974 if (mode != UNIT_CHECK) {
975 CGroupDeviceAllow *a = NULL, *b;
976
977 LIST_FOREACH(device_allow, b, c->device_allow) {
978 if (path_equal(b->path, path)) {
979 a = b;
980 break;
981 }
982 }
983
984 if (!a) {
985 a = new0(CGroupDeviceAllow, 1);
986 if (!a)
987 return -ENOMEM;
988
989 a->path = strdup(path);
990 if (!a->path) {
991 free(a);
992 return -ENOMEM;
993 }
994
995 LIST_PREPEND(device_allow, c->device_allow, a);
996 }
997
998 a->r = !!strchr(rwm, 'r');
999 a->w = !!strchr(rwm, 'w');
1000 a->m = !!strchr(rwm, 'm');
1001 }
1002
1003 n++;
1004 }
1005 if (r < 0)
1006 return r;
1007
1008 r = sd_bus_message_exit_container(message);
1009 if (r < 0)
1010 return r;
1011
1012 if (mode != UNIT_CHECK) {
1013 _cleanup_free_ char *buf = NULL;
1014 _cleanup_fclose_ FILE *f = NULL;
1015 CGroupDeviceAllow *a;
1016 size_t size = 0;
1017
1018 if (n == 0) {
1019 while (c->device_allow)
1020 cgroup_context_free_device_allow(c, c->device_allow);
1021 }
1022
1023 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
1024
1025 f = open_memstream(&buf, &size);
1026 if (!f)
1027 return -ENOMEM;
1028
1029 fputs("DeviceAllow=\n", f);
1030 LIST_FOREACH(device_allow, a, c->device_allow)
1031 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1032
1033 r = fflush_and_check(f);
1034 if (r < 0)
1035 return r;
1036 unit_write_drop_in_private(u, mode, name, buf);
1037 }
1038
1039 return 1;
1040
1041 } else if (streq(name, "TasksAccounting")) {
1042 int b;
1043
1044 r = sd_bus_message_read(message, "b", &b);
1045 if (r < 0)
1046 return r;
1047
1048 if (mode != UNIT_CHECK) {
1049 c->tasks_accounting = b;
1050 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1051 unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
1052 }
1053
1054 return 1;
1055
1056 } else if (streq(name, "TasksMax")) {
1057 uint64_t limit;
1058
1059 r = sd_bus_message_read(message, "t", &limit);
1060 if (r < 0)
1061 return r;
1062
1063 if (mode != UNIT_CHECK) {
1064 c->tasks_max = limit;
1065 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1066
1067 if (limit == (uint64_t) -1)
1068 unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
1069 else
1070 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
1071 }
1072
1073 return 1;
1074 }
1075
1076 if (u->transient && u->load_state == UNIT_STUB) {
1077 r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
1078 if (r != 0)
1079 return r;
1080
1081 }
1082
1083 return 0;
1084 }