]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
sd-dhcp-client: respect TP_STATUS_CSUMNOTREADY
[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),
610f780c
LP
138 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
139 SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
140 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
141 SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
142 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
143 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
144 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
145 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
146 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
147 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
148 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
718db961 149 SD_BUS_VTABLE_END
4ad49000 150};
8e2af478
LP
151
152int bus_cgroup_set_property(
153 Unit *u,
154 CGroupContext *c,
155 const char *name,
718db961 156 sd_bus_message *message,
8e2af478 157 UnitSetPropertiesMode mode,
718db961
LP
158 sd_bus_error *error) {
159
160 int r;
8e2af478 161
8e2af478
LP
162 assert(u);
163 assert(c);
718db961
LP
164 assert(name);
165 assert(message);
8e2af478
LP
166
167 if (streq(name, "CPUAccounting")) {
718db961 168 int b;
8e2af478 169
718db961
LP
170 r = sd_bus_message_read(message, "b", &b);
171 if (r < 0)
172 return r;
8e2af478
LP
173
174 if (mode != UNIT_CHECK) {
8e2af478 175 c->cpu_accounting = b;
b9ec9359 176 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
b42defe3
LP
177 }
178
179 return 1;
180
181 } else if (streq(name, "CPUShares")) {
182 uint64_t u64;
183 unsigned long ul;
184
718db961
LP
185 r = sd_bus_message_read(message, "t", &u64);
186 if (r < 0)
187 return r;
b42defe3 188
b42defe3 189 ul = (unsigned long) u64;
718db961
LP
190 if (ul <= 0 || (uint64_t) ul != u64)
191 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
b42defe3
LP
192
193 if (mode != UNIT_CHECK) {
b42defe3 194 c->cpu_shares = ul;
b9ec9359 195 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
8e2af478
LP
196 }
197
198 return 1;
199
200 } else if (streq(name, "BlockIOAccounting")) {
718db961 201 int b;
8e2af478 202
718db961
LP
203 r = sd_bus_message_read(message, "b", &b);
204 if (r < 0)
205 return r;
8e2af478
LP
206
207 if (mode != UNIT_CHECK) {
8e2af478 208 c->blockio_accounting = b;
b9ec9359 209 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
210 }
211
212 return 1;
b42defe3
LP
213
214 } else if (streq(name, "BlockIOWeight")) {
215 uint64_t u64;
216 unsigned long ul;
217
718db961
LP
218 r = sd_bus_message_read(message, "t", &u64);
219 if (r < 0)
220 return r;
b42defe3 221
b42defe3 222 ul = (unsigned long) u64;
718db961
LP
223 if (ul < 10 || ul > 1000)
224 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
b42defe3
LP
225
226 if (mode != UNIT_CHECK) {
f2369103 227 c->blockio_weight = ul;
b9ec9359 228 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
b42defe3
LP
229 }
230
231 return 1;
232
f004c2ca 233 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
718db961 234 const char *path;
f004c2ca 235 bool read = true;
718db961
LP
236 unsigned n = 0;
237 uint64_t u64;
f004c2ca
G
238
239 if (streq(name, "BlockIOWriteBandwidth"))
240 read = false;
241
718db961
LP
242 r = sd_bus_message_enter_container(message, 'a', "(st)");
243 if (r < 0)
244 return r;
f004c2ca 245
718db961 246 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca
G
247
248 if (mode != UNIT_CHECK) {
718db961 249 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
250
251 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
252 if (path_equal(path, b->path) && read == b->read) {
253 a = b;
f004c2ca
G
254 break;
255 }
256 }
257
718db961 258 if (!a) {
f004c2ca
G
259 a = new0(CGroupBlockIODeviceBandwidth, 1);
260 if (!a)
261 return -ENOMEM;
262
263 a->read = read;
264 a->path = strdup(path);
265 if (!a->path) {
266 free(a);
267 return -ENOMEM;
268 }
718db961
LP
269
270 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
271 }
272
273 a->bandwidth = u64;
f004c2ca
G
274 }
275
276 n++;
f004c2ca 277 }
718db961
LP
278 if (r < 0)
279 return r;
f004c2ca
G
280
281 if (mode != UNIT_CHECK) {
718db961 282 CGroupBlockIODeviceBandwidth *a, *next;
f004c2ca
G
283 _cleanup_free_ char *buf = NULL;
284 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
285 size_t size = 0;
286
287 if (n == 0) {
288 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
289 if (a->read == read)
290 cgroup_context_free_blockio_device_bandwidth(c, a);
291 }
292
293 f = open_memstream(&buf, &size);
294 if (!f)
295 return -ENOMEM;
296
297 if (read) {
298 fputs("BlockIOReadBandwidth=\n", f);
299 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
300 if (a->read)
301 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
302 } else {
303 fputs("BlockIOWriteBandwidth=\n", f);
304 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
305 if (!a->read)
306 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
307 }
308
6f68ecb4
G
309 fflush(f);
310 unit_write_drop_in_private(u, mode, name, buf);
311 }
312
313 return 1;
314
315 } else if (streq(name, "BlockIODeviceWeight")) {
718db961
LP
316 const char *path;
317 uint64_t u64;
6f68ecb4
G
318 unsigned n = 0;
319
718db961
LP
320 r = sd_bus_message_enter_container(message, 'a', "(st)");
321 if (r < 0)
322 return r;
6f68ecb4 323
ccd06097
ZJS
324 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
325 unsigned long ul = u64;
6f68ecb4 326
6f68ecb4 327 if (ul < 10 || ul > 1000)
718db961 328 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
6f68ecb4
G
329
330 if (mode != UNIT_CHECK) {
718db961 331 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
332
333 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
334 if (path_equal(b->path, path)) {
335 a = b;
6f68ecb4
G
336 break;
337 }
338 }
339
718db961 340 if (!a) {
6f68ecb4
G
341 a = new0(CGroupBlockIODeviceWeight, 1);
342 if (!a)
343 return -ENOMEM;
344
345 a->path = strdup(path);
346 if (!a->path) {
347 free(a);
348 return -ENOMEM;
349 }
718db961 350 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
351 }
352
353 a->weight = ul;
6f68ecb4
G
354 }
355
356 n++;
6f68ecb4
G
357 }
358
359 if (mode != UNIT_CHECK) {
360 _cleanup_free_ char *buf = NULL;
361 _cleanup_fclose_ FILE *f = NULL;
362 CGroupBlockIODeviceWeight *a;
363 size_t size = 0;
364
365 if (n == 0) {
366 while (c->blockio_device_weights)
367 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
368 }
369
370 f = open_memstream(&buf, &size);
371 if (!f)
372 return -ENOMEM;
373
374 fputs("BlockIODeviceWeight=\n", f);
375 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
376 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
377
f004c2ca
G
378 fflush(f);
379 unit_write_drop_in_private(u, mode, name, buf);
380 }
381
382 return 1;
383
8e2af478 384 } else if (streq(name, "MemoryAccounting")) {
718db961 385 int b;
8e2af478 386
718db961
LP
387 r = sd_bus_message_read(message, "b", &b);
388 if (r < 0)
389 return r;
8e2af478
LP
390
391 if (mode != UNIT_CHECK) {
b42defe3 392 c->memory_accounting = b;
b9ec9359 393 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
394 }
395
396 return 1;
8e2af478 397
ddca82ac 398 } else if (streq(name, "MemoryLimit")) {
718db961 399 uint64_t limit;
b42defe3 400
718db961
LP
401 r = sd_bus_message_read(message, "t", &limit);
402 if (r < 0)
403 return r;
b42defe3
LP
404
405 if (mode != UNIT_CHECK) {
ddca82ac 406 c->memory_limit = limit;
b9ec9359 407 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
b42defe3
LP
408 }
409
7041efe9
LP
410 return 1;
411
412 } else if (streq(name, "DevicePolicy")) {
413 const char *policy;
414 CGroupDevicePolicy p;
415
718db961
LP
416 r = sd_bus_message_read(message, "s", &policy);
417 if (r < 0)
418 return r;
7041efe9 419
7041efe9
LP
420 p = cgroup_device_policy_from_string(policy);
421 if (p < 0)
422 return -EINVAL;
423
424 if (mode != UNIT_CHECK) {
425 char *buf;
426
427 c->device_policy = p;
428
429 buf = strappenda("DevicePolicy=", policy);
b9ec9359 430 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
431 }
432
433 return 1;
434
435 } else if (streq(name, "DeviceAllow")) {
718db961 436 const char *path, *rwm;
7041efe9
LP
437 unsigned n = 0;
438
718db961
LP
439 r = sd_bus_message_enter_container(message, 'a', "(ss)");
440 if (r < 0)
441 return r;
7041efe9 442
718db961 443 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 444
90060676
LP
445 if ((!startswith(path, "/dev/") &&
446 !startswith(path, "block-") &&
447 !startswith(path, "char-")) ||
448 strpbrk(path, WHITESPACE))
449 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
7041efe9
LP
450
451 if (isempty(rwm))
452 rwm = "rwm";
453
718db961
LP
454 if (!in_charset(rwm, "rwm"))
455 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
7041efe9 456
7041efe9 457 if (mode != UNIT_CHECK) {
718db961 458 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
459
460 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 461 if (path_equal(b->path, path)) {
ad7bfffd 462 a = b;
ad7bfffd
G
463 break;
464 }
465 }
466
718db961 467 if (!a) {
ad7bfffd
G
468 a = new0(CGroupDeviceAllow, 1);
469 if (!a)
470 return -ENOMEM;
471
472 a->path = strdup(path);
473 if (!a->path) {
474 free(a);
475 return -ENOMEM;
476 }
718db961
LP
477
478 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
479 }
480
481 a->r = !!strchr(rwm, 'r');
482 a->w = !!strchr(rwm, 'w');
483 a->m = !!strchr(rwm, 'm');
484
7041efe9
LP
485 }
486
c2756a68 487 n++;
7041efe9 488 }
43a99a7a
LP
489 if (r < 0)
490 return r;
7041efe9
LP
491
492 if (mode != UNIT_CHECK) {
493 _cleanup_free_ char *buf = NULL;
494 _cleanup_fclose_ FILE *f = NULL;
495 CGroupDeviceAllow *a;
496 size_t size = 0;
497
498 if (n == 0) {
499 while (c->device_allow)
500 cgroup_context_free_device_allow(c, c->device_allow);
501 }
502
503 f = open_memstream(&buf, &size);
504 if (!f)
505 return -ENOMEM;
506
507 fputs("DeviceAllow=\n", f);
508 LIST_FOREACH(device_allow, a, c->device_allow)
509 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
510
511 fflush(f);
b9ec9359 512 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
513 }
514
b42defe3
LP
515 return 1;
516 }
8e2af478
LP
517
518 return 0;
519}