chiark / gitweb /
ae360eae3348a0d6be3eba422358860bf0e3de67
[elogind.git] / src / core / dbus-cgroup.c
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
24 #include "dbus-cgroup.h"
25
26 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
27
28 static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
29         DBusMessageIter sub, sub2;
30         CGroupContext *c = data;
31         CGroupBlockIODeviceWeight *w;
32
33         assert(i);
34         assert(property);
35         assert(c);
36
37         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
38                 return -ENOMEM;
39
40         LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
41
42                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
43                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) ||
44                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) ||
45                     !dbus_message_iter_close_container(&sub, &sub2))
46                         return -ENOMEM;
47         }
48
49         if (!dbus_message_iter_close_container(i, &sub))
50                 return -ENOMEM;
51
52         return 0;
53 }
54
55 static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
56         DBusMessageIter sub, sub2;
57         CGroupContext *c = data;
58         CGroupBlockIODeviceBandwidth *b;
59
60         assert(i);
61         assert(property);
62         assert(c);
63
64         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
65                 return -ENOMEM;
66
67         LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
68
69                 if (streq(property, "BlockIOReadBandwidth") != b->read)
70                         continue;
71
72                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
73                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) ||
74                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) ||
75                     !dbus_message_iter_close_container(&sub, &sub2))
76                         return -ENOMEM;
77         }
78
79         if (!dbus_message_iter_close_container(i, &sub))
80                 return -ENOMEM;
81
82         return 0;
83 }
84
85 static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
86         DBusMessageIter sub, sub2;
87         CGroupContext *c = data;
88         CGroupDeviceAllow *a;
89
90         assert(i);
91         assert(property);
92         assert(c);
93
94         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
95                 return -ENOMEM;
96
97         LIST_FOREACH(device_allow, a, c->device_allow) {
98                 const char *rwm;
99                 char buf[4];
100                 unsigned k = 0;
101
102                 if (a->r)
103                         buf[k++] = 'r';
104                 if (a->w)
105                         buf[k++] = 'w';
106                 if (a->m)
107                         buf[k++] = 'm';
108
109                 buf[k] = 0;
110                 rwm = buf;
111
112                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
113                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) ||
114                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) ||
115                     !dbus_message_iter_close_container(&sub, &sub2))
116                         return -ENOMEM;
117         }
118
119         if (!dbus_message_iter_close_container(i, &sub))
120                 return -ENOMEM;
121
122         return 0;
123 }
124
125 const BusProperty bus_cgroup_context_properties[] = {
126         { "CPUAccounting",           bus_property_append_bool,            "b",     offsetof(CGroupContext, cpu_accounting)     },
127         { "CPUShares",               bus_property_append_ul,              "t",     offsetof(CGroupContext, cpu_shares)         },
128         { "BlockIOAccounting",       bus_property_append_bool,            "b",     offsetof(CGroupContext, blockio_accounting) },
129         { "BlockIOWeight",           bus_property_append_ul,              "t",     offsetof(CGroupContext, blockio_weight)     },
130         { "BlockIODeviceWeight",     bus_cgroup_append_device_weights,    "a(st)", 0                                           },
131         { "BlockIOReadBandwidth",    bus_cgroup_append_device_bandwidths, "a(st)", 0                                           },
132         { "BlockIOWriteBandwidth",   bus_cgroup_append_device_bandwidths, "a(st)", 0                                           },
133         { "MemoryAccounting",        bus_property_append_bool,            "b",     offsetof(CGroupContext, memory_accounting)  },
134         { "MemoryLimit",             bus_property_append_uint64,          "t",     offsetof(CGroupContext, memory_limit)       },
135         { "MemorySoftLimit",         bus_property_append_uint64,          "t",     offsetof(CGroupContext, memory_soft_limit)  },
136         { "DevicePolicy",            bus_cgroup_append_device_policy,     "s",     offsetof(CGroupContext, device_policy)      },
137         { "DeviceAllow",             bus_cgroup_append_device_allow,      "a(ss)", 0                                           },
138         {}
139 };
140
141 int bus_cgroup_set_property(
142                 Unit *u,
143                 CGroupContext *c,
144                 const char *name,
145                 DBusMessageIter *i,
146                 UnitSetPropertiesMode mode,
147                 DBusError *error) {
148
149         assert(name);
150         assert(u);
151         assert(c);
152         assert(i);
153
154         if (streq(name, "CPUAccounting")) {
155
156                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
157                         return -EINVAL;
158
159                 if (mode != UNIT_CHECK) {
160                         dbus_bool_t b;
161                         dbus_message_iter_get_basic(i, &b);
162
163                         c->cpu_accounting = b;
164                         unit_write_drop_in_private_section(u, mode, "cpu-accounting", b ? "CPUAccounting=yes" : "CPUAccounting=no");
165                 }
166
167                 return 1;
168
169         } else if (streq(name, "CPUShares")) {
170                 uint64_t u64;
171                 unsigned long ul;
172
173                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
174                         return -EINVAL;
175
176                 dbus_message_iter_get_basic(i, &u64);
177                 ul = (unsigned long) u64;
178
179                 if (u64 <= 0 || u64 != (uint64_t) ul)
180                         return -EINVAL;
181
182                 if (mode != UNIT_CHECK) {
183                         char buf[sizeof("CPUShares=") + DECIMAL_STR_MAX(ul)];
184                         c->cpu_shares = ul;
185
186                         sprintf(buf, "CPUShares=%lu", ul);
187                         unit_write_drop_in_private_section(u, mode, "cpu-shares", buf);
188                 }
189
190                 return 1;
191
192         } else if (streq(name, "BlockIOAccounting")) {
193
194                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
195                         return -EINVAL;
196
197                 if (mode != UNIT_CHECK) {
198                         dbus_bool_t b;
199                         dbus_message_iter_get_basic(i, &b);
200
201                         c->blockio_accounting = b;
202                         unit_write_drop_in_private_section(u, mode, "block-io-accounting", b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
203                 }
204
205                 return 1;
206
207         } else if (streq(name, "BlockIOWeight")) {
208                 uint64_t u64;
209                 unsigned long ul;
210
211                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
212                         return -EINVAL;
213
214                 dbus_message_iter_get_basic(i, &u64);
215                 ul = (unsigned long) u64;
216
217                 if (u64 < 10 || u64 > 1000)
218                         return -EINVAL;
219
220                 if (mode != UNIT_CHECK) {
221                         char buf[sizeof("BlockIOWeight=") + DECIMAL_STR_MAX(ul)];
222                         c->cpu_shares = ul;
223
224                         sprintf(buf, "BlockIOWeight=%lu", ul);
225                         unit_write_drop_in_private_section(u, mode, "blockio-weight", buf);
226                 }
227
228                 return 1;
229
230         } else if (streq(name, "MemoryAccounting")) {
231
232                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
233                         return -EINVAL;
234
235                 if (mode != UNIT_CHECK) {
236                         dbus_bool_t b;
237                         dbus_message_iter_get_basic(i, &b);
238
239                         c->memory_accounting = b;
240                         unit_write_drop_in_private_section(u, mode, "memory-accounting", b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
241                 }
242
243                 return 1;
244
245         } else if (streq(name, "MemoryLimit") || streq(name, "MemorySoftLimit")) {
246
247                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
248                         return -EINVAL;
249
250                 if (mode != UNIT_CHECK) {
251                         uint64_t limit;
252                         char buf[sizeof("MemorySoftLimit=") + DECIMAL_STR_MAX(limit)];
253
254                         dbus_message_iter_get_basic(i, &limit);
255
256                         if (streq(name, "MemoryLimit")) {
257                                 c->memory_limit = limit;
258                                 sprintf(buf, "MemoryLimit=%" PRIu64, limit);
259                                 unit_write_drop_in_private_section(u, mode, "memory-limit", buf);
260                         } else {
261                                 c->memory_soft_limit = limit;
262                                 sprintf(buf, "MemorySoftLimit=%" PRIu64, limit);
263                                 unit_write_drop_in_private_section(u, mode, "memory-soft-limit", buf);
264                         }
265                 }
266
267                 return 1;
268         }
269
270         return 0;
271 }