]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
man: also mention /run/log/journal in systemd-jouranld.service(8)
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
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
22#include <dbus/dbus.h>
23
7041efe9 24#include "path-util.h"
4ad49000
LP
25#include "dbus-cgroup.h"
26
27static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
28
29static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
30 DBusMessageIter sub, sub2;
31 CGroupContext *c = data;
32 CGroupBlockIODeviceWeight *w;
33
34 assert(i);
35 assert(property);
36 assert(c);
37
38 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
39 return -ENOMEM;
40
41 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
42
43 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
44 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) ||
45 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) ||
46 !dbus_message_iter_close_container(&sub, &sub2))
47 return -ENOMEM;
48 }
49
50 if (!dbus_message_iter_close_container(i, &sub))
51 return -ENOMEM;
52
53 return 0;
54}
55
56static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
57 DBusMessageIter sub, sub2;
58 CGroupContext *c = data;
59 CGroupBlockIODeviceBandwidth *b;
60
61 assert(i);
62 assert(property);
63 assert(c);
64
65 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
66 return -ENOMEM;
67
68 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
69
70 if (streq(property, "BlockIOReadBandwidth") != b->read)
71 continue;
72
73 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
74 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) ||
75 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) ||
76 !dbus_message_iter_close_container(&sub, &sub2))
77 return -ENOMEM;
78 }
79
80 if (!dbus_message_iter_close_container(i, &sub))
81 return -ENOMEM;
82
83 return 0;
84}
85
86static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
87 DBusMessageIter sub, sub2;
88 CGroupContext *c = data;
89 CGroupDeviceAllow *a;
90
91 assert(i);
92 assert(property);
93 assert(c);
94
95 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
96 return -ENOMEM;
97
98 LIST_FOREACH(device_allow, a, c->device_allow) {
99 const char *rwm;
100 char buf[4];
101 unsigned k = 0;
102
103 if (a->r)
104 buf[k++] = 'r';
105 if (a->w)
106 buf[k++] = 'w';
107 if (a->m)
108 buf[k++] = 'm';
109
110 buf[k] = 0;
111 rwm = buf;
112
113 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
114 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) ||
115 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) ||
116 !dbus_message_iter_close_container(&sub, &sub2))
117 return -ENOMEM;
118 }
119
120 if (!dbus_message_iter_close_container(i, &sub))
121 return -ENOMEM;
122
123 return 0;
124}
125
126const BusProperty bus_cgroup_context_properties[] = {
127 { "CPUAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, cpu_accounting) },
128 { "CPUShares", bus_property_append_ul, "t", offsetof(CGroupContext, cpu_shares) },
129 { "BlockIOAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, blockio_accounting) },
130 { "BlockIOWeight", bus_property_append_ul, "t", offsetof(CGroupContext, blockio_weight) },
131 { "BlockIODeviceWeight", bus_cgroup_append_device_weights, "a(st)", 0 },
132 { "BlockIOReadBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
133 { "BlockIOWriteBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
134 { "MemoryAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, memory_accounting) },
135 { "MemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_limit) },
136 { "MemorySoftLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_soft_limit) },
137 { "DevicePolicy", bus_cgroup_append_device_policy, "s", offsetof(CGroupContext, device_policy) },
138 { "DeviceAllow", bus_cgroup_append_device_allow, "a(ss)", 0 },
139 {}
140};
8e2af478
LP
141
142int bus_cgroup_set_property(
143 Unit *u,
144 CGroupContext *c,
145 const char *name,
146 DBusMessageIter *i,
147 UnitSetPropertiesMode mode,
148 DBusError *error) {
149
150 assert(name);
151 assert(u);
152 assert(c);
153 assert(i);
154
155 if (streq(name, "CPUAccounting")) {
8e2af478
LP
156
157 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
158 return -EINVAL;
159
160 if (mode != UNIT_CHECK) {
b42defe3 161 dbus_bool_t b;
8e2af478
LP
162 dbus_message_iter_get_basic(i, &b);
163
164 c->cpu_accounting = b;
b9ec9359 165 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
b42defe3
LP
166 }
167
168 return 1;
169
170 } else if (streq(name, "CPUShares")) {
171 uint64_t u64;
172 unsigned long ul;
173
174 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
175 return -EINVAL;
176
177 dbus_message_iter_get_basic(i, &u64);
178 ul = (unsigned long) u64;
179
180 if (u64 <= 0 || u64 != (uint64_t) ul)
181 return -EINVAL;
182
183 if (mode != UNIT_CHECK) {
b42defe3 184 c->cpu_shares = ul;
b9ec9359 185 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
8e2af478
LP
186 }
187
188 return 1;
189
190 } else if (streq(name, "BlockIOAccounting")) {
8e2af478
LP
191
192 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
193 return -EINVAL;
194
195 if (mode != UNIT_CHECK) {
b42defe3 196 dbus_bool_t b;
8e2af478
LP
197 dbus_message_iter_get_basic(i, &b);
198
199 c->blockio_accounting = b;
b9ec9359 200 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
201 }
202
203 return 1;
b42defe3
LP
204
205 } else if (streq(name, "BlockIOWeight")) {
206 uint64_t u64;
207 unsigned long ul;
208
209 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
210 return -EINVAL;
211
212 dbus_message_iter_get_basic(i, &u64);
213 ul = (unsigned long) u64;
214
215 if (u64 < 10 || u64 > 1000)
216 return -EINVAL;
217
218 if (mode != UNIT_CHECK) {
b42defe3 219 c->cpu_shares = ul;
b9ec9359 220 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
b42defe3
LP
221 }
222
223 return 1;
224
8e2af478 225 } else if (streq(name, "MemoryAccounting")) {
8e2af478
LP
226
227 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
228 return -EINVAL;
229
230 if (mode != UNIT_CHECK) {
b42defe3 231 dbus_bool_t b;
8e2af478
LP
232 dbus_message_iter_get_basic(i, &b);
233
b42defe3 234 c->memory_accounting = b;
b9ec9359 235 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
236 }
237
238 return 1;
8e2af478 239
b42defe3
LP
240 } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
241
242 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
243 return -EINVAL;
244
245 if (mode != UNIT_CHECK) {
246 uint64_t limit;
b42defe3
LP
247
248 dbus_message_iter_get_basic(i, &limit);
249
b9ec9359 250 if (streq(name, "MemoryLimit"))
b42defe3 251 c->memory_limit = limit;
b9ec9359 252 else
b42defe3 253 c->memory_soft_limit = limit;
b9ec9359
LP
254
255 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
b42defe3
LP
256 }
257
7041efe9
LP
258 return 1;
259
260 } else if (streq(name, "DevicePolicy")) {
261 const char *policy;
262 CGroupDevicePolicy p;
263
264 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
265 return -EINVAL;
266
267 dbus_message_iter_get_basic(i, &policy);
268 p = cgroup_device_policy_from_string(policy);
269 if (p < 0)
270 return -EINVAL;
271
272 if (mode != UNIT_CHECK) {
273 char *buf;
274
275 c->device_policy = p;
276
277 buf = strappenda("DevicePolicy=", policy);
b9ec9359 278 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
279 }
280
281 return 1;
282
283 } else if (streq(name, "DeviceAllow")) {
284 DBusMessageIter sub;
285 unsigned n = 0;
286
287 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
288 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
289 return -EINVAL;
290
291 dbus_message_iter_recurse(i, &sub);
292 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
293 DBusMessageIter sub2;
294 const char *path, *rwm;
295 CGroupDeviceAllow *a;
296
297 dbus_message_iter_recurse(&sub, &sub2);
298
299 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
300 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
301 return -EINVAL;
302
303 if (!path_startswith(path, "/dev")) {
304 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
305 return -EINVAL;
306 }
307
308 if (isempty(rwm))
309 rwm = "rwm";
310
311 if (!in_charset(rwm, "rwm")) {
312 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
313 return -EINVAL;
314 }
315
7041efe9
LP
316 if (mode != UNIT_CHECK) {
317 a = new0(CGroupDeviceAllow, 1);
318 if (!a)
319 return -ENOMEM;
320
321 a->path = strdup(path);
322 if (!a->path) {
323 free(a);
324 return -ENOMEM;
325 }
326
327 a->r = !!strchr(rwm, 'r');
328 a->w = !!strchr(rwm, 'w');
329 a->m = !!strchr(rwm, 'm');
330
331 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
332 }
333
c2756a68 334 n++;
7041efe9
LP
335 dbus_message_iter_next(&sub);
336 }
337
338 if (mode != UNIT_CHECK) {
339 _cleanup_free_ char *buf = NULL;
340 _cleanup_fclose_ FILE *f = NULL;
341 CGroupDeviceAllow *a;
342 size_t size = 0;
343
344 if (n == 0) {
345 while (c->device_allow)
346 cgroup_context_free_device_allow(c, c->device_allow);
347 }
348
349 f = open_memstream(&buf, &size);
350 if (!f)
351 return -ENOMEM;
352
353 fputs("DeviceAllow=\n", f);
354 LIST_FOREACH(device_allow, a, c->device_allow)
355 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
356
357 fflush(f);
b9ec9359 358 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
359 }
360
b42defe3
LP
361 return 1;
362 }
8e2af478
LP
363
364 return 0;
365}