]> git.proxmox.com Git - systemd.git/blame - src/machine/image-dbus.c
Merge tag 'upstream/229'
[systemd.git] / src / machine / image-dbus.c
CommitLineData
e735f4d4
MP
1/***
2 This file is part of systemd.
3
4 Copyright 2014 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
db2df898 20#include "alloc-util.h"
e735f4d4 21#include "bus-label.h"
e735f4d4 22#include "bus-util.h"
e735f4d4 23#include "image-dbus.h"
4c89c718 24#include "io-util.h"
db2df898
MP
25#include "machine-image.h"
26#include "strv.h"
27#include "user-util.h"
e735f4d4
MP
28
29static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
30
31int bus_image_method_remove(
e735f4d4
MP
32 sd_bus_message *message,
33 void *userdata,
34 sd_bus_error *error) {
35
36 Image *image = userdata;
e3bff60a 37 Manager *m = image->userdata;
e735f4d4
MP
38 int r;
39
e735f4d4
MP
40 assert(message);
41 assert(image);
42
e3bff60a
MP
43 r = bus_verify_polkit_async(
44 message,
45 CAP_SYS_ADMIN,
46 "org.freedesktop.machine1.manage-images",
d9dfd233 47 NULL,
e3bff60a
MP
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
e735f4d4
MP
57 r = image_remove(image);
58 if (r < 0)
59 return r;
60
61 return sd_bus_reply_method_return(message, NULL);
62}
63
64int bus_image_method_rename(
e735f4d4
MP
65 sd_bus_message *message,
66 void *userdata,
67 sd_bus_error *error) {
68
69 Image *image = userdata;
e3bff60a 70 Manager *m = image->userdata;
e735f4d4
MP
71 const char *new_name;
72 int r;
73
e735f4d4
MP
74 assert(message);
75 assert(image);
76
77 r = sd_bus_message_read(message, "s", &new_name);
78 if (r < 0)
79 return r;
80
81 if (!image_name_is_valid(new_name))
82 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
83
e3bff60a
MP
84 r = bus_verify_polkit_async(
85 message,
86 CAP_SYS_ADMIN,
87 "org.freedesktop.machine1.manage-images",
d9dfd233 88 NULL,
e3bff60a
MP
89 false,
90 UID_INVALID,
91 &m->polkit_registry,
92 error);
93 if (r < 0)
94 return r;
95 if (r == 0)
96 return 1; /* Will call us back */
97
e735f4d4
MP
98 r = image_rename(image, new_name);
99 if (r < 0)
100 return r;
101
102 return sd_bus_reply_method_return(message, NULL);
103}
104
105int bus_image_method_clone(
e735f4d4
MP
106 sd_bus_message *message,
107 void *userdata,
108 sd_bus_error *error) {
109
110 Image *image = userdata;
e3bff60a 111 Manager *m = image->userdata;
e735f4d4
MP
112 const char *new_name;
113 int r, read_only;
114
e735f4d4
MP
115 assert(message);
116 assert(image);
117
118 r = sd_bus_message_read(message, "sb", &new_name, &read_only);
119 if (r < 0)
120 return r;
121
122 if (!image_name_is_valid(new_name))
123 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
124
e3bff60a
MP
125 r = bus_verify_polkit_async(
126 message,
127 CAP_SYS_ADMIN,
128 "org.freedesktop.machine1.manage-images",
d9dfd233 129 NULL,
e3bff60a
MP
130 false,
131 UID_INVALID,
132 &m->polkit_registry,
133 error);
134 if (r < 0)
135 return r;
136 if (r == 0)
137 return 1; /* Will call us back */
138
e735f4d4
MP
139 r = image_clone(image, new_name, read_only);
140 if (r < 0)
141 return r;
142
143 return sd_bus_reply_method_return(message, NULL);
144}
145
146int bus_image_method_mark_read_only(
e735f4d4
MP
147 sd_bus_message *message,
148 void *userdata,
149 sd_bus_error *error) {
150
151 Image *image = userdata;
e3bff60a 152 Manager *m = image->userdata;
e735f4d4
MP
153 int r, read_only;
154
e735f4d4
MP
155 assert(message);
156
157 r = sd_bus_message_read(message, "b", &read_only);
158 if (r < 0)
159 return r;
160
e3bff60a
MP
161 r = bus_verify_polkit_async(
162 message,
163 CAP_SYS_ADMIN,
164 "org.freedesktop.machine1.manage-images",
d9dfd233 165 NULL,
e3bff60a
MP
166 false,
167 UID_INVALID,
168 &m->polkit_registry,
169 error);
170 if (r < 0)
171 return r;
172 if (r == 0)
173 return 1; /* Will call us back */
174
e735f4d4
MP
175 r = image_read_only(image, read_only);
176 if (r < 0)
177 return r;
178
179 return sd_bus_reply_method_return(message, NULL);
180}
181
e3bff60a
MP
182int bus_image_method_set_limit(
183 sd_bus_message *message,
184 void *userdata,
185 sd_bus_error *error) {
186
187 Image *image = userdata;
188 Manager *m = image->userdata;
189 uint64_t limit;
190 int r;
191
192 assert(message);
193
194 r = sd_bus_message_read(message, "t", &limit);
195 if (r < 0)
196 return r;
4c89c718
MP
197 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
198 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
e3bff60a
MP
199
200 r = bus_verify_polkit_async(
201 message,
202 CAP_SYS_ADMIN,
203 "org.freedesktop.machine1.manage-images",
d9dfd233 204 NULL,
e3bff60a
MP
205 false,
206 UID_INVALID,
207 &m->polkit_registry,
208 error);
209 if (r < 0)
210 return r;
211 if (r == 0)
212 return 1; /* Will call us back */
213
214 r = image_set_limit(image, limit);
215 if (r < 0)
216 return r;
217
218 return sd_bus_reply_method_return(message, NULL);
219}
220
e735f4d4
MP
221const sd_bus_vtable image_vtable[] = {
222 SD_BUS_VTABLE_START(0),
223 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
224 SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
225 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
226 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
227 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
228 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
229 SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
230 SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
231 SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
232 SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
e3bff60a
MP
233 SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
234 SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
235 SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
236 SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
237 SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
e735f4d4
MP
238 SD_BUS_VTABLE_END
239};
240
241static int image_flush_cache(sd_event_source *s, void *userdata) {
242 Manager *m = userdata;
243 Image *i;
244
245 assert(s);
246 assert(m);
247
248 while ((i = hashmap_steal_first(m->image_cache)))
249 image_unref(i);
250
251 return 0;
252}
253
254int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
255 _cleanup_free_ char *e = NULL;
256 Manager *m = userdata;
257 Image *image = NULL;
258 const char *p;
259 int r;
260
261 assert(bus);
262 assert(path);
263 assert(interface);
264 assert(found);
265
266 p = startswith(path, "/org/freedesktop/machine1/image/");
267 if (!p)
268 return 0;
269
270 e = bus_label_unescape(p);
271 if (!e)
272 return -ENOMEM;
273
274 image = hashmap_get(m->image_cache, e);
275 if (image) {
276 *found = image;
277 return 1;
278 }
279
280 r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
281 if (r < 0)
282 return r;
283
284 if (!m->image_cache_defer_event) {
285 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
286 if (r < 0)
287 return r;
288
289 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
290 if (r < 0)
291 return r;
292 }
293
294 r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
295 if (r < 0)
296 return r;
297
298 r = image_find(e, &image);
299 if (r <= 0)
300 return r;
301
e3bff60a
MP
302 image->userdata = m;
303
e735f4d4
MP
304 r = hashmap_put(m->image_cache, image->name, image);
305 if (r < 0) {
306 image_unref(image);
307 return r;
308 }
309
310 *found = image;
311 return 1;
312}
313
314char *image_bus_path(const char *name) {
315 _cleanup_free_ char *e = NULL;
316
317 assert(name);
318
319 e = bus_label_escape(name);
320 if (!e)
321 return NULL;
322
323 return strappend("/org/freedesktop/machine1/image/", e);
324}
325
326int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
327 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
328 _cleanup_strv_free_ char **l = NULL;
329 Image *image;
330 Iterator i;
331 int r;
332
333 assert(bus);
334 assert(path);
335 assert(nodes);
336
337 images = hashmap_new(&string_hash_ops);
338 if (!images)
339 return -ENOMEM;
340
341 r = image_discover(images);
342 if (r < 0)
343 return r;
344
345 HASHMAP_FOREACH(image, images, i) {
346 char *p;
347
348 p = image_bus_path(image->name);
349 if (!p)
350 return -ENOMEM;
351
352 r = strv_consume(&l, p);
353 if (r < 0)
354 return r;
355 }
356
357 *nodes = l;
358 l = NULL;
359
360 return 1;
361}