]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
Merge pull request #3329 from htejun/dbus-cgroup-fixes
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
4ad49000
LP
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
b5efdb8a 20#include "alloc-util.h"
718db961 21#include "bus-util.h"
718db961
LP
22#include "cgroup-util.h"
23#include "cgroup.h"
4ad49000 24#include "dbus-cgroup.h"
3ffd4af2 25#include "fd-util.h"
0d39fa9c 26#include "fileio.h"
3ffd4af2 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
13c31542
TH
31static 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
61static 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) {
9be57249 83 CGroupIOLimitType type;
13c31542 84
9be57249
TH
85 type = cgroup_io_limit_type_from_string(property);
86 if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
13c31542
TH
87 continue;
88
9be57249 89 r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
13c31542
TH
90 if (r < 0)
91 return r;
92 }
93
94 return sd_bus_message_close_container(reply);
95}
96
718db961
LP
97static 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,
ebcf1f97
LP
103 void *userdata,
104 sd_bus_error *error) {
4ad49000 105
718db961 106 CGroupContext *c = userdata;
4ad49000 107 CGroupBlockIODeviceWeight *w;
718db961 108 int r;
4ad49000 109
718db961
LP
110 assert(bus);
111 assert(reply);
4ad49000
LP
112 assert(c);
113
718db961
LP
114 r = sd_bus_message_open_container(reply, 'a', "(st)");
115 if (r < 0)
116 return r;
4ad49000
LP
117
118 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
718db961
LP
119 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
120 if (r < 0)
121 return r;
4ad49000
LP
122 }
123
718db961 124 return sd_bus_message_close_container(reply);
4ad49000
LP
125}
126
718db961
LP
127static 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,
ebcf1f97
LP
133 void *userdata,
134 sd_bus_error *error) {
718db961
LP
135
136 CGroupContext *c = userdata;
4ad49000 137 CGroupBlockIODeviceBandwidth *b;
718db961 138 int r;
4ad49000 139
718db961
LP
140 assert(bus);
141 assert(reply);
4ad49000
LP
142 assert(c);
143
718db961
LP
144 r = sd_bus_message_open_container(reply, 'a', "(st)");
145 if (r < 0)
146 return r;
4ad49000
LP
147
148 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
979d0311 149 uint64_t v;
4ad49000 150
979d0311
TH
151 if (streq(property, "BlockIOReadBandwidth"))
152 v = b->rbps;
153 else
154 v = b->wbps;
155
156 if (v == CGROUP_LIMIT_MAX)
4ad49000
LP
157 continue;
158
979d0311 159 r = sd_bus_message_append(reply, "(st)", b->path, v);
718db961
LP
160 if (r < 0)
161 return r;
4ad49000
LP
162 }
163
718db961 164 return sd_bus_message_close_container(reply);
4ad49000
LP
165}
166
718db961
LP
167static 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,
ebcf1f97
LP
173 void *userdata,
174 sd_bus_error *error) {
718db961
LP
175
176 CGroupContext *c = userdata;
4ad49000 177 CGroupDeviceAllow *a;
718db961 178 int r;
4ad49000 179
718db961
LP
180 assert(bus);
181 assert(reply);
4ad49000
LP
182 assert(c);
183
718db961
LP
184 r = sd_bus_message_open_container(reply, 'a', "(ss)");
185 if (r < 0)
186 return r;
4ad49000
LP
187
188 LIST_FOREACH(device_allow, a, c->device_allow) {
4ad49000 189 unsigned k = 0;
718db961 190 char rwm[4];
4ad49000
LP
191
192 if (a->r)
718db961 193 rwm[k++] = 'r';
4ad49000 194 if (a->w)
718db961 195 rwm[k++] = 'w';
4ad49000 196 if (a->m)
718db961 197 rwm[k++] = 'm';
4ad49000 198
718db961 199 rwm[k] = 0;
4ad49000 200
718db961
LP
201 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
202 if (r < 0)
203 return r;
4ad49000
LP
204 }
205
718db961 206 return sd_bus_message_close_container(reply);
4ad49000
LP
207}
208
718db961
LP
209const sd_bus_vtable bus_cgroup_vtable[] = {
210 SD_BUS_VTABLE_START(0),
a931ad47 211 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
610f780c 212 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
d53d9474
LP
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),
ee26bcc0 215 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
13c31542
TH
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),
ac06a0cf
TH
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),
610f780c 224 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
d53d9474
LP
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),
610f780c
LP
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),
03a7b521
LP
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),
718db961 236 SD_BUS_VTABLE_END
4ad49000 237};
8e2af478 238
a931ad47
LP
239static 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;
0c2d96f5 263 unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes\n" : "Delegate=no\n");
a931ad47
LP
264 }
265
266 return 1;
267 }
268
269 return 0;
270}
271
8e2af478
LP
272int bus_cgroup_set_property(
273 Unit *u,
274 CGroupContext *c,
275 const char *name,
718db961 276 sd_bus_message *message,
8e2af478 277 UnitSetPropertiesMode mode,
718db961
LP
278 sd_bus_error *error) {
279
9be57249 280 CGroupIOLimitType iol_type;
718db961 281 int r;
8e2af478 282
8e2af478
LP
283 assert(u);
284 assert(c);
718db961
LP
285 assert(name);
286 assert(message);
8e2af478
LP
287
288 if (streq(name, "CPUAccounting")) {
718db961 289 int b;
8e2af478 290
718db961
LP
291 r = sd_bus_message_read(message, "b", &b);
292 if (r < 0)
293 return r;
8e2af478
LP
294
295 if (mode != UNIT_CHECK) {
8e2af478 296 c->cpu_accounting = b;
e7ab4d1a 297 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
0c2d96f5 298 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes\n" : "CPUAccounting=no\n");
b42defe3
LP
299 }
300
301 return 1;
302
303 } else if (streq(name, "CPUShares")) {
d53d9474 304 uint64_t shares;
b42defe3 305
d53d9474 306 r = sd_bus_message_read(message, "t", &shares);
718db961
LP
307 if (r < 0)
308 return r;
b42defe3 309
d53d9474
LP
310 if (!CGROUP_CPU_SHARES_IS_OK(shares))
311 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
b42defe3
LP
312
313 if (mode != UNIT_CHECK) {
d53d9474 314 c->cpu_shares = shares;
e7ab4d1a 315 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
316
317 if (shares == CGROUP_CPU_SHARES_INVALID)
0c2d96f5 318 unit_write_drop_in_private(u, mode, name, "CPUShares=\n");
d53d9474 319 else
0c2d96f5 320 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64 "\n", shares);
8e2af478
LP
321 }
322
323 return 1;
324
95ae05c0 325 } else if (streq(name, "StartupCPUShares")) {
d53d9474 326 uint64_t shares;
95ae05c0 327
d53d9474 328 r = sd_bus_message_read(message, "t", &shares);
95ae05c0
WC
329 if (r < 0)
330 return r;
331
d53d9474
LP
332 if (!CGROUP_CPU_SHARES_IS_OK(shares))
333 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
95ae05c0
WC
334
335 if (mode != UNIT_CHECK) {
d53d9474 336 c->startup_cpu_shares = shares;
e7ab4d1a 337 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
d53d9474
LP
338
339 if (shares == CGROUP_CPU_SHARES_INVALID)
0c2d96f5 340 unit_write_drop_in_private(u, mode, name, "StartupCPUShares=\n");
d53d9474 341 else
0c2d96f5 342 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64 "\n", shares);
95ae05c0
WC
343 }
344
345 return 1;
346
b2f8b02e
LP
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;
e7ab4d1a 359 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
0c2d96f5 360 unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%\n", (double) (c->cpu_quota_per_sec_usec / 10000));
b2f8b02e
LP
361 }
362
363 return 1;
364
13c31542
TH
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);
0c2d96f5 375 unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes\n" : "IOAccounting=no\n");
13c31542
TH
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)
0c2d96f5 395 unit_write_drop_in_private(u, mode, name, "IOWeight=\n");
13c31542 396 else
0c2d96f5 397 unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64 "\n", weight);
13c31542
TH
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)
0c2d96f5 417 unit_write_drop_in_private(u, mode, name, "StartupIOWeight=\n");
13c31542 418 else
0c2d96f5 419 unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64 "\n", weight);
13c31542
TH
420 }
421
422 return 1;
423
9be57249 424 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
13c31542 425 const char *path;
13c31542
TH
426 unsigned n = 0;
427 uint64_t u64;
428
13c31542
TH
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) {
9be57249
TH
446 CGroupIOLimitType type;
447
13c31542
TH
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
9be57249
TH
458 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
459 a->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
460
461 LIST_PREPEND(device_limits, c->io_device_limits, a);
462 }
463
9be57249 464 a->limits[iol_type] = u64;
13c31542
TH
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)
9be57249 484 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
13c31542
TH
485 }
486
487 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
488
489 f = open_memstream(&buf, &size);
490 if (!f)
491 return -ENOMEM;
492
9be57249
TH
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]);
13c31542
TH
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
8e2af478 582 } else if (streq(name, "BlockIOAccounting")) {
718db961 583 int b;
8e2af478 584
718db961
LP
585 r = sd_bus_message_read(message, "b", &b);
586 if (r < 0)
587 return r;
8e2af478
LP
588
589 if (mode != UNIT_CHECK) {
8e2af478 590 c->blockio_accounting = b;
e7ab4d1a 591 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
0c2d96f5 592 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes\n" : "BlockIOAccounting=no\n");
8e2af478
LP
593 }
594
595 return 1;
b42defe3
LP
596
597 } else if (streq(name, "BlockIOWeight")) {
d53d9474 598 uint64_t weight;
b42defe3 599
d53d9474 600 r = sd_bus_message_read(message, "t", &weight);
718db961
LP
601 if (r < 0)
602 return r;
b42defe3 603
d53d9474
LP
604 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
605 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
b42defe3
LP
606
607 if (mode != UNIT_CHECK) {
d53d9474 608 c->blockio_weight = weight;
e7ab4d1a 609 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
610
611 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
0c2d96f5 612 unit_write_drop_in_private(u, mode, name, "BlockIOWeight=\n");
d53d9474 613 else
0c2d96f5 614 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64 "\n", weight);
b42defe3
LP
615 }
616
617 return 1;
95ae05c0
WC
618
619 } else if (streq(name, "StartupBlockIOWeight")) {
d53d9474 620 uint64_t weight;
95ae05c0 621
d53d9474 622 r = sd_bus_message_read(message, "t", &weight);
95ae05c0
WC
623 if (r < 0)
624 return r;
625
6fb09269 626 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
d53d9474 627 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
95ae05c0
WC
628
629 if (mode != UNIT_CHECK) {
d53d9474 630 c->startup_blockio_weight = weight;
e7ab4d1a 631 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
d53d9474
LP
632
633 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
0c2d96f5 634 unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=\n");
d53d9474 635 else
0c2d96f5 636 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64 "\n", weight);
95ae05c0
WC
637 }
638
639 return 1;
b42defe3 640
f004c2ca 641 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
718db961 642 const char *path;
f004c2ca 643 bool read = true;
718db961
LP
644 unsigned n = 0;
645 uint64_t u64;
f004c2ca
G
646
647 if (streq(name, "BlockIOWriteBandwidth"))
648 read = false;
649
718db961
LP
650 r = sd_bus_message_enter_container(message, 'a', "(st)");
651 if (r < 0)
652 return r;
f004c2ca 653
718db961 654 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca
G
655
656 if (mode != UNIT_CHECK) {
718db961 657 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
658
659 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
979d0311 660 if (path_equal(path, b->path)) {
f004c2ca 661 a = b;
f004c2ca
G
662 break;
663 }
664 }
665
718db961 666 if (!a) {
f004c2ca
G
667 a = new0(CGroupBlockIODeviceBandwidth, 1);
668 if (!a)
669 return -ENOMEM;
670
979d0311
TH
671 a->rbps = CGROUP_LIMIT_MAX;
672 a->wbps = CGROUP_LIMIT_MAX;
f004c2ca
G
673 a->path = strdup(path);
674 if (!a->path) {
675 free(a);
676 return -ENOMEM;
677 }
718db961
LP
678
679 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
680 }
681
979d0311
TH
682 if (read)
683 a->rbps = u64;
684 else
685 a->wbps = u64;
f004c2ca
G
686 }
687
688 n++;
f004c2ca 689 }
718db961
LP
690 if (r < 0)
691 return r;
f004c2ca 692
9c96019d
LP
693 r = sd_bus_message_exit_container(message);
694 if (r < 0)
695 return r;
696
f004c2ca 697 if (mode != UNIT_CHECK) {
979d0311 698 CGroupBlockIODeviceBandwidth *a;
f004c2ca
G
699 _cleanup_free_ char *buf = NULL;
700 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
701 size_t size = 0;
702
703 if (n == 0) {
979d0311
TH
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 }
f004c2ca
G
710 }
711
e7ab4d1a 712 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 713
f004c2ca
G
714 f = open_memstream(&buf, &size);
715 if (!f)
716 return -ENOMEM;
717
7d6884b6 718 if (read) {
f004c2ca 719 fputs("BlockIOReadBandwidth=\n", f);
7d6884b6 720 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
721 if (a->rbps != CGROUP_LIMIT_MAX)
722 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
f004c2ca
G
723 } else {
724 fputs("BlockIOWriteBandwidth=\n", f);
725 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
979d0311
TH
726 if (a->wbps != CGROUP_LIMIT_MAX)
727 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
f004c2ca
G
728 }
729
1f2f874c
NC
730 r = fflush_and_check(f);
731 if (r < 0)
732 return r;
6f68ecb4
G
733 unit_write_drop_in_private(u, mode, name, buf);
734 }
735
736 return 1;
737
738 } else if (streq(name, "BlockIODeviceWeight")) {
718db961 739 const char *path;
d53d9474 740 uint64_t weight;
6f68ecb4
G
741 unsigned n = 0;
742
718db961
LP
743 r = sd_bus_message_enter_container(message, 'a', "(st)");
744 if (r < 0)
745 return r;
6f68ecb4 746
d53d9474 747 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
6f68ecb4 748
d53d9474 749 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
718db961 750 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
6f68ecb4
G
751
752 if (mode != UNIT_CHECK) {
718db961 753 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
754
755 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
756 if (path_equal(b->path, path)) {
757 a = b;
6f68ecb4
G
758 break;
759 }
760 }
761
718db961 762 if (!a) {
6f68ecb4
G
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 }
718db961 772 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
773 }
774
d53d9474 775 a->weight = weight;
6f68ecb4
G
776 }
777
778 n++;
6f68ecb4
G
779 }
780
9c96019d
LP
781 r = sd_bus_message_exit_container(message);
782 if (r < 0)
783 return r;
784
6f68ecb4
G
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
e7ab4d1a 796 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
3051f187 797
6f68ecb4
G
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)
d53d9474 804 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
6f68ecb4 805
1f2f874c
NC
806 r = fflush_and_check(f);
807 if (r < 0)
808 return r;
f004c2ca
G
809 unit_write_drop_in_private(u, mode, name, buf);
810 }
811
812 return 1;
813
8e2af478 814 } else if (streq(name, "MemoryAccounting")) {
718db961 815 int b;
8e2af478 816
718db961
LP
817 r = sd_bus_message_read(message, "b", &b);
818 if (r < 0)
819 return r;
8e2af478
LP
820
821 if (mode != UNIT_CHECK) {
b42defe3 822 c->memory_accounting = b;
e7ab4d1a 823 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
0c2d96f5 824 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes\n" : "MemoryAccounting=no\n");
8e2af478
LP
825 }
826
827 return 1;
8e2af478 828
ddca82ac 829 } else if (streq(name, "MemoryLimit")) {
718db961 830 uint64_t limit;
b42defe3 831
718db961
LP
832 r = sd_bus_message_read(message, "t", &limit);
833 if (r < 0)
834 return r;
b42defe3
LP
835
836 if (mode != UNIT_CHECK) {
ddca82ac 837 c->memory_limit = limit;
e7ab4d1a 838 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
03a7b521
LP
839
840 if (limit == (uint64_t) -1)
0c2d96f5 841 unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity\n");
03a7b521 842 else
0c2d96f5 843 unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64 "\n", limit);
b42defe3
LP
844 }
845
7041efe9
LP
846 return 1;
847
848 } else if (streq(name, "DevicePolicy")) {
849 const char *policy;
850 CGroupDevicePolicy p;
851
718db961
LP
852 r = sd_bus_message_read(message, "s", &policy);
853 if (r < 0)
854 return r;
7041efe9 855
7041efe9
LP
856 p = cgroup_device_policy_from_string(policy);
857 if (p < 0)
858 return -EINVAL;
859
860 if (mode != UNIT_CHECK) {
7041efe9 861 c->device_policy = p;
e7ab4d1a 862 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
0c2d96f5 863 unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s\n", policy);
7041efe9
LP
864 }
865
866 return 1;
867
868 } else if (streq(name, "DeviceAllow")) {
718db961 869 const char *path, *rwm;
7041efe9
LP
870 unsigned n = 0;
871
718db961
LP
872 r = sd_bus_message_enter_container(message, 'a', "(ss)");
873 if (r < 0)
874 return r;
7041efe9 875
718db961 876 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 877
90060676
LP
878 if ((!startswith(path, "/dev/") &&
879 !startswith(path, "block-") &&
880 !startswith(path, "char-")) ||
881 strpbrk(path, WHITESPACE))
882 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
7041efe9
LP
883
884 if (isempty(rwm))
885 rwm = "rwm";
886
718db961
LP
887 if (!in_charset(rwm, "rwm"))
888 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
7041efe9 889
7041efe9 890 if (mode != UNIT_CHECK) {
718db961 891 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
892
893 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 894 if (path_equal(b->path, path)) {
ad7bfffd 895 a = b;
ad7bfffd
G
896 break;
897 }
898 }
899
718db961 900 if (!a) {
ad7bfffd
G
901 a = new0(CGroupDeviceAllow, 1);
902 if (!a)
903 return -ENOMEM;
904
905 a->path = strdup(path);
906 if (!a->path) {
907 free(a);
908 return -ENOMEM;
909 }
718db961
LP
910
911 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
912 }
913
914 a->r = !!strchr(rwm, 'r');
915 a->w = !!strchr(rwm, 'w');
916 a->m = !!strchr(rwm, 'm');
7041efe9
LP
917 }
918
c2756a68 919 n++;
7041efe9 920 }
43a99a7a
LP
921 if (r < 0)
922 return r;
7041efe9 923
9c96019d
LP
924 r = sd_bus_message_exit_container(message);
925 if (r < 0)
926 return r;
927
7041efe9
LP
928 if (mode != UNIT_CHECK) {
929 _cleanup_free_ char *buf = NULL;
930 _cleanup_fclose_ FILE *f = NULL;
931 CGroupDeviceAllow *a;
932 size_t size = 0;
933
934 if (n == 0) {
935 while (c->device_allow)
936 cgroup_context_free_device_allow(c, c->device_allow);
937 }
938
e7ab4d1a 939 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
3051f187 940
7041efe9
LP
941 f = open_memstream(&buf, &size);
942 if (!f)
943 return -ENOMEM;
944
945 fputs("DeviceAllow=\n", f);
946 LIST_FOREACH(device_allow, a, c->device_allow)
947 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
948
1f2f874c
NC
949 r = fflush_and_check(f);
950 if (r < 0)
951 return r;
b9ec9359 952 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
953 }
954
b42defe3 955 return 1;
a931ad47 956
03a7b521
LP
957 } else if (streq(name, "TasksAccounting")) {
958 int b;
959
960 r = sd_bus_message_read(message, "b", &b);
961 if (r < 0)
962 return r;
963
964 if (mode != UNIT_CHECK) {
965 c->tasks_accounting = b;
e7ab4d1a 966 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
0c2d96f5 967 unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes\n" : "TasksAccounting=no\n");
03a7b521
LP
968 }
969
970 return 1;
971
972 } else if (streq(name, "TasksMax")) {
973 uint64_t limit;
974
975 r = sd_bus_message_read(message, "t", &limit);
976 if (r < 0)
977 return r;
978
979 if (mode != UNIT_CHECK) {
980 c->tasks_max = limit;
e7ab4d1a 981 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
03a7b521
LP
982
983 if (limit == (uint64_t) -1)
0c2d96f5 984 unit_write_drop_in_private(u, mode, name, "TasksMax=infinity\n");
03a7b521 985 else
0c2d96f5 986 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64 "\n", limit);
03a7b521
LP
987 }
988
989 return 1;
a931ad47
LP
990 }
991
992 if (u->transient && u->load_state == UNIT_STUB) {
993 r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
994 if (r != 0)
995 return r;
996
b42defe3 997 }
8e2af478
LP
998
999 return 0;
1000}