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