]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
core: unified cgroup hierarchy support
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
4ad49000
LP
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
718db961 22#include "bus-util.h"
7041efe9 23#include "path-util.h"
718db961
LP
24#include "cgroup-util.h"
25#include "cgroup.h"
4ad49000
LP
26#include "dbus-cgroup.h"
27
718db961
LP
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,
ebcf1f97
LP
36 void *userdata,
37 sd_bus_error *error) {
4ad49000 38
718db961 39 CGroupContext *c = userdata;
4ad49000 40 CGroupBlockIODeviceWeight *w;
718db961 41 int r;
4ad49000 42
718db961
LP
43 assert(bus);
44 assert(reply);
4ad49000
LP
45 assert(c);
46
718db961
LP
47 r = sd_bus_message_open_container(reply, 'a', "(st)");
48 if (r < 0)
49 return r;
4ad49000
LP
50
51 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
718db961
LP
52 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
53 if (r < 0)
54 return r;
4ad49000
LP
55 }
56
718db961 57 return sd_bus_message_close_container(reply);
4ad49000
LP
58}
59
718db961
LP
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,
ebcf1f97
LP
66 void *userdata,
67 sd_bus_error *error) {
718db961
LP
68
69 CGroupContext *c = userdata;
4ad49000 70 CGroupBlockIODeviceBandwidth *b;
718db961 71 int r;
4ad49000 72
718db961
LP
73 assert(bus);
74 assert(reply);
4ad49000
LP
75 assert(c);
76
718db961
LP
77 r = sd_bus_message_open_container(reply, 'a', "(st)");
78 if (r < 0)
79 return r;
4ad49000
LP
80
81 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
82
83 if (streq(property, "BlockIOReadBandwidth") != b->read)
84 continue;
85
718db961
LP
86 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
87 if (r < 0)
88 return r;
4ad49000
LP
89 }
90
718db961 91 return sd_bus_message_close_container(reply);
4ad49000
LP
92}
93
718db961
LP
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,
ebcf1f97
LP
100 void *userdata,
101 sd_bus_error *error) {
718db961
LP
102
103 CGroupContext *c = userdata;
4ad49000 104 CGroupDeviceAllow *a;
718db961 105 int r;
4ad49000 106
718db961
LP
107 assert(bus);
108 assert(reply);
4ad49000
LP
109 assert(c);
110
718db961
LP
111 r = sd_bus_message_open_container(reply, 'a', "(ss)");
112 if (r < 0)
113 return r;
4ad49000
LP
114
115 LIST_FOREACH(device_allow, a, c->device_allow) {
4ad49000 116 unsigned k = 0;
718db961 117 char rwm[4];
4ad49000
LP
118
119 if (a->r)
718db961 120 rwm[k++] = 'r';
4ad49000 121 if (a->w)
718db961 122 rwm[k++] = 'w';
4ad49000 123 if (a->m)
718db961 124 rwm[k++] = 'm';
4ad49000 125
718db961 126 rwm[k] = 0;
4ad49000 127
718db961
LP
128 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
129 if (r < 0)
130 return r;
4ad49000
LP
131 }
132
718db961 133 return sd_bus_message_close_container(reply);
4ad49000
LP
134}
135
db785129
LP
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);
152}
153
718db961
LP
154const sd_bus_vtable bus_cgroup_vtable[] = {
155 SD_BUS_VTABLE_START(0),
a931ad47 156 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
610f780c 157 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
db785129
LP
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),
ee26bcc0 160 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
610f780c 161 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
db785129
LP
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),
610f780c
LP
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),
718db961 171 SD_BUS_VTABLE_END
4ad49000 172};
8e2af478 173
a931ad47
LP
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
8e2af478
LP
207int bus_cgroup_set_property(
208 Unit *u,
209 CGroupContext *c,
210 const char *name,
718db961 211 sd_bus_message *message,
8e2af478 212 UnitSetPropertiesMode mode,
718db961
LP
213 sd_bus_error *error) {
214
215 int r;
8e2af478 216
8e2af478
LP
217 assert(u);
218 assert(c);
718db961
LP
219 assert(name);
220 assert(message);
8e2af478
LP
221
222 if (streq(name, "CPUAccounting")) {
718db961 223 int b;
8e2af478 224
718db961
LP
225 r = sd_bus_message_read(message, "b", &b);
226 if (r < 0)
227 return r;
8e2af478
LP
228
229 if (mode != UNIT_CHECK) {
8e2af478 230 c->cpu_accounting = b;
efdb0237 231 u->cgroup_realized_mask &= ~CGROUP_MASK_CPUACCT;
b9ec9359 232 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
b42defe3
LP
233 }
234
235 return 1;
236
237 } else if (streq(name, "CPUShares")) {
238 uint64_t u64;
239 unsigned long ul;
240
718db961
LP
241 r = sd_bus_message_read(message, "t", &u64);
242 if (r < 0)
243 return r;
b42defe3 244
db785129
LP
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 }
b42defe3
LP
252
253 if (mode != UNIT_CHECK) {
b42defe3 254 c->cpu_shares = ul;
efdb0237 255 u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
b9ec9359 256 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
8e2af478
LP
257 }
258
259 return 1;
260
95ae05c0
WC
261 } else if (streq(name, "StartupCPUShares")) {
262 uint64_t u64;
263 unsigned long ul;
264
265 r = sd_bus_message_read(message, "t", &u64);
266 if (r < 0)
267 return r;
268
db785129
LP
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 }
95ae05c0
WC
276
277 if (mode != UNIT_CHECK) {
278 c->startup_cpu_shares = ul;
efdb0237 279 u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
95ae05c0
WC
280 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
281 }
282
283 return 1;
284
b2f8b02e
LP
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");
294
295 if (mode != UNIT_CHECK) {
296 c->cpu_quota_per_sec_usec = u64;
efdb0237 297 u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
b2f8b02e
LP
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
8e2af478 303 } else if (streq(name, "BlockIOAccounting")) {
718db961 304 int b;
8e2af478 305
718db961
LP
306 r = sd_bus_message_read(message, "b", &b);
307 if (r < 0)
308 return r;
8e2af478
LP
309
310 if (mode != UNIT_CHECK) {
8e2af478 311 c->blockio_accounting = b;
efdb0237 312 u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
b9ec9359 313 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
314 }
315
316 return 1;
b42defe3
LP
317
318 } else if (streq(name, "BlockIOWeight")) {
319 uint64_t u64;
320 unsigned long ul;
321
718db961
LP
322 r = sd_bus_message_read(message, "t", &u64);
323 if (r < 0)
324 return r;
b42defe3 325
db785129
LP
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 }
b42defe3
LP
333
334 if (mode != UNIT_CHECK) {
f2369103 335 c->blockio_weight = ul;
efdb0237 336 u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
b9ec9359 337 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
b42defe3
LP
338 }
339
340 return 1;
95ae05c0
WC
341
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
db785129
LP
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 }
95ae05c0
WC
357
358 if (mode != UNIT_CHECK) {
359 c->startup_blockio_weight = ul;
efdb0237 360 u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
95ae05c0
WC
361 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
362 }
363
364 return 1;
b42defe3 365
f004c2ca 366 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
718db961 367 const char *path;
f004c2ca 368 bool read = true;
718db961
LP
369 unsigned n = 0;
370 uint64_t u64;
f004c2ca
G
371
372 if (streq(name, "BlockIOWriteBandwidth"))
373 read = false;
374
718db961
LP
375 r = sd_bus_message_enter_container(message, 'a', "(st)");
376 if (r < 0)
377 return r;
f004c2ca 378
718db961 379 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca
G
380
381 if (mode != UNIT_CHECK) {
718db961 382 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
383
384 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
385 if (path_equal(path, b->path) && read == b->read) {
386 a = b;
f004c2ca
G
387 break;
388 }
389 }
390
718db961 391 if (!a) {
f004c2ca
G
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 }
718db961
LP
402
403 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
404 }
405
406 a->bandwidth = u64;
f004c2ca
G
407 }
408
409 n++;
f004c2ca 410 }
718db961
LP
411 if (r < 0)
412 return r;
f004c2ca 413
9c96019d
LP
414 r = sd_bus_message_exit_container(message);
415 if (r < 0)
416 return r;
417
f004c2ca 418 if (mode != UNIT_CHECK) {
718db961 419 CGroupBlockIODeviceBandwidth *a, *next;
f004c2ca
G
420 _cleanup_free_ char *buf = NULL;
421 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
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
efdb0237 430 u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
3051f187 431
f004c2ca
G
432 f = open_memstream(&buf, &size);
433 if (!f)
434 return -ENOMEM;
435
7d6884b6 436 if (read) {
f004c2ca 437 fputs("BlockIOReadBandwidth=\n", f);
7d6884b6 438 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
f004c2ca
G
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
6f68ecb4
G
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")) {
718db961
LP
455 const char *path;
456 uint64_t u64;
6f68ecb4
G
457 unsigned n = 0;
458
718db961
LP
459 r = sd_bus_message_enter_container(message, 'a', "(st)");
460 if (r < 0)
461 return r;
6f68ecb4 462
ccd06097
ZJS
463 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
464 unsigned long ul = u64;
6f68ecb4 465
6f68ecb4 466 if (ul < 10 || ul > 1000)
718db961 467 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
6f68ecb4
G
468
469 if (mode != UNIT_CHECK) {
718db961 470 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
471
472 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
473 if (path_equal(b->path, path)) {
474 a = b;
6f68ecb4
G
475 break;
476 }
477 }
478
718db961 479 if (!a) {
6f68ecb4
G
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 }
718db961 489 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
490 }
491
492 a->weight = ul;
6f68ecb4
G
493 }
494
495 n++;
6f68ecb4
G
496 }
497
9c96019d
LP
498 r = sd_bus_message_exit_container(message);
499 if (r < 0)
500 return r;
501
6f68ecb4
G
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
efdb0237 513 u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
3051f187 514
6f68ecb4
G
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
f004c2ca
G
523 fflush(f);
524 unit_write_drop_in_private(u, mode, name, buf);
525 }
526
527 return 1;
528
8e2af478 529 } else if (streq(name, "MemoryAccounting")) {
718db961 530 int b;
8e2af478 531
718db961
LP
532 r = sd_bus_message_read(message, "b", &b);
533 if (r < 0)
534 return r;
8e2af478
LP
535
536 if (mode != UNIT_CHECK) {
b42defe3 537 c->memory_accounting = b;
efdb0237 538 u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
b9ec9359 539 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
540 }
541
542 return 1;
8e2af478 543
ddca82ac 544 } else if (streq(name, "MemoryLimit")) {
718db961 545 uint64_t limit;
b42defe3 546
718db961
LP
547 r = sd_bus_message_read(message, "t", &limit);
548 if (r < 0)
549 return r;
b42defe3
LP
550
551 if (mode != UNIT_CHECK) {
ddca82ac 552 c->memory_limit = limit;
efdb0237 553 u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
b9ec9359 554 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
b42defe3
LP
555 }
556
7041efe9
LP
557 return 1;
558
559 } else if (streq(name, "DevicePolicy")) {
560 const char *policy;
561 CGroupDevicePolicy p;
562
718db961
LP
563 r = sd_bus_message_read(message, "s", &policy);
564 if (r < 0)
565 return r;
7041efe9 566
7041efe9
LP
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;
efdb0237 575 u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICE;
7041efe9 576
63c372cb 577 buf = strjoina("DevicePolicy=", policy);
b9ec9359 578 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
579 }
580
581 return 1;
582
583 } else if (streq(name, "DeviceAllow")) {
718db961 584 const char *path, *rwm;
7041efe9
LP
585 unsigned n = 0;
586
718db961
LP
587 r = sd_bus_message_enter_container(message, 'a', "(ss)");
588 if (r < 0)
589 return r;
7041efe9 590
718db961 591 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 592
90060676
LP
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");
7041efe9
LP
598
599 if (isempty(rwm))
600 rwm = "rwm";
601
718db961
LP
602 if (!in_charset(rwm, "rwm"))
603 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
7041efe9 604
7041efe9 605 if (mode != UNIT_CHECK) {
718db961 606 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
607
608 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 609 if (path_equal(b->path, path)) {
ad7bfffd 610 a = b;
ad7bfffd
G
611 break;
612 }
613 }
614
718db961 615 if (!a) {
ad7bfffd
G
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 }
718db961
LP
625
626 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
627 }
628
629 a->r = !!strchr(rwm, 'r');
630 a->w = !!strchr(rwm, 'w');
631 a->m = !!strchr(rwm, 'm');
7041efe9
LP
632 }
633
c2756a68 634 n++;
7041efe9 635 }
43a99a7a
LP
636 if (r < 0)
637 return r;
7041efe9 638
9c96019d
LP
639 r = sd_bus_message_exit_container(message);
640 if (r < 0)
641 return r;
642
7041efe9
LP
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
efdb0237 654 u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICE;
3051f187 655
7041efe9
LP
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);
b9ec9359 665 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
666 }
667
b42defe3 668 return 1;
a931ad47
LP
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
b42defe3 677 }
8e2af478
LP
678
679 return 0;
680}