]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-cgroup.c
service: improve readability, by reducing line-breaks
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
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
22 #include "bus-util.h"
23 #include "path-util.h"
24 #include "cgroup-util.h"
25 #include "cgroup.h"
26 #include "dbus-cgroup.h"
27
28 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
29
30 static int property_get_blockio_device_weight(
31 sd_bus *bus,
32 const char *path,
33 const char *interface,
34 const char *property,
35 sd_bus_message *reply,
36 void *userdata,
37 sd_bus_error *error) {
38
39 CGroupContext *c = userdata;
40 CGroupBlockIODeviceWeight *w;
41 int r;
42
43 assert(bus);
44 assert(reply);
45 assert(c);
46
47 r = sd_bus_message_open_container(reply, 'a', "(st)");
48 if (r < 0)
49 return r;
50
51 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
52 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
53 if (r < 0)
54 return r;
55 }
56
57 return sd_bus_message_close_container(reply);
58 }
59
60 static int property_get_blockio_device_bandwidths(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
66 void *userdata,
67 sd_bus_error *error) {
68
69 CGroupContext *c = userdata;
70 CGroupBlockIODeviceBandwidth *b;
71 int r;
72
73 assert(bus);
74 assert(reply);
75 assert(c);
76
77 r = sd_bus_message_open_container(reply, 'a', "(st)");
78 if (r < 0)
79 return r;
80
81 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
82
83 if (streq(property, "BlockIOReadBandwidth") != b->read)
84 continue;
85
86 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
87 if (r < 0)
88 return r;
89 }
90
91 return sd_bus_message_close_container(reply);
92 }
93
94 static int property_get_device_allow(
95 sd_bus *bus,
96 const char *path,
97 const char *interface,
98 const char *property,
99 sd_bus_message *reply,
100 void *userdata,
101 sd_bus_error *error) {
102
103 CGroupContext *c = userdata;
104 CGroupDeviceAllow *a;
105 int r;
106
107 assert(bus);
108 assert(reply);
109 assert(c);
110
111 r = sd_bus_message_open_container(reply, 'a', "(ss)");
112 if (r < 0)
113 return r;
114
115 LIST_FOREACH(device_allow, a, c->device_allow) {
116 unsigned k = 0;
117 char rwm[4];
118
119 if (a->r)
120 rwm[k++] = 'r';
121 if (a->w)
122 rwm[k++] = 'w';
123 if (a->m)
124 rwm[k++] = 'm';
125
126 rwm[k] = 0;
127
128 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
129 if (r < 0)
130 return r;
131 }
132
133 return sd_bus_message_close_container(reply);
134 }
135
136 static 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
154 const sd_bus_vtable bus_cgroup_vtable[] = {
155 SD_BUS_VTABLE_START(0),
156 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
157 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
158 SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0),
159 SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0),
160 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
161 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
162 SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0),
163 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0),
164 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
165 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
166 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
167 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
168 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
169 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
170 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
171 SD_BUS_VTABLE_END
172 };
173
174 static 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
207 int bus_cgroup_set_property(
208 Unit *u,
209 CGroupContext *c,
210 const char *name,
211 sd_bus_message *message,
212 UnitSetPropertiesMode mode,
213 sd_bus_error *error) {
214
215 int r;
216
217 assert(u);
218 assert(c);
219 assert(name);
220 assert(message);
221
222 if (streq(name, "CPUAccounting")) {
223 int b;
224
225 r = sd_bus_message_read(message, "b", &b);
226 if (r < 0)
227 return r;
228
229 if (mode != UNIT_CHECK) {
230 c->cpu_accounting = b;
231 u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
232 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
233 }
234
235 return 1;
236
237 } else if (streq(name, "CPUShares")) {
238 uint64_t u64;
239 unsigned long ul;
240
241 r = sd_bus_message_read(message, "t", &u64);
242 if (r < 0)
243 return r;
244
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 }
252
253 if (mode != UNIT_CHECK) {
254 c->cpu_shares = ul;
255 u->cgroup_realized_mask &= ~CGROUP_CPU;
256 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
257 }
258
259 return 1;
260
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
269 if (u64 == (uint64_t) -1)
270 ul = (unsigned long) -1;
271 else {
272 ul = (unsigned long) u64;
273 if (ul <= 0 || (uint64_t) ul != u64)
274 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
275 }
276
277 if (mode != UNIT_CHECK) {
278 c->startup_cpu_shares = ul;
279 u->cgroup_realized_mask &= ~CGROUP_CPU;
280 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
281 }
282
283 return 1;
284
285 } else if (streq(name, "CPUQuotaPerSecUSec")) {
286 uint64_t u64;
287
288 r = sd_bus_message_read(message, "t", &u64);
289 if (r < 0)
290 return r;
291
292 if (u64 <= 0)
293 return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
294
295 if (mode != UNIT_CHECK) {
296 c->cpu_quota_per_sec_usec = u64;
297 u->cgroup_realized_mask &= ~CGROUP_CPU;
298 unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
299 }
300
301 return 1;
302
303 } else if (streq(name, "BlockIOAccounting")) {
304 int b;
305
306 r = sd_bus_message_read(message, "b", &b);
307 if (r < 0)
308 return r;
309
310 if (mode != UNIT_CHECK) {
311 c->blockio_accounting = b;
312 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
313 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
314 }
315
316 return 1;
317
318 } else if (streq(name, "BlockIOWeight")) {
319 uint64_t u64;
320 unsigned long ul;
321
322 r = sd_bus_message_read(message, "t", &u64);
323 if (r < 0)
324 return r;
325
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 }
333
334 if (mode != UNIT_CHECK) {
335 c->blockio_weight = ul;
336 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
337 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
338 }
339
340 return 1;
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
350 if (u64 == (uint64_t) -1)
351 ul = (unsigned long) -1;
352 else {
353 ul = (unsigned long) u64;
354 if (ul < 10 || ul > 1000)
355 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
356 }
357
358 if (mode != UNIT_CHECK) {
359 c->startup_blockio_weight = ul;
360 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
361 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
362 }
363
364 return 1;
365
366 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
367 const char *path;
368 bool read = true;
369 unsigned n = 0;
370 uint64_t u64;
371
372 if (streq(name, "BlockIOWriteBandwidth"))
373 read = false;
374
375 r = sd_bus_message_enter_container(message, 'a', "(st)");
376 if (r < 0)
377 return r;
378
379 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
380
381 if (mode != UNIT_CHECK) {
382 CGroupBlockIODeviceBandwidth *a = NULL, *b;
383
384 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
385 if (path_equal(path, b->path) && read == b->read) {
386 a = b;
387 break;
388 }
389 }
390
391 if (!a) {
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 }
402
403 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
404 }
405
406 a->bandwidth = u64;
407 }
408
409 n++;
410 }
411 if (r < 0)
412 return r;
413
414 r = sd_bus_message_exit_container(message);
415 if (r < 0)
416 return r;
417
418 if (mode != UNIT_CHECK) {
419 CGroupBlockIODeviceBandwidth *a, *next;
420 _cleanup_free_ char *buf = NULL;
421 _cleanup_fclose_ FILE *f = NULL;
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
430 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
431
432 f = open_memstream(&buf, &size);
433 if (!f)
434 return -ENOMEM;
435
436 if (read) {
437 fputs("BlockIOReadBandwidth=\n", f);
438 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
439 if (a->read)
440 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
441 } else {
442 fputs("BlockIOWriteBandwidth=\n", f);
443 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
444 if (!a->read)
445 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
446 }
447
448 fflush(f);
449 unit_write_drop_in_private(u, mode, name, buf);
450 }
451
452 return 1;
453
454 } else if (streq(name, "BlockIODeviceWeight")) {
455 const char *path;
456 uint64_t u64;
457 unsigned n = 0;
458
459 r = sd_bus_message_enter_container(message, 'a', "(st)");
460 if (r < 0)
461 return r;
462
463 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
464 unsigned long ul = u64;
465
466 if (ul < 10 || ul > 1000)
467 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
468
469 if (mode != UNIT_CHECK) {
470 CGroupBlockIODeviceWeight *a = NULL, *b;
471
472 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
473 if (path_equal(b->path, path)) {
474 a = b;
475 break;
476 }
477 }
478
479 if (!a) {
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 }
489 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
490 }
491
492 a->weight = ul;
493 }
494
495 n++;
496 }
497
498 r = sd_bus_message_exit_container(message);
499 if (r < 0)
500 return r;
501
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
513 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
514
515 f = open_memstream(&buf, &size);
516 if (!f)
517 return -ENOMEM;
518
519 fputs("BlockIODeviceWeight=\n", f);
520 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
521 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
522
523 fflush(f);
524 unit_write_drop_in_private(u, mode, name, buf);
525 }
526
527 return 1;
528
529 } else if (streq(name, "MemoryAccounting")) {
530 int b;
531
532 r = sd_bus_message_read(message, "b", &b);
533 if (r < 0)
534 return r;
535
536 if (mode != UNIT_CHECK) {
537 c->memory_accounting = b;
538 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
539 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
540 }
541
542 return 1;
543
544 } else if (streq(name, "MemoryLimit")) {
545 uint64_t limit;
546
547 r = sd_bus_message_read(message, "t", &limit);
548 if (r < 0)
549 return r;
550
551 if (mode != UNIT_CHECK) {
552 c->memory_limit = limit;
553 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
554 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
555 }
556
557 return 1;
558
559 } else if (streq(name, "DevicePolicy")) {
560 const char *policy;
561 CGroupDevicePolicy p;
562
563 r = sd_bus_message_read(message, "s", &policy);
564 if (r < 0)
565 return r;
566
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;
575 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
576
577 buf = strjoina("DevicePolicy=", policy);
578 unit_write_drop_in_private(u, mode, name, buf);
579 }
580
581 return 1;
582
583 } else if (streq(name, "DeviceAllow")) {
584 const char *path, *rwm;
585 unsigned n = 0;
586
587 r = sd_bus_message_enter_container(message, 'a', "(ss)");
588 if (r < 0)
589 return r;
590
591 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
592
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");
598
599 if (isempty(rwm))
600 rwm = "rwm";
601
602 if (!in_charset(rwm, "rwm"))
603 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
604
605 if (mode != UNIT_CHECK) {
606 CGroupDeviceAllow *a = NULL, *b;
607
608 LIST_FOREACH(device_allow, b, c->device_allow) {
609 if (path_equal(b->path, path)) {
610 a = b;
611 break;
612 }
613 }
614
615 if (!a) {
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 }
625
626 LIST_PREPEND(device_allow, c->device_allow, a);
627 }
628
629 a->r = !!strchr(rwm, 'r');
630 a->w = !!strchr(rwm, 'w');
631 a->m = !!strchr(rwm, 'm');
632 }
633
634 n++;
635 }
636 if (r < 0)
637 return r;
638
639 r = sd_bus_message_exit_container(message);
640 if (r < 0)
641 return r;
642
643 if (mode != UNIT_CHECK) {
644 _cleanup_free_ char *buf = NULL;
645 _cleanup_fclose_ FILE *f = NULL;
646 CGroupDeviceAllow *a;
647 size_t size = 0;
648
649 if (n == 0) {
650 while (c->device_allow)
651 cgroup_context_free_device_allow(c, c->device_allow);
652 }
653
654 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
655
656 f = open_memstream(&buf, &size);
657 if (!f)
658 return -ENOMEM;
659
660 fputs("DeviceAllow=\n", f);
661 LIST_FOREACH(device_allow, a, c->device_allow)
662 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
663
664 fflush(f);
665 unit_write_drop_in_private(u, mode, name, buf);
666 }
667
668 return 1;
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
677 }
678
679 return 0;
680 }