]>
Commit | Line | Data |
---|---|---|
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 |
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, | |
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 |
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, | |
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 |
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, | |
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 |
136 | const 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 | |
152 | int 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 | |
718db961 | 324 | while (( r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { |
6f68ecb4 | 325 | unsigned long ul; |
6f68ecb4 | 326 | |
6f68ecb4 G |
327 | ul = (unsigned long) u64; |
328 | if (ul < 10 || ul > 1000) | |
718db961 | 329 | return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); |
6f68ecb4 G |
330 | |
331 | if (mode != UNIT_CHECK) { | |
718db961 | 332 | CGroupBlockIODeviceWeight *a = NULL, *b; |
6f68ecb4 G |
333 | |
334 | LIST_FOREACH(device_weights, b, c->blockio_device_weights) { | |
335 | if (path_equal(b->path, path)) { | |
336 | a = b; | |
6f68ecb4 G |
337 | break; |
338 | } | |
339 | } | |
340 | ||
718db961 | 341 | if (!a) { |
6f68ecb4 G |
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 | } | |
718db961 | 351 | LIST_PREPEND(device_weights,c->blockio_device_weights, a); |
6f68ecb4 G |
352 | } |
353 | ||
354 | a->weight = ul; | |
6f68ecb4 G |
355 | } |
356 | ||
357 | n++; | |
6f68ecb4 G |
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 | ||
f004c2ca G |
379 | fflush(f); |
380 | unit_write_drop_in_private(u, mode, name, buf); | |
381 | } | |
382 | ||
383 | return 1; | |
384 | ||
8e2af478 | 385 | } else if (streq(name, "MemoryAccounting")) { |
718db961 | 386 | int b; |
8e2af478 | 387 | |
718db961 LP |
388 | r = sd_bus_message_read(message, "b", &b); |
389 | if (r < 0) | |
390 | return r; | |
8e2af478 LP |
391 | |
392 | if (mode != UNIT_CHECK) { | |
b42defe3 | 393 | c->memory_accounting = b; |
b9ec9359 | 394 | unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); |
8e2af478 LP |
395 | } |
396 | ||
397 | return 1; | |
8e2af478 | 398 | |
ddca82ac | 399 | } else if (streq(name, "MemoryLimit")) { |
718db961 | 400 | uint64_t limit; |
b42defe3 | 401 | |
718db961 LP |
402 | r = sd_bus_message_read(message, "t", &limit); |
403 | if (r < 0) | |
404 | return r; | |
b42defe3 LP |
405 | |
406 | if (mode != UNIT_CHECK) { | |
ddca82ac | 407 | c->memory_limit = limit; |
b9ec9359 | 408 | unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit); |
b42defe3 LP |
409 | } |
410 | ||
7041efe9 LP |
411 | return 1; |
412 | ||
413 | } else if (streq(name, "DevicePolicy")) { | |
414 | const char *policy; | |
415 | CGroupDevicePolicy p; | |
416 | ||
718db961 LP |
417 | r = sd_bus_message_read(message, "s", &policy); |
418 | if (r < 0) | |
419 | return r; | |
7041efe9 | 420 | |
7041efe9 LP |
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); | |
b9ec9359 | 431 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
432 | } |
433 | ||
434 | return 1; | |
435 | ||
436 | } else if (streq(name, "DeviceAllow")) { | |
718db961 | 437 | const char *path, *rwm; |
7041efe9 LP |
438 | unsigned n = 0; |
439 | ||
718db961 LP |
440 | r = sd_bus_message_enter_container(message, 'a', "(ss)"); |
441 | if (r < 0) | |
442 | return r; | |
7041efe9 | 443 | |
718db961 | 444 | while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { |
7041efe9 | 445 | |
718db961 LP |
446 | if (!path_startswith(path, "/dev")) |
447 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node"); | |
7041efe9 LP |
448 | |
449 | if (isempty(rwm)) | |
450 | rwm = "rwm"; | |
451 | ||
718db961 LP |
452 | if (!in_charset(rwm, "rwm")) |
453 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags"); | |
7041efe9 | 454 | |
7041efe9 | 455 | if (mode != UNIT_CHECK) { |
718db961 | 456 | CGroupDeviceAllow *a = NULL, *b; |
ad7bfffd G |
457 | |
458 | LIST_FOREACH(device_allow, b, c->device_allow) { | |
06eb4e3b | 459 | if (path_equal(b->path, path)) { |
ad7bfffd | 460 | a = b; |
ad7bfffd G |
461 | break; |
462 | } | |
463 | } | |
464 | ||
718db961 | 465 | if (!a) { |
ad7bfffd G |
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 | } | |
718db961 LP |
475 | |
476 | LIST_PREPEND(device_allow, c->device_allow, a); | |
7041efe9 LP |
477 | } |
478 | ||
479 | a->r = !!strchr(rwm, 'r'); | |
480 | a->w = !!strchr(rwm, 'w'); | |
481 | a->m = !!strchr(rwm, 'm'); | |
482 | ||
7041efe9 LP |
483 | } |
484 | ||
c2756a68 | 485 | n++; |
7041efe9 | 486 | } |
43a99a7a LP |
487 | if (r < 0) |
488 | return r; | |
7041efe9 LP |
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); | |
b9ec9359 | 510 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
511 | } |
512 | ||
b42defe3 LP |
513 | return 1; |
514 | } | |
8e2af478 LP |
515 | |
516 | return 0; | |
517 | } |