chiark / gitweb /
0d4ebde92b5eb97d566d710f314b1aef1ae23c05
[elogind.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 "bus-common-errors.h"
24 #include "strv.h"
25 #include "bus-util.h"
26 #include "machine-image.h"
27 #include "image-dbus.h"
28
29 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
30
31 int bus_image_method_remove(
32                 sd_bus *bus,
33                 sd_bus_message *message,
34                 void *userdata,
35                 sd_bus_error *error) {
36
37         Image *image = userdata;
38         Manager *m = image->userdata;
39         int r;
40
41         assert(bus);
42         assert(message);
43         assert(image);
44
45         r = bus_verify_polkit_async(
46                         message,
47                         CAP_SYS_ADMIN,
48                         "org.freedesktop.machine1.manage-images",
49                         false,
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                         &m->polkit_registry,
92                         error);
93         if (r < 0)
94                 return r;
95         if (r == 0)
96                 return 1; /* Will call us back */
97
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
105 int bus_image_method_clone(
106                 sd_bus *bus,
107                 sd_bus_message *message,
108                 void *userdata,
109                 sd_bus_error *error) {
110
111         Image *image = userdata;
112         Manager *m = image->userdata;
113         const char *new_name;
114         int r, read_only;
115
116         assert(bus);
117         assert(message);
118         assert(image);
119
120         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
121         if (r < 0)
122                 return r;
123
124         if (!image_name_is_valid(new_name))
125                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
126
127         r = bus_verify_polkit_async(
128                         message,
129                         CAP_SYS_ADMIN,
130                         "org.freedesktop.machine1.manage-images",
131                         false,
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
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
146 int bus_image_method_mark_read_only(
147                 sd_bus *bus,
148                 sd_bus_message *message,
149                 void *userdata,
150                 sd_bus_error *error) {
151
152         Image *image = userdata;
153         Manager *m = image->userdata;
154         int r, read_only;
155
156         assert(bus);
157         assert(message);
158
159         r = sd_bus_message_read(message, "b", &read_only);
160         if (r < 0)
161                 return r;
162
163         r = bus_verify_polkit_async(
164                         message,
165                         CAP_SYS_ADMIN,
166                         "org.freedesktop.machine1.manage-images",
167                         false,
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
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
182 const sd_bus_vtable image_vtable[] = {
183         SD_BUS_VTABLE_START(0),
184         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
185         SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
186         SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
187         SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
188         SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
189         SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
190         SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
191         SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
192         SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
193         SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
194         SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
195         SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
196         SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
197         SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
198         SD_BUS_VTABLE_END
199 };
200
201 static int image_flush_cache(sd_event_source *s, void *userdata) {
202         Manager *m = userdata;
203         Image *i;
204
205         assert(s);
206         assert(m);
207
208         while ((i = hashmap_steal_first(m->image_cache)))
209                 image_unref(i);
210
211         return 0;
212 }
213
214 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
215         _cleanup_free_ char *e = NULL;
216         Manager *m = userdata;
217         Image *image = NULL;
218         const char *p;
219         int r;
220
221         assert(bus);
222         assert(path);
223         assert(interface);
224         assert(found);
225
226         p = startswith(path, "/org/freedesktop/machine1/image/");
227         if (!p)
228                 return 0;
229
230         e = bus_label_unescape(p);
231         if (!e)
232                 return -ENOMEM;
233
234         image = hashmap_get(m->image_cache, e);
235         if (image) {
236                 *found = image;
237                 return 1;
238         }
239
240         r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
241         if (r < 0)
242                 return r;
243
244         if (!m->image_cache_defer_event) {
245                 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
246                 if (r < 0)
247                         return r;
248
249                 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
250                 if (r < 0)
251                         return r;
252         }
253
254         r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
255         if (r < 0)
256                 return r;
257
258         r = image_find(e, &image);
259         if (r <= 0)
260                 return r;
261
262         image->userdata = m;
263
264         r = hashmap_put(m->image_cache, image->name, image);
265         if (r < 0) {
266                 image_unref(image);
267                 return r;
268         }
269
270         *found = image;
271         return 1;
272 }
273
274 char *image_bus_path(const char *name) {
275         _cleanup_free_ char *e = NULL;
276
277         assert(name);
278
279         e = bus_label_escape(name);
280         if (!e)
281                 return NULL;
282
283         return strappend("/org/freedesktop/machine1/image/", e);
284 }
285
286 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
287         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
288         _cleanup_strv_free_ char **l = NULL;
289         Image *image;
290         Iterator i;
291         int r;
292
293         assert(bus);
294         assert(path);
295         assert(nodes);
296
297         images = hashmap_new(&string_hash_ops);
298         if (!images)
299                 return -ENOMEM;
300
301         r = image_discover(images);
302         if (r < 0)
303                 return r;
304
305         HASHMAP_FOREACH(image, images, i) {
306                 char *p;
307
308                 p = image_bus_path(image->name);
309                 if (!p)
310                         return -ENOMEM;
311
312                 r = strv_consume(&l, p);
313                 if (r < 0)
314                         return r;
315         }
316
317         *nodes = l;
318         l = NULL;
319
320         return 1;
321 }