]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/image-dbus.c
Merge pull request #3109 from poettering/journal-by-fd
[thirdparty/systemd.git] / src / machine / image-dbus.c
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
20 #include "alloc-util.h"
21 #include "bus-label.h"
22 #include "bus-util.h"
23 #include "image-dbus.h"
24 #include "io-util.h"
25 #include "machine-image.h"
26 #include "strv.h"
27 #include "user-util.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_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(message);
41 assert(image);
42
43 r = bus_verify_polkit_async(
44 message,
45 CAP_SYS_ADMIN,
46 "org.freedesktop.machine1.manage-images",
47 NULL,
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_message *message,
66 void *userdata,
67 sd_bus_error *error) {
68
69 Image *image = userdata;
70 Manager *m = image->userdata;
71 const char *new_name;
72 int r;
73
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
84 r = bus_verify_polkit_async(
85 message,
86 CAP_SYS_ADMIN,
87 "org.freedesktop.machine1.manage-images",
88 NULL,
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
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_message *message,
107 void *userdata,
108 sd_bus_error *error) {
109
110 Image *image = userdata;
111 Manager *m = image->userdata;
112 const char *new_name;
113 int r, read_only;
114
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
125 r = bus_verify_polkit_async(
126 message,
127 CAP_SYS_ADMIN,
128 "org.freedesktop.machine1.manage-images",
129 NULL,
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
139 r = image_clone(image, new_name, read_only);
140 if (r == -EOPNOTSUPP)
141 return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems.");
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_message *message,
150 void *userdata,
151 sd_bus_error *error) {
152
153 Image *image = userdata;
154 Manager *m = image->userdata;
155 int r, read_only;
156
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 NULL,
168 false,
169 UID_INVALID,
170 &m->polkit_registry,
171 error);
172 if (r < 0)
173 return r;
174 if (r == 0)
175 return 1; /* Will call us back */
176
177 r = image_read_only(image, read_only);
178 if (r < 0)
179 return r;
180
181 return sd_bus_reply_method_return(message, NULL);
182 }
183
184 int bus_image_method_set_limit(
185 sd_bus_message *message,
186 void *userdata,
187 sd_bus_error *error) {
188
189 Image *image = userdata;
190 Manager *m = image->userdata;
191 uint64_t limit;
192 int r;
193
194 assert(message);
195
196 r = sd_bus_message_read(message, "t", &limit);
197 if (r < 0)
198 return r;
199 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
201
202 r = bus_verify_polkit_async(
203 message,
204 CAP_SYS_ADMIN,
205 "org.freedesktop.machine1.manage-images",
206 NULL,
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 }