]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/image-dbus.c
machined,machinectl: add calls for changing container/VM quotas
[thirdparty/systemd.git] / src / machine / image-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 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-label.h"
23 #include "strv.h"
24 #include "bus-util.h"
25 #include "machine-image.h"
26 #include "image-dbus.h"
27
28 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
29
30 int bus_image_method_remove(
31 sd_bus *bus,
32 sd_bus_message *message,
33 void *userdata,
34 sd_bus_error *error) {
35
36 Image *image = userdata;
37 Manager *m = image->userdata;
38 int r;
39
40 assert(bus);
41 assert(message);
42 assert(image);
43
44 r = bus_verify_polkit_async(
45 message,
46 CAP_SYS_ADMIN,
47 "org.freedesktop.machine1.manage-images",
48 false,
49 UID_INVALID,
50 &m->polkit_registry,
51 error);
52 if (r < 0)
53 return r;
54 if (r == 0)
55 return 1; /* Will call us back */
56
57 r = image_remove(image);
58 if (r < 0)
59 return r;
60
61 return sd_bus_reply_method_return(message, NULL);
62 }
63
64 int bus_image_method_rename(
65 sd_bus *bus,
66 sd_bus_message *message,
67 void *userdata,
68 sd_bus_error *error) {
69
70 Image *image = userdata;
71 Manager *m = image->userdata;
72 const char *new_name;
73 int r;
74
75 assert(bus);
76 assert(message);
77 assert(image);
78
79 r = sd_bus_message_read(message, "s", &new_name);
80 if (r < 0)
81 return r;
82
83 if (!image_name_is_valid(new_name))
84 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
85
86 r = bus_verify_polkit_async(
87 message,
88 CAP_SYS_ADMIN,
89 "org.freedesktop.machine1.manage-images",
90 false,
91 UID_INVALID,
92 &m->polkit_registry,
93 error);
94 if (r < 0)
95 return r;
96 if (r == 0)
97 return 1; /* Will call us back */
98
99 r = image_rename(image, new_name);
100 if (r < 0)
101 return r;
102
103 return sd_bus_reply_method_return(message, NULL);
104 }
105
106 int bus_image_method_clone(
107 sd_bus *bus,
108 sd_bus_message *message,
109 void *userdata,
110 sd_bus_error *error) {
111
112 Image *image = userdata;
113 Manager *m = image->userdata;
114 const char *new_name;
115 int r, read_only;
116
117 assert(bus);
118 assert(message);
119 assert(image);
120
121 r = sd_bus_message_read(message, "sb", &new_name, &read_only);
122 if (r < 0)
123 return r;
124
125 if (!image_name_is_valid(new_name))
126 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
127
128 r = bus_verify_polkit_async(
129 message,
130 CAP_SYS_ADMIN,
131 "org.freedesktop.machine1.manage-images",
132 false,
133 UID_INVALID,
134 &m->polkit_registry,
135 error);
136 if (r < 0)
137 return r;
138 if (r == 0)
139 return 1; /* Will call us back */
140
141 r = image_clone(image, new_name, read_only);
142 if (r < 0)
143 return r;
144
145 return sd_bus_reply_method_return(message, NULL);
146 }
147
148 int bus_image_method_mark_read_only(
149 sd_bus *bus,
150 sd_bus_message *message,
151 void *userdata,
152 sd_bus_error *error) {
153
154 Image *image = userdata;
155 Manager *m = image->userdata;
156 int r, read_only;
157
158 assert(bus);
159 assert(message);
160
161 r = sd_bus_message_read(message, "b", &read_only);
162 if (r < 0)
163 return r;
164
165 r = bus_verify_polkit_async(
166 message,
167 CAP_SYS_ADMIN,
168 "org.freedesktop.machine1.manage-images",
169 false,
170 UID_INVALID,
171 &m->polkit_registry,
172 error);
173 if (r < 0)
174 return r;
175 if (r == 0)
176 return 1; /* Will call us back */
177
178 r = image_read_only(image, read_only);
179 if (r < 0)
180 return r;
181
182 return sd_bus_reply_method_return(message, NULL);
183 }
184
185 int bus_image_method_set_limit(
186 sd_bus *bus,
187 sd_bus_message *message,
188 void *userdata,
189 sd_bus_error *error) {
190
191 Image *image = userdata;
192 Manager *m = image->userdata;
193 uint64_t limit;
194 int r;
195
196 assert(bus);
197 assert(message);
198
199 r = sd_bus_message_read(message, "t", &limit);
200 if (r < 0)
201 return r;
202
203 r = bus_verify_polkit_async(
204 message,
205 CAP_SYS_ADMIN,
206 "org.freedesktop.machine1.manage-images",
207 false,
208 UID_INVALID,
209 &m->polkit_registry,
210 error);
211 if (r < 0)
212 return r;
213 if (r == 0)
214 return 1; /* Will call us back */
215
216 r = image_set_limit(image, limit);
217 if (r < 0)
218 return r;
219
220 return sd_bus_reply_method_return(message, NULL);
221 }
222
223 const sd_bus_vtable image_vtable[] = {
224 SD_BUS_VTABLE_START(0),
225 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
226 SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
227 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
228 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
229 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
230 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
231 SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
232 SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
233 SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
234 SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
235 SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
236 SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
237 SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
238 SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
239 SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
240 SD_BUS_VTABLE_END
241 };
242
243 static int image_flush_cache(sd_event_source *s, void *userdata) {
244 Manager *m = userdata;
245 Image *i;
246
247 assert(s);
248 assert(m);
249
250 while ((i = hashmap_steal_first(m->image_cache)))
251 image_unref(i);
252
253 return 0;
254 }
255
256 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
257 _cleanup_free_ char *e = NULL;
258 Manager *m = userdata;
259 Image *image = NULL;
260 const char *p;
261 int r;
262
263 assert(bus);
264 assert(path);
265 assert(interface);
266 assert(found);
267
268 p = startswith(path, "/org/freedesktop/machine1/image/");
269 if (!p)
270 return 0;
271
272 e = bus_label_unescape(p);
273 if (!e)
274 return -ENOMEM;
275
276 image = hashmap_get(m->image_cache, e);
277 if (image) {
278 *found = image;
279 return 1;
280 }
281
282 r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
283 if (r < 0)
284 return r;
285
286 if (!m->image_cache_defer_event) {
287 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
288 if (r < 0)
289 return r;
290
291 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
292 if (r < 0)
293 return r;
294 }
295
296 r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
297 if (r < 0)
298 return r;
299
300 r = image_find(e, &image);
301 if (r <= 0)
302 return r;
303
304 image->userdata = m;
305
306 r = hashmap_put(m->image_cache, image->name, image);
307 if (r < 0) {
308 image_unref(image);
309 return r;
310 }
311
312 *found = image;
313 return 1;
314 }
315
316 char *image_bus_path(const char *name) {
317 _cleanup_free_ char *e = NULL;
318
319 assert(name);
320
321 e = bus_label_escape(name);
322 if (!e)
323 return NULL;
324
325 return strappend("/org/freedesktop/machine1/image/", e);
326 }
327
328 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
329 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
330 _cleanup_strv_free_ char **l = NULL;
331 Image *image;
332 Iterator i;
333 int r;
334
335 assert(bus);
336 assert(path);
337 assert(nodes);
338
339 images = hashmap_new(&string_hash_ops);
340 if (!images)
341 return -ENOMEM;
342
343 r = image_discover(images);
344 if (r < 0)
345 return r;
346
347 HASHMAP_FOREACH(image, images, i) {
348 char *p;
349
350 p = image_bus_path(image->name);
351 if (!p)
352 return -ENOMEM;
353
354 r = strv_consume(&l, p);
355 if (r < 0)
356 return r;
357 }
358
359 *nodes = l;
360 l = NULL;
361
362 return 1;
363 }