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