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