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