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