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