]>
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 | ||
db785129 LP |
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 | ||
718db961 LP |
154 | const sd_bus_vtable bus_cgroup_vtable[] = { |
155 | SD_BUS_VTABLE_START(0), | |
a931ad47 | 156 | SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0), |
610f780c | 157 | SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), |
db785129 LP |
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), | |
ee26bcc0 | 160 | SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), |
610f780c | 161 | SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), |
db785129 LP |
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), | |
610f780c LP |
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), | |
03a7b521 LP |
171 | SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0), |
172 | SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0), | |
718db961 | 173 | SD_BUS_VTABLE_END |
4ad49000 | 174 | }; |
8e2af478 | 175 | |
a931ad47 LP |
176 | static int bus_cgroup_set_transient_property( |
177 | Unit *u, | |
178 | CGroupContext *c, | |
179 | const char *name, | |
180 | sd_bus_message *message, | |
181 | UnitSetPropertiesMode mode, | |
182 | sd_bus_error *error) { | |
183 | ||
184 | int r; | |
185 | ||
186 | assert(u); | |
187 | assert(c); | |
188 | assert(name); | |
189 | assert(message); | |
190 | ||
191 | if (streq(name, "Delegate")) { | |
192 | int b; | |
193 | ||
194 | r = sd_bus_message_read(message, "b", &b); | |
195 | if (r < 0) | |
196 | return r; | |
197 | ||
198 | if (mode != UNIT_CHECK) { | |
199 | c->delegate = b; | |
200 | unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no"); | |
201 | } | |
202 | ||
203 | return 1; | |
204 | } | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
8e2af478 LP |
209 | int bus_cgroup_set_property( |
210 | Unit *u, | |
211 | CGroupContext *c, | |
212 | const char *name, | |
718db961 | 213 | sd_bus_message *message, |
8e2af478 | 214 | UnitSetPropertiesMode mode, |
718db961 LP |
215 | sd_bus_error *error) { |
216 | ||
217 | int r; | |
8e2af478 | 218 | |
8e2af478 LP |
219 | assert(u); |
220 | assert(c); | |
718db961 LP |
221 | assert(name); |
222 | assert(message); | |
8e2af478 LP |
223 | |
224 | if (streq(name, "CPUAccounting")) { | |
718db961 | 225 | int b; |
8e2af478 | 226 | |
718db961 LP |
227 | r = sd_bus_message_read(message, "b", &b); |
228 | if (r < 0) | |
229 | return r; | |
8e2af478 LP |
230 | |
231 | if (mode != UNIT_CHECK) { | |
8e2af478 | 232 | c->cpu_accounting = b; |
efdb0237 | 233 | u->cgroup_realized_mask &= ~CGROUP_MASK_CPUACCT; |
b9ec9359 | 234 | unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); |
b42defe3 LP |
235 | } |
236 | ||
237 | return 1; | |
238 | ||
239 | } else if (streq(name, "CPUShares")) { | |
240 | uint64_t u64; | |
241 | unsigned long ul; | |
242 | ||
718db961 LP |
243 | r = sd_bus_message_read(message, "t", &u64); |
244 | if (r < 0) | |
245 | return r; | |
b42defe3 | 246 | |
db785129 LP |
247 | if (u64 == (uint64_t) -1) |
248 | ul = (unsigned long) -1; | |
249 | else { | |
250 | ul = (unsigned long) u64; | |
251 | if (ul <= 0 || (uint64_t) ul != u64) | |
252 | return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); | |
253 | } | |
b42defe3 LP |
254 | |
255 | if (mode != UNIT_CHECK) { | |
b42defe3 | 256 | c->cpu_shares = ul; |
efdb0237 | 257 | u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; |
b9ec9359 | 258 | unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul); |
8e2af478 LP |
259 | } |
260 | ||
261 | return 1; | |
262 | ||
95ae05c0 WC |
263 | } else if (streq(name, "StartupCPUShares")) { |
264 | uint64_t u64; | |
265 | unsigned long ul; | |
266 | ||
267 | r = sd_bus_message_read(message, "t", &u64); | |
268 | if (r < 0) | |
269 | return r; | |
270 | ||
db785129 LP |
271 | if (u64 == (uint64_t) -1) |
272 | ul = (unsigned long) -1; | |
273 | else { | |
274 | ul = (unsigned long) u64; | |
275 | if (ul <= 0 || (uint64_t) ul != u64) | |
276 | return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); | |
277 | } | |
95ae05c0 WC |
278 | |
279 | if (mode != UNIT_CHECK) { | |
280 | c->startup_cpu_shares = ul; | |
efdb0237 | 281 | u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; |
95ae05c0 WC |
282 | unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul); |
283 | } | |
284 | ||
285 | return 1; | |
286 | ||
b2f8b02e LP |
287 | } else if (streq(name, "CPUQuotaPerSecUSec")) { |
288 | uint64_t u64; | |
289 | ||
290 | r = sd_bus_message_read(message, "t", &u64); | |
291 | if (r < 0) | |
292 | return r; | |
293 | ||
294 | if (u64 <= 0) | |
295 | return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range"); | |
296 | ||
297 | if (mode != UNIT_CHECK) { | |
298 | c->cpu_quota_per_sec_usec = u64; | |
efdb0237 | 299 | u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; |
b2f8b02e LP |
300 | unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000)); |
301 | } | |
302 | ||
303 | return 1; | |
304 | ||
8e2af478 | 305 | } else if (streq(name, "BlockIOAccounting")) { |
718db961 | 306 | int b; |
8e2af478 | 307 | |
718db961 LP |
308 | r = sd_bus_message_read(message, "b", &b); |
309 | if (r < 0) | |
310 | return r; | |
8e2af478 LP |
311 | |
312 | if (mode != UNIT_CHECK) { | |
8e2af478 | 313 | c->blockio_accounting = b; |
efdb0237 | 314 | u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; |
b9ec9359 | 315 | unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); |
8e2af478 LP |
316 | } |
317 | ||
318 | return 1; | |
b42defe3 LP |
319 | |
320 | } else if (streq(name, "BlockIOWeight")) { | |
321 | uint64_t u64; | |
322 | unsigned long ul; | |
323 | ||
718db961 LP |
324 | r = sd_bus_message_read(message, "t", &u64); |
325 | if (r < 0) | |
326 | return r; | |
b42defe3 | 327 | |
db785129 LP |
328 | if (u64 == (uint64_t) -1) |
329 | ul = (unsigned long) -1; | |
330 | else { | |
331 | ul = (unsigned long) u64; | |
332 | if (ul < 10 || ul > 1000) | |
333 | return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); | |
334 | } | |
b42defe3 LP |
335 | |
336 | if (mode != UNIT_CHECK) { | |
f2369103 | 337 | c->blockio_weight = ul; |
efdb0237 | 338 | u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; |
b9ec9359 | 339 | unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul); |
b42defe3 LP |
340 | } |
341 | ||
342 | return 1; | |
95ae05c0 WC |
343 | |
344 | } else if (streq(name, "StartupBlockIOWeight")) { | |
345 | uint64_t u64; | |
346 | unsigned long ul; | |
347 | ||
348 | r = sd_bus_message_read(message, "t", &u64); | |
349 | if (r < 0) | |
350 | return r; | |
351 | ||
db785129 LP |
352 | if (u64 == (uint64_t) -1) |
353 | ul = (unsigned long) -1; | |
354 | else { | |
355 | ul = (unsigned long) u64; | |
356 | if (ul < 10 || ul > 1000) | |
357 | return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); | |
358 | } | |
95ae05c0 WC |
359 | |
360 | if (mode != UNIT_CHECK) { | |
361 | c->startup_blockio_weight = ul; | |
efdb0237 | 362 | u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; |
95ae05c0 WC |
363 | unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul); |
364 | } | |
365 | ||
366 | return 1; | |
b42defe3 | 367 | |
f004c2ca | 368 | } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { |
718db961 | 369 | const char *path; |
f004c2ca | 370 | bool read = true; |
718db961 LP |
371 | unsigned n = 0; |
372 | uint64_t u64; | |
f004c2ca G |
373 | |
374 | if (streq(name, "BlockIOWriteBandwidth")) | |
375 | read = false; | |
376 | ||
718db961 LP |
377 | r = sd_bus_message_enter_container(message, 'a', "(st)"); |
378 | if (r < 0) | |
379 | return r; | |
f004c2ca | 380 | |
718db961 | 381 | while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { |
f004c2ca G |
382 | |
383 | if (mode != UNIT_CHECK) { | |
718db961 | 384 | CGroupBlockIODeviceBandwidth *a = NULL, *b; |
f004c2ca G |
385 | |
386 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { | |
387 | if (path_equal(path, b->path) && read == b->read) { | |
388 | a = b; | |
f004c2ca G |
389 | break; |
390 | } | |
391 | } | |
392 | ||
718db961 | 393 | if (!a) { |
f004c2ca G |
394 | a = new0(CGroupBlockIODeviceBandwidth, 1); |
395 | if (!a) | |
396 | return -ENOMEM; | |
397 | ||
398 | a->read = read; | |
399 | a->path = strdup(path); | |
400 | if (!a->path) { | |
401 | free(a); | |
402 | return -ENOMEM; | |
403 | } | |
718db961 LP |
404 | |
405 | LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); | |
f004c2ca G |
406 | } |
407 | ||
408 | a->bandwidth = u64; | |
f004c2ca G |
409 | } |
410 | ||
411 | n++; | |
f004c2ca | 412 | } |
718db961 LP |
413 | if (r < 0) |
414 | return r; | |
f004c2ca | 415 | |
9c96019d LP |
416 | r = sd_bus_message_exit_container(message); |
417 | if (r < 0) | |
418 | return r; | |
419 | ||
f004c2ca | 420 | if (mode != UNIT_CHECK) { |
718db961 | 421 | CGroupBlockIODeviceBandwidth *a, *next; |
f004c2ca G |
422 | _cleanup_free_ char *buf = NULL; |
423 | _cleanup_fclose_ FILE *f = NULL; | |
f004c2ca G |
424 | size_t size = 0; |
425 | ||
426 | if (n == 0) { | |
427 | LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths) | |
428 | if (a->read == read) | |
429 | cgroup_context_free_blockio_device_bandwidth(c, a); | |
430 | } | |
431 | ||
efdb0237 | 432 | u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; |
3051f187 | 433 | |
f004c2ca G |
434 | f = open_memstream(&buf, &size); |
435 | if (!f) | |
436 | return -ENOMEM; | |
437 | ||
7d6884b6 | 438 | if (read) { |
f004c2ca | 439 | fputs("BlockIOReadBandwidth=\n", f); |
7d6884b6 | 440 | LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) |
f004c2ca G |
441 | if (a->read) |
442 | fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); | |
443 | } else { | |
444 | fputs("BlockIOWriteBandwidth=\n", f); | |
445 | LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) | |
446 | if (!a->read) | |
447 | fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); | |
448 | } | |
449 | ||
6f68ecb4 G |
450 | fflush(f); |
451 | unit_write_drop_in_private(u, mode, name, buf); | |
452 | } | |
453 | ||
454 | return 1; | |
455 | ||
456 | } else if (streq(name, "BlockIODeviceWeight")) { | |
718db961 LP |
457 | const char *path; |
458 | uint64_t u64; | |
6f68ecb4 G |
459 | unsigned n = 0; |
460 | ||
718db961 LP |
461 | r = sd_bus_message_enter_container(message, 'a', "(st)"); |
462 | if (r < 0) | |
463 | return r; | |
6f68ecb4 | 464 | |
ccd06097 ZJS |
465 | while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { |
466 | unsigned long ul = u64; | |
6f68ecb4 | 467 | |
6f68ecb4 | 468 | if (ul < 10 || ul > 1000) |
718db961 | 469 | return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); |
6f68ecb4 G |
470 | |
471 | if (mode != UNIT_CHECK) { | |
718db961 | 472 | CGroupBlockIODeviceWeight *a = NULL, *b; |
6f68ecb4 G |
473 | |
474 | LIST_FOREACH(device_weights, b, c->blockio_device_weights) { | |
475 | if (path_equal(b->path, path)) { | |
476 | a = b; | |
6f68ecb4 G |
477 | break; |
478 | } | |
479 | } | |
480 | ||
718db961 | 481 | if (!a) { |
6f68ecb4 G |
482 | a = new0(CGroupBlockIODeviceWeight, 1); |
483 | if (!a) | |
484 | return -ENOMEM; | |
485 | ||
486 | a->path = strdup(path); | |
487 | if (!a->path) { | |
488 | free(a); | |
489 | return -ENOMEM; | |
490 | } | |
718db961 | 491 | LIST_PREPEND(device_weights,c->blockio_device_weights, a); |
6f68ecb4 G |
492 | } |
493 | ||
494 | a->weight = ul; | |
6f68ecb4 G |
495 | } |
496 | ||
497 | n++; | |
6f68ecb4 G |
498 | } |
499 | ||
9c96019d LP |
500 | r = sd_bus_message_exit_container(message); |
501 | if (r < 0) | |
502 | return r; | |
503 | ||
6f68ecb4 G |
504 | if (mode != UNIT_CHECK) { |
505 | _cleanup_free_ char *buf = NULL; | |
506 | _cleanup_fclose_ FILE *f = NULL; | |
507 | CGroupBlockIODeviceWeight *a; | |
508 | size_t size = 0; | |
509 | ||
510 | if (n == 0) { | |
511 | while (c->blockio_device_weights) | |
512 | cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); | |
513 | } | |
514 | ||
efdb0237 | 515 | u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; |
3051f187 | 516 | |
6f68ecb4 G |
517 | f = open_memstream(&buf, &size); |
518 | if (!f) | |
519 | return -ENOMEM; | |
520 | ||
521 | fputs("BlockIODeviceWeight=\n", f); | |
522 | LIST_FOREACH(device_weights, a, c->blockio_device_weights) | |
523 | fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight); | |
524 | ||
f004c2ca G |
525 | fflush(f); |
526 | unit_write_drop_in_private(u, mode, name, buf); | |
527 | } | |
528 | ||
529 | return 1; | |
530 | ||
8e2af478 | 531 | } else if (streq(name, "MemoryAccounting")) { |
718db961 | 532 | int b; |
8e2af478 | 533 | |
718db961 LP |
534 | r = sd_bus_message_read(message, "b", &b); |
535 | if (r < 0) | |
536 | return r; | |
8e2af478 LP |
537 | |
538 | if (mode != UNIT_CHECK) { | |
b42defe3 | 539 | c->memory_accounting = b; |
efdb0237 | 540 | u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY; |
b9ec9359 | 541 | unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); |
8e2af478 LP |
542 | } |
543 | ||
544 | return 1; | |
8e2af478 | 545 | |
ddca82ac | 546 | } else if (streq(name, "MemoryLimit")) { |
718db961 | 547 | uint64_t limit; |
b42defe3 | 548 | |
718db961 LP |
549 | r = sd_bus_message_read(message, "t", &limit); |
550 | if (r < 0) | |
551 | return r; | |
b42defe3 LP |
552 | |
553 | if (mode != UNIT_CHECK) { | |
ddca82ac | 554 | c->memory_limit = limit; |
efdb0237 | 555 | u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY; |
03a7b521 LP |
556 | |
557 | if (limit == (uint64_t) -1) | |
558 | unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); | |
559 | else | |
560 | unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit); | |
b42defe3 LP |
561 | } |
562 | ||
7041efe9 LP |
563 | return 1; |
564 | ||
565 | } else if (streq(name, "DevicePolicy")) { | |
566 | const char *policy; | |
567 | CGroupDevicePolicy p; | |
568 | ||
718db961 LP |
569 | r = sd_bus_message_read(message, "s", &policy); |
570 | if (r < 0) | |
571 | return r; | |
7041efe9 | 572 | |
7041efe9 LP |
573 | p = cgroup_device_policy_from_string(policy); |
574 | if (p < 0) | |
575 | return -EINVAL; | |
576 | ||
577 | if (mode != UNIT_CHECK) { | |
578 | char *buf; | |
579 | ||
580 | c->device_policy = p; | |
3905f127 | 581 | u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES; |
7041efe9 | 582 | |
63c372cb | 583 | buf = strjoina("DevicePolicy=", policy); |
b9ec9359 | 584 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
585 | } |
586 | ||
587 | return 1; | |
588 | ||
589 | } else if (streq(name, "DeviceAllow")) { | |
718db961 | 590 | const char *path, *rwm; |
7041efe9 LP |
591 | unsigned n = 0; |
592 | ||
718db961 LP |
593 | r = sd_bus_message_enter_container(message, 'a', "(ss)"); |
594 | if (r < 0) | |
595 | return r; | |
7041efe9 | 596 | |
718db961 | 597 | while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { |
7041efe9 | 598 | |
90060676 LP |
599 | if ((!startswith(path, "/dev/") && |
600 | !startswith(path, "block-") && | |
601 | !startswith(path, "char-")) || | |
602 | strpbrk(path, WHITESPACE)) | |
603 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node"); | |
7041efe9 LP |
604 | |
605 | if (isempty(rwm)) | |
606 | rwm = "rwm"; | |
607 | ||
718db961 LP |
608 | if (!in_charset(rwm, "rwm")) |
609 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags"); | |
7041efe9 | 610 | |
7041efe9 | 611 | if (mode != UNIT_CHECK) { |
718db961 | 612 | CGroupDeviceAllow *a = NULL, *b; |
ad7bfffd G |
613 | |
614 | LIST_FOREACH(device_allow, b, c->device_allow) { | |
06eb4e3b | 615 | if (path_equal(b->path, path)) { |
ad7bfffd | 616 | a = b; |
ad7bfffd G |
617 | break; |
618 | } | |
619 | } | |
620 | ||
718db961 | 621 | if (!a) { |
ad7bfffd G |
622 | a = new0(CGroupDeviceAllow, 1); |
623 | if (!a) | |
624 | return -ENOMEM; | |
625 | ||
626 | a->path = strdup(path); | |
627 | if (!a->path) { | |
628 | free(a); | |
629 | return -ENOMEM; | |
630 | } | |
718db961 LP |
631 | |
632 | LIST_PREPEND(device_allow, c->device_allow, a); | |
7041efe9 LP |
633 | } |
634 | ||
635 | a->r = !!strchr(rwm, 'r'); | |
636 | a->w = !!strchr(rwm, 'w'); | |
637 | a->m = !!strchr(rwm, 'm'); | |
7041efe9 LP |
638 | } |
639 | ||
c2756a68 | 640 | n++; |
7041efe9 | 641 | } |
43a99a7a LP |
642 | if (r < 0) |
643 | return r; | |
7041efe9 | 644 | |
9c96019d LP |
645 | r = sd_bus_message_exit_container(message); |
646 | if (r < 0) | |
647 | return r; | |
648 | ||
7041efe9 LP |
649 | if (mode != UNIT_CHECK) { |
650 | _cleanup_free_ char *buf = NULL; | |
651 | _cleanup_fclose_ FILE *f = NULL; | |
652 | CGroupDeviceAllow *a; | |
653 | size_t size = 0; | |
654 | ||
655 | if (n == 0) { | |
656 | while (c->device_allow) | |
657 | cgroup_context_free_device_allow(c, c->device_allow); | |
658 | } | |
659 | ||
3905f127 | 660 | u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES; |
3051f187 | 661 | |
7041efe9 LP |
662 | f = open_memstream(&buf, &size); |
663 | if (!f) | |
664 | return -ENOMEM; | |
665 | ||
666 | fputs("DeviceAllow=\n", f); | |
667 | LIST_FOREACH(device_allow, a, c->device_allow) | |
668 | fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); | |
669 | ||
670 | fflush(f); | |
b9ec9359 | 671 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
672 | } |
673 | ||
b42defe3 | 674 | return 1; |
a931ad47 | 675 | |
03a7b521 LP |
676 | } else if (streq(name, "TasksAccounting")) { |
677 | int b; | |
678 | ||
679 | r = sd_bus_message_read(message, "b", &b); | |
680 | if (r < 0) | |
681 | return r; | |
682 | ||
683 | if (mode != UNIT_CHECK) { | |
684 | c->tasks_accounting = b; | |
685 | u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS; | |
686 | unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); | |
687 | } | |
688 | ||
689 | return 1; | |
690 | ||
691 | } else if (streq(name, "TasksMax")) { | |
692 | uint64_t limit; | |
693 | ||
694 | r = sd_bus_message_read(message, "t", &limit); | |
695 | if (r < 0) | |
696 | return r; | |
697 | ||
698 | if (mode != UNIT_CHECK) { | |
699 | c->tasks_max = limit; | |
700 | u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS; | |
701 | ||
702 | if (limit == (uint64_t) -1) | |
703 | unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); | |
704 | else | |
705 | unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); | |
706 | } | |
707 | ||
708 | return 1; | |
a931ad47 LP |
709 | } |
710 | ||
711 | if (u->transient && u->load_state == UNIT_STUB) { | |
712 | r = bus_cgroup_set_transient_property(u, c, name, message, mode, error); | |
713 | if (r != 0) | |
714 | return r; | |
715 | ||
b42defe3 | 716 | } |
8e2af478 LP |
717 | |
718 | return 0; | |
719 | } |