]>
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 | ||
b5efdb8a | 22 | #include "alloc-util.h" |
718db961 | 23 | #include "bus-util.h" |
718db961 LP |
24 | #include "cgroup-util.h" |
25 | #include "cgroup.h" | |
4ad49000 | 26 | #include "dbus-cgroup.h" |
3ffd4af2 | 27 | #include "fd-util.h" |
0d39fa9c | 28 | #include "fileio.h" |
3ffd4af2 | 29 | #include "path-util.h" |
4ad49000 | 30 | |
718db961 LP |
31 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); |
32 | ||
33 | static int property_get_blockio_device_weight( | |
34 | sd_bus *bus, | |
35 | const char *path, | |
36 | const char *interface, | |
37 | const char *property, | |
38 | sd_bus_message *reply, | |
ebcf1f97 LP |
39 | void *userdata, |
40 | sd_bus_error *error) { | |
4ad49000 | 41 | |
718db961 | 42 | CGroupContext *c = userdata; |
4ad49000 | 43 | CGroupBlockIODeviceWeight *w; |
718db961 | 44 | int r; |
4ad49000 | 45 | |
718db961 LP |
46 | assert(bus); |
47 | assert(reply); | |
4ad49000 LP |
48 | assert(c); |
49 | ||
718db961 LP |
50 | r = sd_bus_message_open_container(reply, 'a', "(st)"); |
51 | if (r < 0) | |
52 | return r; | |
4ad49000 LP |
53 | |
54 | LIST_FOREACH(device_weights, w, c->blockio_device_weights) { | |
718db961 LP |
55 | r = sd_bus_message_append(reply, "(st)", w->path, w->weight); |
56 | if (r < 0) | |
57 | return r; | |
4ad49000 LP |
58 | } |
59 | ||
718db961 | 60 | return sd_bus_message_close_container(reply); |
4ad49000 LP |
61 | } |
62 | ||
718db961 LP |
63 | static int property_get_blockio_device_bandwidths( |
64 | sd_bus *bus, | |
65 | const char *path, | |
66 | const char *interface, | |
67 | const char *property, | |
68 | sd_bus_message *reply, | |
ebcf1f97 LP |
69 | void *userdata, |
70 | sd_bus_error *error) { | |
718db961 LP |
71 | |
72 | CGroupContext *c = userdata; | |
4ad49000 | 73 | CGroupBlockIODeviceBandwidth *b; |
718db961 | 74 | int r; |
4ad49000 | 75 | |
718db961 LP |
76 | assert(bus); |
77 | assert(reply); | |
4ad49000 LP |
78 | assert(c); |
79 | ||
718db961 LP |
80 | r = sd_bus_message_open_container(reply, 'a', "(st)"); |
81 | if (r < 0) | |
82 | return r; | |
4ad49000 LP |
83 | |
84 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { | |
85 | ||
86 | if (streq(property, "BlockIOReadBandwidth") != b->read) | |
87 | continue; | |
88 | ||
718db961 LP |
89 | r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth); |
90 | if (r < 0) | |
91 | return r; | |
4ad49000 LP |
92 | } |
93 | ||
718db961 | 94 | return sd_bus_message_close_container(reply); |
4ad49000 LP |
95 | } |
96 | ||
718db961 LP |
97 | static int property_get_device_allow( |
98 | sd_bus *bus, | |
99 | const char *path, | |
100 | const char *interface, | |
101 | const char *property, | |
102 | sd_bus_message *reply, | |
ebcf1f97 LP |
103 | void *userdata, |
104 | sd_bus_error *error) { | |
718db961 LP |
105 | |
106 | CGroupContext *c = userdata; | |
4ad49000 | 107 | CGroupDeviceAllow *a; |
718db961 | 108 | int r; |
4ad49000 | 109 | |
718db961 LP |
110 | assert(bus); |
111 | assert(reply); | |
4ad49000 LP |
112 | assert(c); |
113 | ||
718db961 LP |
114 | r = sd_bus_message_open_container(reply, 'a', "(ss)"); |
115 | if (r < 0) | |
116 | return r; | |
4ad49000 LP |
117 | |
118 | LIST_FOREACH(device_allow, a, c->device_allow) { | |
4ad49000 | 119 | unsigned k = 0; |
718db961 | 120 | char rwm[4]; |
4ad49000 LP |
121 | |
122 | if (a->r) | |
718db961 | 123 | rwm[k++] = 'r'; |
4ad49000 | 124 | if (a->w) |
718db961 | 125 | rwm[k++] = 'w'; |
4ad49000 | 126 | if (a->m) |
718db961 | 127 | rwm[k++] = 'm'; |
4ad49000 | 128 | |
718db961 | 129 | rwm[k] = 0; |
4ad49000 | 130 | |
718db961 LP |
131 | r = sd_bus_message_append(reply, "(ss)", a->path, rwm); |
132 | if (r < 0) | |
133 | return r; | |
4ad49000 LP |
134 | } |
135 | ||
718db961 | 136 | return sd_bus_message_close_container(reply); |
4ad49000 LP |
137 | } |
138 | ||
718db961 LP |
139 | const sd_bus_vtable bus_cgroup_vtable[] = { |
140 | SD_BUS_VTABLE_START(0), | |
a931ad47 | 141 | SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0), |
610f780c | 142 | SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), |
d53d9474 LP |
143 | SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0), |
144 | SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), | |
ee26bcc0 | 145 | SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), |
610f780c | 146 | SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), |
d53d9474 LP |
147 | SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0), |
148 | SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0), | |
610f780c LP |
149 | SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0), |
150 | SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), | |
151 | SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), | |
152 | SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), | |
153 | SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), | |
154 | SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), | |
155 | SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), | |
03a7b521 LP |
156 | SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0), |
157 | SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0), | |
718db961 | 158 | SD_BUS_VTABLE_END |
4ad49000 | 159 | }; |
8e2af478 | 160 | |
a931ad47 LP |
161 | static int bus_cgroup_set_transient_property( |
162 | Unit *u, | |
163 | CGroupContext *c, | |
164 | const char *name, | |
165 | sd_bus_message *message, | |
166 | UnitSetPropertiesMode mode, | |
167 | sd_bus_error *error) { | |
168 | ||
169 | int r; | |
170 | ||
171 | assert(u); | |
172 | assert(c); | |
173 | assert(name); | |
174 | assert(message); | |
175 | ||
176 | if (streq(name, "Delegate")) { | |
177 | int b; | |
178 | ||
179 | r = sd_bus_message_read(message, "b", &b); | |
180 | if (r < 0) | |
181 | return r; | |
182 | ||
183 | if (mode != UNIT_CHECK) { | |
184 | c->delegate = b; | |
185 | unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no"); | |
186 | } | |
187 | ||
188 | return 1; | |
189 | } | |
190 | ||
191 | return 0; | |
192 | } | |
193 | ||
8e2af478 LP |
194 | int bus_cgroup_set_property( |
195 | Unit *u, | |
196 | CGroupContext *c, | |
197 | const char *name, | |
718db961 | 198 | sd_bus_message *message, |
8e2af478 | 199 | UnitSetPropertiesMode mode, |
718db961 LP |
200 | sd_bus_error *error) { |
201 | ||
202 | int r; | |
8e2af478 | 203 | |
8e2af478 LP |
204 | assert(u); |
205 | assert(c); | |
718db961 LP |
206 | assert(name); |
207 | assert(message); | |
8e2af478 LP |
208 | |
209 | if (streq(name, "CPUAccounting")) { | |
718db961 | 210 | int b; |
8e2af478 | 211 | |
718db961 LP |
212 | r = sd_bus_message_read(message, "b", &b); |
213 | if (r < 0) | |
214 | return r; | |
8e2af478 LP |
215 | |
216 | if (mode != UNIT_CHECK) { | |
8e2af478 | 217 | c->cpu_accounting = b; |
e7ab4d1a | 218 | unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU); |
b9ec9359 | 219 | unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); |
b42defe3 LP |
220 | } |
221 | ||
222 | return 1; | |
223 | ||
224 | } else if (streq(name, "CPUShares")) { | |
d53d9474 | 225 | uint64_t shares; |
b42defe3 | 226 | |
d53d9474 | 227 | r = sd_bus_message_read(message, "t", &shares); |
718db961 LP |
228 | if (r < 0) |
229 | return r; | |
b42defe3 | 230 | |
d53d9474 LP |
231 | if (!CGROUP_CPU_SHARES_IS_OK(shares)) |
232 | return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); | |
b42defe3 LP |
233 | |
234 | if (mode != UNIT_CHECK) { | |
d53d9474 | 235 | c->cpu_shares = shares; |
e7ab4d1a | 236 | unit_invalidate_cgroup(u, CGROUP_MASK_CPU); |
d53d9474 LP |
237 | |
238 | if (shares == CGROUP_CPU_SHARES_INVALID) | |
239 | unit_write_drop_in_private(u, mode, name, "CPUShares="); | |
240 | else | |
241 | unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares); | |
8e2af478 LP |
242 | } |
243 | ||
244 | return 1; | |
245 | ||
95ae05c0 | 246 | } else if (streq(name, "StartupCPUShares")) { |
d53d9474 | 247 | uint64_t shares; |
95ae05c0 | 248 | |
d53d9474 | 249 | r = sd_bus_message_read(message, "t", &shares); |
95ae05c0 WC |
250 | if (r < 0) |
251 | return r; | |
252 | ||
d53d9474 LP |
253 | if (!CGROUP_CPU_SHARES_IS_OK(shares)) |
254 | return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); | |
95ae05c0 WC |
255 | |
256 | if (mode != UNIT_CHECK) { | |
d53d9474 | 257 | c->startup_cpu_shares = shares; |
e7ab4d1a | 258 | unit_invalidate_cgroup(u, CGROUP_MASK_CPU); |
d53d9474 LP |
259 | |
260 | if (shares == CGROUP_CPU_SHARES_INVALID) | |
261 | unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); | |
262 | else | |
263 | unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares); | |
95ae05c0 WC |
264 | } |
265 | ||
266 | return 1; | |
267 | ||
b2f8b02e LP |
268 | } else if (streq(name, "CPUQuotaPerSecUSec")) { |
269 | uint64_t u64; | |
270 | ||
271 | r = sd_bus_message_read(message, "t", &u64); | |
272 | if (r < 0) | |
273 | return r; | |
274 | ||
275 | if (u64 <= 0) | |
276 | return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range"); | |
277 | ||
278 | if (mode != UNIT_CHECK) { | |
279 | c->cpu_quota_per_sec_usec = u64; | |
e7ab4d1a | 280 | unit_invalidate_cgroup(u, CGROUP_MASK_CPU); |
b2f8b02e LP |
281 | unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000)); |
282 | } | |
283 | ||
284 | return 1; | |
285 | ||
8e2af478 | 286 | } else if (streq(name, "BlockIOAccounting")) { |
718db961 | 287 | int b; |
8e2af478 | 288 | |
718db961 LP |
289 | r = sd_bus_message_read(message, "b", &b); |
290 | if (r < 0) | |
291 | return r; | |
8e2af478 LP |
292 | |
293 | if (mode != UNIT_CHECK) { | |
8e2af478 | 294 | c->blockio_accounting = b; |
e7ab4d1a | 295 | unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); |
b9ec9359 | 296 | unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); |
8e2af478 LP |
297 | } |
298 | ||
299 | return 1; | |
b42defe3 LP |
300 | |
301 | } else if (streq(name, "BlockIOWeight")) { | |
d53d9474 | 302 | uint64_t weight; |
b42defe3 | 303 | |
d53d9474 | 304 | r = sd_bus_message_read(message, "t", &weight); |
718db961 LP |
305 | if (r < 0) |
306 | return r; | |
b42defe3 | 307 | |
d53d9474 LP |
308 | if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight)) |
309 | return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); | |
b42defe3 LP |
310 | |
311 | if (mode != UNIT_CHECK) { | |
d53d9474 | 312 | c->blockio_weight = weight; |
e7ab4d1a | 313 | unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); |
d53d9474 LP |
314 | |
315 | if (weight == CGROUP_BLKIO_WEIGHT_INVALID) | |
316 | unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); | |
317 | else | |
318 | unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight); | |
b42defe3 LP |
319 | } |
320 | ||
321 | return 1; | |
95ae05c0 WC |
322 | |
323 | } else if (streq(name, "StartupBlockIOWeight")) { | |
d53d9474 | 324 | uint64_t weight; |
95ae05c0 | 325 | |
d53d9474 | 326 | r = sd_bus_message_read(message, "t", &weight); |
95ae05c0 WC |
327 | if (r < 0) |
328 | return r; | |
329 | ||
d53d9474 LP |
330 | if (CGROUP_BLKIO_WEIGHT_IS_OK(weight)) |
331 | return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); | |
95ae05c0 WC |
332 | |
333 | if (mode != UNIT_CHECK) { | |
d53d9474 | 334 | c->startup_blockio_weight = weight; |
e7ab4d1a | 335 | unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); |
d53d9474 LP |
336 | |
337 | if (weight == CGROUP_BLKIO_WEIGHT_INVALID) | |
338 | unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); | |
339 | else | |
340 | unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight); | |
95ae05c0 WC |
341 | } |
342 | ||
343 | return 1; | |
b42defe3 | 344 | |
f004c2ca | 345 | } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { |
718db961 | 346 | const char *path; |
f004c2ca | 347 | bool read = true; |
718db961 LP |
348 | unsigned n = 0; |
349 | uint64_t u64; | |
f004c2ca G |
350 | |
351 | if (streq(name, "BlockIOWriteBandwidth")) | |
352 | read = false; | |
353 | ||
718db961 LP |
354 | r = sd_bus_message_enter_container(message, 'a', "(st)"); |
355 | if (r < 0) | |
356 | return r; | |
f004c2ca | 357 | |
718db961 | 358 | while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { |
f004c2ca G |
359 | |
360 | if (mode != UNIT_CHECK) { | |
718db961 | 361 | CGroupBlockIODeviceBandwidth *a = NULL, *b; |
f004c2ca G |
362 | |
363 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { | |
364 | if (path_equal(path, b->path) && read == b->read) { | |
365 | a = b; | |
f004c2ca G |
366 | break; |
367 | } | |
368 | } | |
369 | ||
718db961 | 370 | if (!a) { |
f004c2ca G |
371 | a = new0(CGroupBlockIODeviceBandwidth, 1); |
372 | if (!a) | |
373 | return -ENOMEM; | |
374 | ||
375 | a->read = read; | |
376 | a->path = strdup(path); | |
377 | if (!a->path) { | |
378 | free(a); | |
379 | return -ENOMEM; | |
380 | } | |
718db961 LP |
381 | |
382 | LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); | |
f004c2ca G |
383 | } |
384 | ||
385 | a->bandwidth = u64; | |
f004c2ca G |
386 | } |
387 | ||
388 | n++; | |
f004c2ca | 389 | } |
718db961 LP |
390 | if (r < 0) |
391 | return r; | |
f004c2ca | 392 | |
9c96019d LP |
393 | r = sd_bus_message_exit_container(message); |
394 | if (r < 0) | |
395 | return r; | |
396 | ||
f004c2ca | 397 | if (mode != UNIT_CHECK) { |
718db961 | 398 | CGroupBlockIODeviceBandwidth *a, *next; |
f004c2ca G |
399 | _cleanup_free_ char *buf = NULL; |
400 | _cleanup_fclose_ FILE *f = NULL; | |
f004c2ca G |
401 | size_t size = 0; |
402 | ||
403 | if (n == 0) { | |
404 | LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths) | |
405 | if (a->read == read) | |
406 | cgroup_context_free_blockio_device_bandwidth(c, a); | |
407 | } | |
408 | ||
e7ab4d1a | 409 | unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); |
3051f187 | 410 | |
f004c2ca G |
411 | f = open_memstream(&buf, &size); |
412 | if (!f) | |
413 | return -ENOMEM; | |
414 | ||
7d6884b6 | 415 | if (read) { |
f004c2ca | 416 | fputs("BlockIOReadBandwidth=\n", f); |
7d6884b6 | 417 | LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) |
f004c2ca G |
418 | if (a->read) |
419 | fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); | |
420 | } else { | |
421 | fputs("BlockIOWriteBandwidth=\n", f); | |
422 | LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) | |
423 | if (!a->read) | |
424 | fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); | |
425 | } | |
426 | ||
1f2f874c NC |
427 | r = fflush_and_check(f); |
428 | if (r < 0) | |
429 | return r; | |
6f68ecb4 G |
430 | unit_write_drop_in_private(u, mode, name, buf); |
431 | } | |
432 | ||
433 | return 1; | |
434 | ||
435 | } else if (streq(name, "BlockIODeviceWeight")) { | |
718db961 | 436 | const char *path; |
d53d9474 | 437 | uint64_t weight; |
6f68ecb4 G |
438 | unsigned n = 0; |
439 | ||
718db961 LP |
440 | r = sd_bus_message_enter_container(message, 'a', "(st)"); |
441 | if (r < 0) | |
442 | return r; | |
6f68ecb4 | 443 | |
d53d9474 | 444 | while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { |
6f68ecb4 | 445 | |
d53d9474 | 446 | if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID) |
718db961 | 447 | return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); |
6f68ecb4 G |
448 | |
449 | if (mode != UNIT_CHECK) { | |
718db961 | 450 | CGroupBlockIODeviceWeight *a = NULL, *b; |
6f68ecb4 G |
451 | |
452 | LIST_FOREACH(device_weights, b, c->blockio_device_weights) { | |
453 | if (path_equal(b->path, path)) { | |
454 | a = b; | |
6f68ecb4 G |
455 | break; |
456 | } | |
457 | } | |
458 | ||
718db961 | 459 | if (!a) { |
6f68ecb4 G |
460 | a = new0(CGroupBlockIODeviceWeight, 1); |
461 | if (!a) | |
462 | return -ENOMEM; | |
463 | ||
464 | a->path = strdup(path); | |
465 | if (!a->path) { | |
466 | free(a); | |
467 | return -ENOMEM; | |
468 | } | |
718db961 | 469 | LIST_PREPEND(device_weights,c->blockio_device_weights, a); |
6f68ecb4 G |
470 | } |
471 | ||
d53d9474 | 472 | a->weight = weight; |
6f68ecb4 G |
473 | } |
474 | ||
475 | n++; | |
6f68ecb4 G |
476 | } |
477 | ||
9c96019d LP |
478 | r = sd_bus_message_exit_container(message); |
479 | if (r < 0) | |
480 | return r; | |
481 | ||
6f68ecb4 G |
482 | if (mode != UNIT_CHECK) { |
483 | _cleanup_free_ char *buf = NULL; | |
484 | _cleanup_fclose_ FILE *f = NULL; | |
485 | CGroupBlockIODeviceWeight *a; | |
486 | size_t size = 0; | |
487 | ||
488 | if (n == 0) { | |
489 | while (c->blockio_device_weights) | |
490 | cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); | |
491 | } | |
492 | ||
e7ab4d1a | 493 | unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); |
3051f187 | 494 | |
6f68ecb4 G |
495 | f = open_memstream(&buf, &size); |
496 | if (!f) | |
497 | return -ENOMEM; | |
498 | ||
499 | fputs("BlockIODeviceWeight=\n", f); | |
500 | LIST_FOREACH(device_weights, a, c->blockio_device_weights) | |
d53d9474 | 501 | fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); |
6f68ecb4 | 502 | |
1f2f874c NC |
503 | r = fflush_and_check(f); |
504 | if (r < 0) | |
505 | return r; | |
f004c2ca G |
506 | unit_write_drop_in_private(u, mode, name, buf); |
507 | } | |
508 | ||
509 | return 1; | |
510 | ||
8e2af478 | 511 | } else if (streq(name, "MemoryAccounting")) { |
718db961 | 512 | int b; |
8e2af478 | 513 | |
718db961 LP |
514 | r = sd_bus_message_read(message, "b", &b); |
515 | if (r < 0) | |
516 | return r; | |
8e2af478 LP |
517 | |
518 | if (mode != UNIT_CHECK) { | |
b42defe3 | 519 | c->memory_accounting = b; |
e7ab4d1a | 520 | unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); |
b9ec9359 | 521 | unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); |
8e2af478 LP |
522 | } |
523 | ||
524 | return 1; | |
8e2af478 | 525 | |
ddca82ac | 526 | } else if (streq(name, "MemoryLimit")) { |
718db961 | 527 | uint64_t limit; |
b42defe3 | 528 | |
718db961 LP |
529 | r = sd_bus_message_read(message, "t", &limit); |
530 | if (r < 0) | |
531 | return r; | |
b42defe3 LP |
532 | |
533 | if (mode != UNIT_CHECK) { | |
ddca82ac | 534 | c->memory_limit = limit; |
e7ab4d1a | 535 | unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); |
03a7b521 LP |
536 | |
537 | if (limit == (uint64_t) -1) | |
538 | unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); | |
539 | else | |
540 | unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit); | |
b42defe3 LP |
541 | } |
542 | ||
7041efe9 LP |
543 | return 1; |
544 | ||
545 | } else if (streq(name, "DevicePolicy")) { | |
546 | const char *policy; | |
547 | CGroupDevicePolicy p; | |
548 | ||
718db961 LP |
549 | r = sd_bus_message_read(message, "s", &policy); |
550 | if (r < 0) | |
551 | return r; | |
7041efe9 | 552 | |
7041efe9 LP |
553 | p = cgroup_device_policy_from_string(policy); |
554 | if (p < 0) | |
555 | return -EINVAL; | |
556 | ||
557 | if (mode != UNIT_CHECK) { | |
558 | char *buf; | |
559 | ||
560 | c->device_policy = p; | |
e7ab4d1a | 561 | unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); |
7041efe9 | 562 | |
63c372cb | 563 | buf = strjoina("DevicePolicy=", policy); |
b9ec9359 | 564 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
565 | } |
566 | ||
567 | return 1; | |
568 | ||
569 | } else if (streq(name, "DeviceAllow")) { | |
718db961 | 570 | const char *path, *rwm; |
7041efe9 LP |
571 | unsigned n = 0; |
572 | ||
718db961 LP |
573 | r = sd_bus_message_enter_container(message, 'a', "(ss)"); |
574 | if (r < 0) | |
575 | return r; | |
7041efe9 | 576 | |
718db961 | 577 | while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { |
7041efe9 | 578 | |
90060676 LP |
579 | if ((!startswith(path, "/dev/") && |
580 | !startswith(path, "block-") && | |
581 | !startswith(path, "char-")) || | |
582 | strpbrk(path, WHITESPACE)) | |
583 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node"); | |
7041efe9 LP |
584 | |
585 | if (isempty(rwm)) | |
586 | rwm = "rwm"; | |
587 | ||
718db961 LP |
588 | if (!in_charset(rwm, "rwm")) |
589 | return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags"); | |
7041efe9 | 590 | |
7041efe9 | 591 | if (mode != UNIT_CHECK) { |
718db961 | 592 | CGroupDeviceAllow *a = NULL, *b; |
ad7bfffd G |
593 | |
594 | LIST_FOREACH(device_allow, b, c->device_allow) { | |
06eb4e3b | 595 | if (path_equal(b->path, path)) { |
ad7bfffd | 596 | a = b; |
ad7bfffd G |
597 | break; |
598 | } | |
599 | } | |
600 | ||
718db961 | 601 | if (!a) { |
ad7bfffd G |
602 | a = new0(CGroupDeviceAllow, 1); |
603 | if (!a) | |
604 | return -ENOMEM; | |
605 | ||
606 | a->path = strdup(path); | |
607 | if (!a->path) { | |
608 | free(a); | |
609 | return -ENOMEM; | |
610 | } | |
718db961 LP |
611 | |
612 | LIST_PREPEND(device_allow, c->device_allow, a); | |
7041efe9 LP |
613 | } |
614 | ||
615 | a->r = !!strchr(rwm, 'r'); | |
616 | a->w = !!strchr(rwm, 'w'); | |
617 | a->m = !!strchr(rwm, 'm'); | |
7041efe9 LP |
618 | } |
619 | ||
c2756a68 | 620 | n++; |
7041efe9 | 621 | } |
43a99a7a LP |
622 | if (r < 0) |
623 | return r; | |
7041efe9 | 624 | |
9c96019d LP |
625 | r = sd_bus_message_exit_container(message); |
626 | if (r < 0) | |
627 | return r; | |
628 | ||
7041efe9 LP |
629 | if (mode != UNIT_CHECK) { |
630 | _cleanup_free_ char *buf = NULL; | |
631 | _cleanup_fclose_ FILE *f = NULL; | |
632 | CGroupDeviceAllow *a; | |
633 | size_t size = 0; | |
634 | ||
635 | if (n == 0) { | |
636 | while (c->device_allow) | |
637 | cgroup_context_free_device_allow(c, c->device_allow); | |
638 | } | |
639 | ||
e7ab4d1a | 640 | unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); |
3051f187 | 641 | |
7041efe9 LP |
642 | f = open_memstream(&buf, &size); |
643 | if (!f) | |
644 | return -ENOMEM; | |
645 | ||
646 | fputs("DeviceAllow=\n", f); | |
647 | LIST_FOREACH(device_allow, a, c->device_allow) | |
648 | fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); | |
649 | ||
1f2f874c NC |
650 | r = fflush_and_check(f); |
651 | if (r < 0) | |
652 | return r; | |
b9ec9359 | 653 | unit_write_drop_in_private(u, mode, name, buf); |
7041efe9 LP |
654 | } |
655 | ||
b42defe3 | 656 | return 1; |
a931ad47 | 657 | |
03a7b521 LP |
658 | } else if (streq(name, "TasksAccounting")) { |
659 | int b; | |
660 | ||
661 | r = sd_bus_message_read(message, "b", &b); | |
662 | if (r < 0) | |
663 | return r; | |
664 | ||
665 | if (mode != UNIT_CHECK) { | |
666 | c->tasks_accounting = b; | |
e7ab4d1a | 667 | unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); |
03a7b521 LP |
668 | unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); |
669 | } | |
670 | ||
671 | return 1; | |
672 | ||
673 | } else if (streq(name, "TasksMax")) { | |
674 | uint64_t limit; | |
675 | ||
676 | r = sd_bus_message_read(message, "t", &limit); | |
677 | if (r < 0) | |
678 | return r; | |
679 | ||
680 | if (mode != UNIT_CHECK) { | |
681 | c->tasks_max = limit; | |
e7ab4d1a | 682 | unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); |
03a7b521 LP |
683 | |
684 | if (limit == (uint64_t) -1) | |
685 | unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); | |
686 | else | |
687 | unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); | |
688 | } | |
689 | ||
690 | return 1; | |
a931ad47 LP |
691 | } |
692 | ||
693 | if (u->transient && u->load_state == UNIT_STUB) { | |
694 | r = bus_cgroup_set_transient_property(u, c, name, message, mode, error); | |
695 | if (r != 0) | |
696 | return r; | |
697 | ||
b42defe3 | 698 | } |
8e2af478 LP |
699 | |
700 | return 0; | |
701 | } |