chiark / gitweb /
rtnl: drop "sd_" prefix from cleanup macros
[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 "bus-util.h"
23 #include "path-util.h"
24 #include "cgroup-util.h"
25 #include "cgroup.h"
26 #include "dbus-cgroup.h"
27
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,
36                 void *userdata,
37                 sd_bus_error *error) {
38
39         CGroupContext *c = userdata;
40         CGroupBlockIODeviceWeight *w;
41         int r;
42
43         assert(bus);
44         assert(reply);
45         assert(c);
46
47         r = sd_bus_message_open_container(reply, 'a', "(st)");
48         if (r < 0)
49                 return r;
50
51         LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
52                 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
53                 if (r < 0)
54                         return r;
55         }
56
57         return sd_bus_message_close_container(reply);
58 }
59
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,
66                 void *userdata,
67                 sd_bus_error *error) {
68
69         CGroupContext *c = userdata;
70         CGroupBlockIODeviceBandwidth *b;
71         int r;
72
73         assert(bus);
74         assert(reply);
75         assert(c);
76
77         r = sd_bus_message_open_container(reply, 'a', "(st)");
78         if (r < 0)
79                 return r;
80
81         LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
82
83                 if (streq(property, "BlockIOReadBandwidth") != b->read)
84                         continue;
85
86                 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
87                 if (r < 0)
88                         return r;
89         }
90
91         return sd_bus_message_close_container(reply);
92 }
93
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,
100                 void *userdata,
101                 sd_bus_error *error) {
102
103         CGroupContext *c = userdata;
104         CGroupDeviceAllow *a;
105         int r;
106
107         assert(bus);
108         assert(reply);
109         assert(c);
110
111         r = sd_bus_message_open_container(reply, 'a', "(ss)");
112         if (r < 0)
113                 return r;
114
115         LIST_FOREACH(device_allow, a, c->device_allow) {
116                 unsigned k = 0;
117                 char rwm[4];
118
119                 if (a->r)
120                         rwm[k++] = 'r';
121                 if (a->w)
122                         rwm[k++] = 'w';
123                 if (a->m)
124                         rwm[k++] = 'm';
125
126                 rwm[k] = 0;
127
128                 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
129                 if (r < 0)
130                         return r;
131         }
132
133         return sd_bus_message_close_container(reply);
134 }
135
136 const sd_bus_vtable bus_cgroup_vtable[] = {
137         SD_BUS_VTABLE_START(0),
138         SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
139         SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
140         SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
141         SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
142         SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
143         SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
144         SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
145         SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
146         SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
147         SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
148         SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
149         SD_BUS_VTABLE_END
150 };
151
152 int bus_cgroup_set_property(
153                 Unit *u,
154                 CGroupContext *c,
155                 const char *name,
156                 sd_bus_message *message,
157                 UnitSetPropertiesMode mode,
158                 sd_bus_error *error) {
159
160         int r;
161
162         assert(u);
163         assert(c);
164         assert(name);
165         assert(message);
166
167         if (streq(name, "CPUAccounting")) {
168                 int b;
169
170                 r = sd_bus_message_read(message, "b", &b);
171                 if (r < 0)
172                         return r;
173
174                 if (mode != UNIT_CHECK) {
175                         c->cpu_accounting = b;
176                         unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
177                 }
178
179                 return 1;
180
181         } else if (streq(name, "CPUShares")) {
182                 uint64_t u64;
183                 unsigned long ul;
184
185                 r = sd_bus_message_read(message, "t", &u64);
186                 if (r < 0)
187                         return r;
188
189                 ul = (unsigned long) u64;
190                 if (ul <= 0 || (uint64_t) ul != u64)
191                         return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
192
193                 if (mode != UNIT_CHECK) {
194                         c->cpu_shares = ul;
195                         unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
196                 }
197
198                 return 1;
199
200         } else if (streq(name, "BlockIOAccounting")) {
201                 int b;
202
203                 r = sd_bus_message_read(message, "b", &b);
204                 if (r < 0)
205                         return r;
206
207                 if (mode != UNIT_CHECK) {
208                         c->blockio_accounting = b;
209                         unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
210                 }
211
212                 return 1;
213
214         } else if (streq(name, "BlockIOWeight")) {
215                 uint64_t u64;
216                 unsigned long ul;
217
218                 r = sd_bus_message_read(message, "t", &u64);
219                 if (r < 0)
220                         return r;
221
222                 ul = (unsigned long) u64;
223                 if (ul < 10 || ul > 1000)
224                         return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
225
226                 if (mode != UNIT_CHECK) {
227                         c->blockio_weight = ul;
228                         unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
229                 }
230
231                 return 1;
232
233         } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
234                 const char *path;
235                 bool read = true;
236                 unsigned n = 0;
237                 uint64_t u64;
238
239                 if (streq(name, "BlockIOWriteBandwidth"))
240                         read = false;
241
242                 r = sd_bus_message_enter_container(message, 'a', "(st)");
243                 if (r < 0)
244                         return r;
245
246                 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
247
248                         if (mode != UNIT_CHECK) {
249                                 CGroupBlockIODeviceBandwidth *a = NULL, *b;
250
251                                 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
252                                         if (path_equal(path, b->path) && read == b->read) {
253                                                 a = b;
254                                                 break;
255                                         }
256                                 }
257
258                                 if (!a) {
259                                         a = new0(CGroupBlockIODeviceBandwidth, 1);
260                                         if (!a)
261                                                 return -ENOMEM;
262
263                                         a->read = read;
264                                         a->path = strdup(path);
265                                         if (!a->path) {
266                                                 free(a);
267                                                 return -ENOMEM;
268                                         }
269
270                                         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
271                                 }
272
273                                 a->bandwidth = u64;
274                         }
275
276                         n++;
277                 }
278                 if (r < 0)
279                         return r;
280
281                 if (mode != UNIT_CHECK) {
282                         CGroupBlockIODeviceBandwidth *a, *next;
283                         _cleanup_free_ char *buf = NULL;
284                         _cleanup_fclose_ FILE *f = NULL;
285                         size_t size = 0;
286
287                         if (n == 0) {
288                                 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
289                                         if (a->read == read)
290                                                 cgroup_context_free_blockio_device_bandwidth(c, a);
291                         }
292
293                         f = open_memstream(&buf, &size);
294                         if (!f)
295                                 return -ENOMEM;
296
297                          if (read) {
298                                 fputs("BlockIOReadBandwidth=\n", f);
299                                  LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
300                                         if (a->read)
301                                                 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
302                         } else {
303                                 fputs("BlockIOWriteBandwidth=\n", f);
304                                 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
305                                         if (!a->read)
306                                                 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
307                         }
308
309                         fflush(f);
310                         unit_write_drop_in_private(u, mode, name, buf);
311                 }
312
313                 return 1;
314
315         } else if (streq(name, "BlockIODeviceWeight")) {
316                 const char *path;
317                 uint64_t u64;
318                 unsigned n = 0;
319
320                 r = sd_bus_message_enter_container(message, 'a', "(st)");
321                 if (r < 0)
322                         return r;
323
324                 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
325                         unsigned long ul = u64;
326
327                         if (ul < 10 || ul > 1000)
328                                 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
329
330                         if (mode != UNIT_CHECK) {
331                                 CGroupBlockIODeviceWeight *a = NULL, *b;
332
333                                 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
334                                         if (path_equal(b->path, path)) {
335                                                 a = b;
336                                                 break;
337                                         }
338                                 }
339
340                                 if (!a) {
341                                         a = new0(CGroupBlockIODeviceWeight, 1);
342                                         if (!a)
343                                                 return -ENOMEM;
344
345                                         a->path = strdup(path);
346                                         if (!a->path) {
347                                                 free(a);
348                                                 return -ENOMEM;
349                                         }
350                                         LIST_PREPEND(device_weights,c->blockio_device_weights, a);
351                                 }
352
353                                 a->weight = ul;
354                         }
355
356                         n++;
357                 }
358
359                 if (mode != UNIT_CHECK) {
360                         _cleanup_free_ char *buf = NULL;
361                         _cleanup_fclose_ FILE *f = NULL;
362                         CGroupBlockIODeviceWeight *a;
363                         size_t size = 0;
364
365                         if (n == 0) {
366                                 while (c->blockio_device_weights)
367                                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
368                         }
369
370                         f = open_memstream(&buf, &size);
371                         if (!f)
372                                 return -ENOMEM;
373
374                         fputs("BlockIODeviceWeight=\n", f);
375                         LIST_FOREACH(device_weights, a, c->blockio_device_weights)
376                                 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
377
378                         fflush(f);
379                         unit_write_drop_in_private(u, mode, name, buf);
380                 }
381
382                 return 1;
383
384         } else if (streq(name, "MemoryAccounting")) {
385                 int b;
386
387                 r = sd_bus_message_read(message, "b", &b);
388                 if (r < 0)
389                         return r;
390
391                 if (mode != UNIT_CHECK) {
392                         c->memory_accounting = b;
393                         unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
394                 }
395
396                 return 1;
397
398         } else if (streq(name, "MemoryLimit")) {
399                 uint64_t limit;
400
401                 r = sd_bus_message_read(message, "t", &limit);
402                 if (r < 0)
403                         return r;
404
405                 if (mode != UNIT_CHECK) {
406                         c->memory_limit = limit;
407                         unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
408                 }
409
410                 return 1;
411
412         } else if (streq(name, "DevicePolicy")) {
413                 const char *policy;
414                 CGroupDevicePolicy p;
415
416                 r = sd_bus_message_read(message, "s", &policy);
417                 if (r < 0)
418                         return r;
419
420                 p = cgroup_device_policy_from_string(policy);
421                 if (p < 0)
422                         return -EINVAL;
423
424                 if (mode != UNIT_CHECK) {
425                         char *buf;
426
427                         c->device_policy = p;
428
429                         buf = strappenda("DevicePolicy=", policy);
430                         unit_write_drop_in_private(u, mode, name, buf);
431                 }
432
433                 return 1;
434
435         } else if (streq(name, "DeviceAllow")) {
436                 const char *path, *rwm;
437                 unsigned n = 0;
438
439                 r = sd_bus_message_enter_container(message, 'a', "(ss)");
440                 if (r < 0)
441                         return r;
442
443                 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
444
445                         if (!path_startswith(path, "/dev"))
446                                 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
447
448                         if (isempty(rwm))
449                                 rwm = "rwm";
450
451                         if (!in_charset(rwm, "rwm"))
452                                 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
453
454                         if (mode != UNIT_CHECK) {
455                                 CGroupDeviceAllow *a = NULL, *b;
456
457                                 LIST_FOREACH(device_allow, b, c->device_allow) {
458                                         if (path_equal(b->path, path)) {
459                                                 a = b;
460                                                 break;
461                                         }
462                                 }
463
464                                 if (!a) {
465                                         a = new0(CGroupDeviceAllow, 1);
466                                         if (!a)
467                                                 return -ENOMEM;
468
469                                         a->path = strdup(path);
470                                         if (!a->path) {
471                                                 free(a);
472                                                 return -ENOMEM;
473                                         }
474
475                                         LIST_PREPEND(device_allow, c->device_allow, a);
476                                 }
477
478                                 a->r = !!strchr(rwm, 'r');
479                                 a->w = !!strchr(rwm, 'w');
480                                 a->m = !!strchr(rwm, 'm');
481
482                         }
483
484                         n++;
485                 }
486                 if (r < 0)
487                         return r;
488
489                 if (mode != UNIT_CHECK) {
490                         _cleanup_free_ char *buf = NULL;
491                         _cleanup_fclose_ FILE *f = NULL;
492                         CGroupDeviceAllow *a;
493                         size_t size = 0;
494
495                         if (n == 0) {
496                                 while (c->device_allow)
497                                         cgroup_context_free_device_allow(c, c->device_allow);
498                         }
499
500                         f = open_memstream(&buf, &size);
501                         if (!f)
502                                 return -ENOMEM;
503
504                         fputs("DeviceAllow=\n", f);
505                         LIST_FOREACH(device_allow, a, c->device_allow)
506                                 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
507
508                         fflush(f);
509                         unit_write_drop_in_private(u, mode, name, buf);
510                 }
511
512                 return 1;
513         }
514
515         return 0;
516 }