chiark / gitweb /
9061017eefce7a8396d92aebe6f71a0827ad93be
[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 "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 const sd_bus_vtable image_vtable[] = {
186         SD_BUS_VTABLE_START(0),
187         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
188         SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
189         SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
190         SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
191         SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
192         SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
193         SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
194         SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
195         SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
196         SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
197         SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
198         SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
199         SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
200         SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
201         SD_BUS_VTABLE_END
202 };
203
204 static int image_flush_cache(sd_event_source *s, void *userdata) {
205         Manager *m = userdata;
206         Image *i;
207
208         assert(s);
209         assert(m);
210
211         while ((i = hashmap_steal_first(m->image_cache)))
212                 image_unref(i);
213
214         return 0;
215 }
216
217 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
218         _cleanup_free_ char *e = NULL;
219         Manager *m = userdata;
220         Image *image = NULL;
221         const char *p;
222         int r;
223
224         assert(bus);
225         assert(path);
226         assert(interface);
227         assert(found);
228
229         p = startswith(path, "/org/freedesktop/machine1/image/");
230         if (!p)
231                 return 0;
232
233         e = bus_label_unescape(p);
234         if (!e)
235                 return -ENOMEM;
236
237         image = hashmap_get(m->image_cache, e);
238         if (image) {
239                 *found = image;
240                 return 1;
241         }
242
243         r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
244         if (r < 0)
245                 return r;
246
247         if (!m->image_cache_defer_event) {
248                 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
249                 if (r < 0)
250                         return r;
251
252                 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
253                 if (r < 0)
254                         return r;
255         }
256
257         r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
258         if (r < 0)
259                 return r;
260
261         r = image_find(e, &image);
262         if (r <= 0)
263                 return r;
264
265         image->userdata = m;
266
267         r = hashmap_put(m->image_cache, image->name, image);
268         if (r < 0) {
269                 image_unref(image);
270                 return r;
271         }
272
273         *found = image;
274         return 1;
275 }
276
277 char *image_bus_path(const char *name) {
278         _cleanup_free_ char *e = NULL;
279
280         assert(name);
281
282         e = bus_label_escape(name);
283         if (!e)
284                 return NULL;
285
286         return strappend("/org/freedesktop/machine1/image/", e);
287 }
288
289 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
290         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
291         _cleanup_strv_free_ char **l = NULL;
292         Image *image;
293         Iterator i;
294         int r;
295
296         assert(bus);
297         assert(path);
298         assert(nodes);
299
300         images = hashmap_new(&string_hash_ops);
301         if (!images)
302                 return -ENOMEM;
303
304         r = image_discover(images);
305         if (r < 0)
306                 return r;
307
308         HASHMAP_FOREACH(image, images, i) {
309                 char *p;
310
311                 p = image_bus_path(image->name);
312                 if (!p)
313                         return -ENOMEM;
314
315                 r = strv_consume(&l, p);
316                 if (r < 0)
317                         return r;
318         }
319
320         *nodes = l;
321         l = NULL;
322
323         return 1;
324 }