chiark / gitweb /
systemd-fsck: always connect to systemd-fsckd
[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                         UID_INVALID,
51                         &m->polkit_registry,
52                         error);
53         if (r < 0)
54                 return r;
55         if (r == 0)
56                 return 1; /* Will call us back */
57
58         r = image_remove(image);
59         if (r < 0)
60                 return r;
61
62         return sd_bus_reply_method_return(message, NULL);
63 }
64
65 int bus_image_method_rename(
66                 sd_bus *bus,
67                 sd_bus_message *message,
68                 void *userdata,
69                 sd_bus_error *error) {
70
71         Image *image = userdata;
72         Manager *m = image->userdata;
73         const char *new_name;
74         int r;
75
76         assert(bus);
77         assert(message);
78         assert(image);
79
80         r = sd_bus_message_read(message, "s", &new_name);
81         if (r < 0)
82                 return r;
83
84         if (!image_name_is_valid(new_name))
85                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
86
87         r = bus_verify_polkit_async(
88                         message,
89                         CAP_SYS_ADMIN,
90                         "org.freedesktop.machine1.manage-images",
91                         false,
92                         UID_INVALID,
93                         &m->polkit_registry,
94                         error);
95         if (r < 0)
96                 return r;
97         if (r == 0)
98                 return 1; /* Will call us back */
99
100         r = image_rename(image, new_name);
101         if (r < 0)
102                 return r;
103
104         return sd_bus_reply_method_return(message, NULL);
105 }
106
107 int bus_image_method_clone(
108                 sd_bus *bus,
109                 sd_bus_message *message,
110                 void *userdata,
111                 sd_bus_error *error) {
112
113         Image *image = userdata;
114         Manager *m = image->userdata;
115         const char *new_name;
116         int r, read_only;
117
118         assert(bus);
119         assert(message);
120         assert(image);
121
122         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
123         if (r < 0)
124                 return r;
125
126         if (!image_name_is_valid(new_name))
127                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
128
129         r = bus_verify_polkit_async(
130                         message,
131                         CAP_SYS_ADMIN,
132                         "org.freedesktop.machine1.manage-images",
133                         false,
134                         UID_INVALID,
135                         &m->polkit_registry,
136                         error);
137         if (r < 0)
138                 return r;
139         if (r == 0)
140                 return 1; /* Will call us back */
141
142         r = image_clone(image, new_name, read_only);
143         if (r < 0)
144                 return r;
145
146         return sd_bus_reply_method_return(message, NULL);
147 }
148
149 int bus_image_method_mark_read_only(
150                 sd_bus *bus,
151                 sd_bus_message *message,
152                 void *userdata,
153                 sd_bus_error *error) {
154
155         Image *image = userdata;
156         Manager *m = image->userdata;
157         int r, read_only;
158
159         assert(bus);
160         assert(message);
161
162         r = sd_bus_message_read(message, "b", &read_only);
163         if (r < 0)
164                 return r;
165
166         r = bus_verify_polkit_async(
167                         message,
168                         CAP_SYS_ADMIN,
169                         "org.freedesktop.machine1.manage-images",
170                         false,
171                         UID_INVALID,
172                         &m->polkit_registry,
173                         error);
174         if (r < 0)
175                 return r;
176         if (r == 0)
177                 return 1; /* Will call us back */
178
179         r = image_read_only(image, read_only);
180         if (r < 0)
181                 return r;
182
183         return sd_bus_reply_method_return(message, NULL);
184 }
185
186 const sd_bus_vtable image_vtable[] = {
187         SD_BUS_VTABLE_START(0),
188         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
189         SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
190         SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
191         SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
192         SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
193         SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
194         SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
195         SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
196         SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
197         SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
198         SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
199         SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
200         SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
201         SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
202         SD_BUS_VTABLE_END
203 };
204
205 static int image_flush_cache(sd_event_source *s, void *userdata) {
206         Manager *m = userdata;
207         Image *i;
208
209         assert(s);
210         assert(m);
211
212         while ((i = hashmap_steal_first(m->image_cache)))
213                 image_unref(i);
214
215         return 0;
216 }
217
218 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
219         _cleanup_free_ char *e = NULL;
220         Manager *m = userdata;
221         Image *image = NULL;
222         const char *p;
223         int r;
224
225         assert(bus);
226         assert(path);
227         assert(interface);
228         assert(found);
229
230         p = startswith(path, "/org/freedesktop/machine1/image/");
231         if (!p)
232                 return 0;
233
234         e = bus_label_unescape(p);
235         if (!e)
236                 return -ENOMEM;
237
238         image = hashmap_get(m->image_cache, e);
239         if (image) {
240                 *found = image;
241                 return 1;
242         }
243
244         r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
245         if (r < 0)
246                 return r;
247
248         if (!m->image_cache_defer_event) {
249                 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
250                 if (r < 0)
251                         return r;
252
253                 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
254                 if (r < 0)
255                         return r;
256         }
257
258         r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
259         if (r < 0)
260                 return r;
261
262         r = image_find(e, &image);
263         if (r <= 0)
264                 return r;
265
266         image->userdata = m;
267
268         r = hashmap_put(m->image_cache, image->name, image);
269         if (r < 0) {
270                 image_unref(image);
271                 return r;
272         }
273
274         *found = image;
275         return 1;
276 }
277
278 char *image_bus_path(const char *name) {
279         _cleanup_free_ char *e = NULL;
280
281         assert(name);
282
283         e = bus_label_escape(name);
284         if (!e)
285                 return NULL;
286
287         return strappend("/org/freedesktop/machine1/image/", e);
288 }
289
290 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
291         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
292         _cleanup_strv_free_ char **l = NULL;
293         Image *image;
294         Iterator i;
295         int r;
296
297         assert(bus);
298         assert(path);
299         assert(nodes);
300
301         images = hashmap_new(&string_hash_ops);
302         if (!images)
303                 return -ENOMEM;
304
305         r = image_discover(images);
306         if (r < 0)
307                 return r;
308
309         HASHMAP_FOREACH(image, images, i) {
310                 char *p;
311
312                 p = image_bus_path(image->name);
313                 if (!p)
314                         return -ENOMEM;
315
316                 r = strv_consume(&l, p);
317                 if (r < 0)
318                         return r;
319         }
320
321         *nodes = l;
322         l = NULL;
323
324         return 1;
325 }