]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-cgroup.c
Imported Upstream version 218
[systemd.git] / src / core / dbus-cgroup.c
CommitLineData
14228c0d
MB
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60f067b4 22#include "bus-util.h"
14228c0d 23#include "path-util.h"
60f067b4
JS
24#include "cgroup-util.h"
25#include "cgroup.h"
14228c0d
MB
26#include "dbus-cgroup.h"
27
60f067b4
JS
28static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
29
30static int property_get_blockio_device_weight(
31 sd_bus *bus,
32 const char *path,
33 const char *interface,
34 const char *property,
35 sd_bus_message *reply,
36 void *userdata,
37 sd_bus_error *error) {
14228c0d 38
60f067b4 39 CGroupContext *c = userdata;
14228c0d 40 CGroupBlockIODeviceWeight *w;
60f067b4 41 int r;
14228c0d 42
60f067b4
JS
43 assert(bus);
44 assert(reply);
14228c0d
MB
45 assert(c);
46
60f067b4
JS
47 r = sd_bus_message_open_container(reply, 'a', "(st)");
48 if (r < 0)
49 return r;
14228c0d
MB
50
51 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
60f067b4
JS
52 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
53 if (r < 0)
54 return r;
14228c0d
MB
55 }
56
60f067b4 57 return sd_bus_message_close_container(reply);
14228c0d
MB
58}
59
60f067b4
JS
60static int property_get_blockio_device_bandwidths(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
66 void *userdata,
67 sd_bus_error *error) {
68
69 CGroupContext *c = userdata;
14228c0d 70 CGroupBlockIODeviceBandwidth *b;
60f067b4 71 int r;
14228c0d 72
60f067b4
JS
73 assert(bus);
74 assert(reply);
14228c0d
MB
75 assert(c);
76
60f067b4
JS
77 r = sd_bus_message_open_container(reply, 'a', "(st)");
78 if (r < 0)
79 return r;
14228c0d
MB
80
81 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
82
83 if (streq(property, "BlockIOReadBandwidth") != b->read)
84 continue;
85
60f067b4
JS
86 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
87 if (r < 0)
88 return r;
14228c0d
MB
89 }
90
60f067b4 91 return sd_bus_message_close_container(reply);
14228c0d
MB
92}
93
60f067b4
JS
94static int property_get_device_allow(
95 sd_bus *bus,
96 const char *path,
97 const char *interface,
98 const char *property,
99 sd_bus_message *reply,
100 void *userdata,
101 sd_bus_error *error) {
102
103 CGroupContext *c = userdata;
14228c0d 104 CGroupDeviceAllow *a;
60f067b4 105 int r;
14228c0d 106
60f067b4
JS
107 assert(bus);
108 assert(reply);
14228c0d
MB
109 assert(c);
110
60f067b4
JS
111 r = sd_bus_message_open_container(reply, 'a', "(ss)");
112 if (r < 0)
113 return r;
14228c0d
MB
114
115 LIST_FOREACH(device_allow, a, c->device_allow) {
14228c0d 116 unsigned k = 0;
60f067b4 117 char rwm[4];
14228c0d
MB
118
119 if (a->r)
60f067b4 120 rwm[k++] = 'r';
14228c0d 121 if (a->w)
60f067b4 122 rwm[k++] = 'w';
14228c0d 123 if (a->m)
60f067b4 124 rwm[k++] = 'm';
14228c0d 125
60f067b4 126 rwm[k] = 0;
14228c0d 127
60f067b4
JS
128 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
129 if (r < 0)
130 return r;
14228c0d
MB
131 }
132
60f067b4
JS
133 return sd_bus_message_close_container(reply);
134}
135
60f067b4
JS
136static int property_get_ulong_as_u64(
137 sd_bus *bus,
138 const char *path,
139 const char *interface,
140 const char *property,
141 sd_bus_message *reply,
142 void *userdata,
143 sd_bus_error *error) {
144
145 unsigned long *ul = userdata;
146
147 assert(bus);
148 assert(reply);
149 assert(ul);
150
151 return sd_bus_message_append(reply, "t", *ul == (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul);
14228c0d
MB
152}
153
60f067b4
JS
154const sd_bus_vtable bus_cgroup_vtable[] = {
155 SD_BUS_VTABLE_START(0),
f47781d8 156 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
60f067b4
JS
157 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
158 SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0),
159 SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0),
5eef597e 160 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
60f067b4
JS
161 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
162 SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0),
163 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0),
164 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
165 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
166 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
167 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
168 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
169 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
170 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
171 SD_BUS_VTABLE_END
14228c0d
MB
172};
173
f47781d8
MP
174static int bus_cgroup_set_transient_property(
175 Unit *u,
176 CGroupContext *c,
177 const char *name,
178 sd_bus_message *message,
179 UnitSetPropertiesMode mode,
180 sd_bus_error *error) {
181
182 int r;
183
184 assert(u);
185 assert(c);
186 assert(name);
187 assert(message);
188
189 if (streq(name, "Delegate")) {
190 int b;
191
192 r = sd_bus_message_read(message, "b", &b);
193 if (r < 0)
194 return r;
195
196 if (mode != UNIT_CHECK) {
197 c->delegate = b;
198 unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
199 }
200
201 return 1;
202 }
203
204 return 0;
205}
206
14228c0d
MB
207int bus_cgroup_set_property(
208 Unit *u,
209 CGroupContext *c,
210 const char *name,
60f067b4 211 sd_bus_message *message,
14228c0d 212 UnitSetPropertiesMode mode,
60f067b4
JS
213 sd_bus_error *error) {
214
215 int r;
14228c0d 216
14228c0d
MB
217 assert(u);
218 assert(c);
60f067b4
JS
219 assert(name);
220 assert(message);
14228c0d
MB
221
222 if (streq(name, "CPUAccounting")) {
60f067b4 223 int b;
14228c0d 224
60f067b4
JS
225 r = sd_bus_message_read(message, "b", &b);
226 if (r < 0)
227 return r;
14228c0d
MB
228
229 if (mode != UNIT_CHECK) {
14228c0d 230 c->cpu_accounting = b;
60f067b4 231 u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
14228c0d
MB
232 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
233 }
234
235 return 1;
236
237 } else if (streq(name, "CPUShares")) {
238 uint64_t u64;
239 unsigned long ul;
240
60f067b4
JS
241 r = sd_bus_message_read(message, "t", &u64);
242 if (r < 0)
243 return r;
14228c0d 244
60f067b4
JS
245 if (u64 == (uint64_t) -1)
246 ul = (unsigned long) -1;
247 else {
248 ul = (unsigned long) u64;
249 if (ul <= 0 || (uint64_t) ul != u64)
250 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
251 }
14228c0d
MB
252
253 if (mode != UNIT_CHECK) {
254 c->cpu_shares = ul;
60f067b4 255 u->cgroup_realized_mask &= ~CGROUP_CPU;
14228c0d
MB
256 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
257 }
258
259 return 1;
260
60f067b4
JS
261 } else if (streq(name, "StartupCPUShares")) {
262 uint64_t u64;
263 unsigned long ul;
14228c0d 264
60f067b4
JS
265 r = sd_bus_message_read(message, "t", &u64);
266 if (r < 0)
267 return r;
268
269 if (u64 == (uint64_t) -1)
270 ul = (unsigned long) -1;
271 else {
272 ul = (unsigned long) u64;
273 if (ul <= 0 || (uint64_t) ul != u64)
274 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
275 }
276
277 if (mode != UNIT_CHECK) {
278 c->startup_cpu_shares = ul;
279 u->cgroup_realized_mask &= ~CGROUP_CPU;
280 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
281 }
282
283 return 1;
284
285 } else if (streq(name, "CPUQuotaPerSecUSec")) {
286 uint64_t u64;
287
288 r = sd_bus_message_read(message, "t", &u64);
289 if (r < 0)
290 return r;
291
292 if (u64 <= 0)
293 return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
14228c0d
MB
294
295 if (mode != UNIT_CHECK) {
60f067b4
JS
296 c->cpu_quota_per_sec_usec = u64;
297 u->cgroup_realized_mask &= ~CGROUP_CPU;
298 unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
299 }
300
301 return 1;
302
303 } else if (streq(name, "BlockIOAccounting")) {
304 int b;
305
306 r = sd_bus_message_read(message, "b", &b);
307 if (r < 0)
308 return r;
14228c0d 309
60f067b4 310 if (mode != UNIT_CHECK) {
14228c0d 311 c->blockio_accounting = b;
60f067b4 312 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
14228c0d
MB
313 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
314 }
315
316 return 1;
317
318 } else if (streq(name, "BlockIOWeight")) {
319 uint64_t u64;
320 unsigned long ul;
321
60f067b4
JS
322 r = sd_bus_message_read(message, "t", &u64);
323 if (r < 0)
324 return r;
14228c0d 325
60f067b4
JS
326 if (u64 == (uint64_t) -1)
327 ul = (unsigned long) -1;
328 else {
329 ul = (unsigned long) u64;
330 if (ul < 10 || ul > 1000)
331 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
332 }
14228c0d
MB
333
334 if (mode != UNIT_CHECK) {
335 c->blockio_weight = ul;
60f067b4 336 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
14228c0d
MB
337 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
338 }
339
340 return 1;
341
60f067b4
JS
342 } else if (streq(name, "StartupBlockIOWeight")) {
343 uint64_t u64;
344 unsigned long ul;
345
346 r = sd_bus_message_read(message, "t", &u64);
347 if (r < 0)
348 return r;
349
350 if (u64 == (uint64_t) -1)
351 ul = (unsigned long) -1;
352 else {
353 ul = (unsigned long) u64;
354 if (ul < 10 || ul > 1000)
355 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
356 }
357
358 if (mode != UNIT_CHECK) {
359 c->startup_blockio_weight = ul;
360 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
361 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
362 }
363
364 return 1;
365
14228c0d 366 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
60f067b4 367 const char *path;
14228c0d 368 bool read = true;
60f067b4
JS
369 unsigned n = 0;
370 uint64_t u64;
14228c0d
MB
371
372 if (streq(name, "BlockIOWriteBandwidth"))
373 read = false;
374
60f067b4
JS
375 r = sd_bus_message_enter_container(message, 'a', "(st)");
376 if (r < 0)
377 return r;
14228c0d 378
60f067b4 379 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
14228c0d
MB
380
381 if (mode != UNIT_CHECK) {
60f067b4 382 CGroupBlockIODeviceBandwidth *a = NULL, *b;
14228c0d
MB
383
384 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
385 if (path_equal(path, b->path) && read == b->read) {
386 a = b;
14228c0d
MB
387 break;
388 }
389 }
390
60f067b4 391 if (!a) {
14228c0d
MB
392 a = new0(CGroupBlockIODeviceBandwidth, 1);
393 if (!a)
394 return -ENOMEM;
395
396 a->read = read;
397 a->path = strdup(path);
398 if (!a->path) {
399 free(a);
400 return -ENOMEM;
401 }
60f067b4
JS
402
403 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
14228c0d
MB
404 }
405
406 a->bandwidth = u64;
14228c0d
MB
407 }
408
409 n++;
14228c0d 410 }
60f067b4
JS
411 if (r < 0)
412 return r;
413
414 r = sd_bus_message_exit_container(message);
415 if (r < 0)
416 return r;
14228c0d
MB
417
418 if (mode != UNIT_CHECK) {
60f067b4 419 CGroupBlockIODeviceBandwidth *a, *next;
14228c0d
MB
420 _cleanup_free_ char *buf = NULL;
421 _cleanup_fclose_ FILE *f = NULL;
14228c0d
MB
422 size_t size = 0;
423
424 if (n == 0) {
425 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
426 if (a->read == read)
427 cgroup_context_free_blockio_device_bandwidth(c, a);
428 }
429
60f067b4
JS
430 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
431
14228c0d
MB
432 f = open_memstream(&buf, &size);
433 if (!f)
434 return -ENOMEM;
435
436 if (read) {
437 fputs("BlockIOReadBandwidth=\n", f);
438 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
439 if (a->read)
440 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
441 } else {
442 fputs("BlockIOWriteBandwidth=\n", f);
443 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
444 if (!a->read)
445 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
446 }
447
448 fflush(f);
449 unit_write_drop_in_private(u, mode, name, buf);
450 }
451
452 return 1;
453
454 } else if (streq(name, "BlockIODeviceWeight")) {
60f067b4
JS
455 const char *path;
456 uint64_t u64;
14228c0d
MB
457 unsigned n = 0;
458
60f067b4
JS
459 r = sd_bus_message_enter_container(message, 'a', "(st)");
460 if (r < 0)
461 return r;
14228c0d 462
60f067b4
JS
463 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
464 unsigned long ul = u64;
14228c0d 465
14228c0d 466 if (ul < 10 || ul > 1000)
60f067b4 467 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
14228c0d
MB
468
469 if (mode != UNIT_CHECK) {
60f067b4 470 CGroupBlockIODeviceWeight *a = NULL, *b;
14228c0d
MB
471
472 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
473 if (path_equal(b->path, path)) {
474 a = b;
14228c0d
MB
475 break;
476 }
477 }
478
60f067b4 479 if (!a) {
14228c0d
MB
480 a = new0(CGroupBlockIODeviceWeight, 1);
481 if (!a)
482 return -ENOMEM;
483
484 a->path = strdup(path);
485 if (!a->path) {
486 free(a);
487 return -ENOMEM;
488 }
60f067b4 489 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
14228c0d
MB
490 }
491
492 a->weight = ul;
14228c0d
MB
493 }
494
495 n++;
14228c0d
MB
496 }
497
60f067b4
JS
498 r = sd_bus_message_exit_container(message);
499 if (r < 0)
500 return r;
501
14228c0d
MB
502 if (mode != UNIT_CHECK) {
503 _cleanup_free_ char *buf = NULL;
504 _cleanup_fclose_ FILE *f = NULL;
505 CGroupBlockIODeviceWeight *a;
506 size_t size = 0;
507
508 if (n == 0) {
509 while (c->blockio_device_weights)
510 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
511 }
512
60f067b4
JS
513 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
514
14228c0d
MB
515 f = open_memstream(&buf, &size);
516 if (!f)
517 return -ENOMEM;
518
519 fputs("BlockIODeviceWeight=\n", f);
520 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
521 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
522
523 fflush(f);
524 unit_write_drop_in_private(u, mode, name, buf);
525 }
526
527 return 1;
528
529 } else if (streq(name, "MemoryAccounting")) {
60f067b4 530 int b;
14228c0d 531
60f067b4
JS
532 r = sd_bus_message_read(message, "b", &b);
533 if (r < 0)
534 return r;
14228c0d
MB
535
536 if (mode != UNIT_CHECK) {
14228c0d 537 c->memory_accounting = b;
60f067b4 538 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
14228c0d
MB
539 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
540 }
541
542 return 1;
543
544 } else if (streq(name, "MemoryLimit")) {
60f067b4 545 uint64_t limit;
14228c0d 546
60f067b4
JS
547 r = sd_bus_message_read(message, "t", &limit);
548 if (r < 0)
549 return r;
14228c0d
MB
550
551 if (mode != UNIT_CHECK) {
14228c0d 552 c->memory_limit = limit;
60f067b4 553 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
14228c0d
MB
554 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
555 }
556
557 return 1;
558
559 } else if (streq(name, "DevicePolicy")) {
560 const char *policy;
561 CGroupDevicePolicy p;
562
60f067b4
JS
563 r = sd_bus_message_read(message, "s", &policy);
564 if (r < 0)
565 return r;
14228c0d 566
14228c0d
MB
567 p = cgroup_device_policy_from_string(policy);
568 if (p < 0)
569 return -EINVAL;
570
571 if (mode != UNIT_CHECK) {
572 char *buf;
573
574 c->device_policy = p;
60f067b4 575 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
14228c0d
MB
576
577 buf = strappenda("DevicePolicy=", policy);
578 unit_write_drop_in_private(u, mode, name, buf);
579 }
580
581 return 1;
582
583 } else if (streq(name, "DeviceAllow")) {
60f067b4 584 const char *path, *rwm;
14228c0d
MB
585 unsigned n = 0;
586
60f067b4
JS
587 r = sd_bus_message_enter_container(message, 'a', "(ss)");
588 if (r < 0)
589 return r;
14228c0d 590
60f067b4 591 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
14228c0d 592
60f067b4
JS
593 if ((!startswith(path, "/dev/") &&
594 !startswith(path, "block-") &&
595 !startswith(path, "char-")) ||
596 strpbrk(path, WHITESPACE))
597 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
14228c0d
MB
598
599 if (isempty(rwm))
600 rwm = "rwm";
601
60f067b4
JS
602 if (!in_charset(rwm, "rwm"))
603 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
14228c0d
MB
604
605 if (mode != UNIT_CHECK) {
60f067b4 606 CGroupDeviceAllow *a = NULL, *b;
14228c0d
MB
607
608 LIST_FOREACH(device_allow, b, c->device_allow) {
609 if (path_equal(b->path, path)) {
610 a = b;
14228c0d
MB
611 break;
612 }
613 }
614
60f067b4 615 if (!a) {
14228c0d
MB
616 a = new0(CGroupDeviceAllow, 1);
617 if (!a)
618 return -ENOMEM;
619
620 a->path = strdup(path);
621 if (!a->path) {
622 free(a);
623 return -ENOMEM;
624 }
60f067b4
JS
625
626 LIST_PREPEND(device_allow, c->device_allow, a);
14228c0d
MB
627 }
628
629 a->r = !!strchr(rwm, 'r');
630 a->w = !!strchr(rwm, 'w');
631 a->m = !!strchr(rwm, 'm');
14228c0d
MB
632 }
633
634 n++;
14228c0d 635 }
60f067b4
JS
636 if (r < 0)
637 return r;
638
639 r = sd_bus_message_exit_container(message);
640 if (r < 0)
641 return r;
14228c0d
MB
642
643 if (mode != UNIT_CHECK) {
644 _cleanup_free_ char *buf = NULL;
645 _cleanup_fclose_ FILE *f = NULL;
646 CGroupDeviceAllow *a;
647 size_t size = 0;
648
649 if (n == 0) {
650 while (c->device_allow)
651 cgroup_context_free_device_allow(c, c->device_allow);
652 }
653
60f067b4
JS
654 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
655
14228c0d
MB
656 f = open_memstream(&buf, &size);
657 if (!f)
658 return -ENOMEM;
659
660 fputs("DeviceAllow=\n", f);
661 LIST_FOREACH(device_allow, a, c->device_allow)
662 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
663
664 fflush(f);
665 unit_write_drop_in_private(u, mode, name, buf);
666 }
667
668 return 1;
f47781d8
MP
669
670 }
671
672 if (u->transient && u->load_state == UNIT_STUB) {
673 r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
674 if (r != 0)
675 return r;
676
14228c0d
MB
677 }
678
679 return 0;
680}