]>
Commit | Line | Data |
---|---|---|
e735f4d4 MP |
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 | ||
db2df898 | 20 | #include "alloc-util.h" |
e735f4d4 | 21 | #include "bus-label.h" |
e735f4d4 | 22 | #include "bus-util.h" |
e735f4d4 | 23 | #include "image-dbus.h" |
4c89c718 | 24 | #include "io-util.h" |
db2df898 MP |
25 | #include "machine-image.h" |
26 | #include "strv.h" | |
27 | #include "user-util.h" | |
e735f4d4 MP |
28 | |
29 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType); | |
30 | ||
31 | int bus_image_method_remove( | |
e735f4d4 MP |
32 | sd_bus_message *message, |
33 | void *userdata, | |
34 | sd_bus_error *error) { | |
35 | ||
36 | Image *image = userdata; | |
e3bff60a | 37 | Manager *m = image->userdata; |
e735f4d4 MP |
38 | int r; |
39 | ||
e735f4d4 MP |
40 | assert(message); |
41 | assert(image); | |
42 | ||
e3bff60a MP |
43 | r = bus_verify_polkit_async( |
44 | message, | |
45 | CAP_SYS_ADMIN, | |
46 | "org.freedesktop.machine1.manage-images", | |
d9dfd233 | 47 | NULL, |
e3bff60a MP |
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 | ||
e735f4d4 MP |
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( | |
e735f4d4 MP |
65 | sd_bus_message *message, |
66 | void *userdata, | |
67 | sd_bus_error *error) { | |
68 | ||
69 | Image *image = userdata; | |
e3bff60a | 70 | Manager *m = image->userdata; |
e735f4d4 MP |
71 | const char *new_name; |
72 | int r; | |
73 | ||
e735f4d4 MP |
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 | ||
e3bff60a MP |
84 | r = bus_verify_polkit_async( |
85 | message, | |
86 | CAP_SYS_ADMIN, | |
87 | "org.freedesktop.machine1.manage-images", | |
d9dfd233 | 88 | NULL, |
e3bff60a MP |
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 | ||
e735f4d4 MP |
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( | |
e735f4d4 MP |
106 | sd_bus_message *message, |
107 | void *userdata, | |
108 | sd_bus_error *error) { | |
109 | ||
110 | Image *image = userdata; | |
e3bff60a | 111 | Manager *m = image->userdata; |
e735f4d4 MP |
112 | const char *new_name; |
113 | int r, read_only; | |
114 | ||
e735f4d4 MP |
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 | ||
e3bff60a MP |
125 | r = bus_verify_polkit_async( |
126 | message, | |
127 | CAP_SYS_ADMIN, | |
128 | "org.freedesktop.machine1.manage-images", | |
d9dfd233 | 129 | NULL, |
e3bff60a MP |
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 | ||
e735f4d4 MP |
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( | |
e735f4d4 MP |
147 | sd_bus_message *message, |
148 | void *userdata, | |
149 | sd_bus_error *error) { | |
150 | ||
151 | Image *image = userdata; | |
e3bff60a | 152 | Manager *m = image->userdata; |
e735f4d4 MP |
153 | int r, read_only; |
154 | ||
e735f4d4 MP |
155 | assert(message); |
156 | ||
157 | r = sd_bus_message_read(message, "b", &read_only); | |
158 | if (r < 0) | |
159 | return r; | |
160 | ||
e3bff60a MP |
161 | r = bus_verify_polkit_async( |
162 | message, | |
163 | CAP_SYS_ADMIN, | |
164 | "org.freedesktop.machine1.manage-images", | |
d9dfd233 | 165 | NULL, |
e3bff60a MP |
166 | false, |
167 | UID_INVALID, | |
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 | ||
e735f4d4 MP |
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 | ||
e3bff60a MP |
182 | int bus_image_method_set_limit( |
183 | sd_bus_message *message, | |
184 | void *userdata, | |
185 | sd_bus_error *error) { | |
186 | ||
187 | Image *image = userdata; | |
188 | Manager *m = image->userdata; | |
189 | uint64_t limit; | |
190 | int r; | |
191 | ||
192 | assert(message); | |
193 | ||
194 | r = sd_bus_message_read(message, "t", &limit); | |
195 | if (r < 0) | |
196 | return r; | |
4c89c718 MP |
197 | if (!FILE_SIZE_VALID_OR_INFINITY(limit)) |
198 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); | |
e3bff60a MP |
199 | |
200 | r = bus_verify_polkit_async( | |
201 | message, | |
202 | CAP_SYS_ADMIN, | |
203 | "org.freedesktop.machine1.manage-images", | |
d9dfd233 | 204 | NULL, |
e3bff60a MP |
205 | false, |
206 | UID_INVALID, | |
207 | &m->polkit_registry, | |
208 | error); | |
209 | if (r < 0) | |
210 | return r; | |
211 | if (r == 0) | |
212 | return 1; /* Will call us back */ | |
213 | ||
214 | r = image_set_limit(image, limit); | |
215 | if (r < 0) | |
216 | return r; | |
217 | ||
218 | return sd_bus_reply_method_return(message, NULL); | |
219 | } | |
220 | ||
e735f4d4 MP |
221 | const sd_bus_vtable image_vtable[] = { |
222 | SD_BUS_VTABLE_START(0), | |
223 | SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0), | |
224 | SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0), | |
225 | SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0), | |
226 | SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0), | |
227 | SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0), | |
228 | SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0), | |
229 | SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0), | |
230 | SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0), | |
231 | SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0), | |
232 | SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0), | |
e3bff60a MP |
233 | SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED), |
234 | SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED), | |
235 | SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED), | |
236 | SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED), | |
237 | SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED), | |
e735f4d4 MP |
238 | SD_BUS_VTABLE_END |
239 | }; | |
240 | ||
241 | static int image_flush_cache(sd_event_source *s, void *userdata) { | |
242 | Manager *m = userdata; | |
243 | Image *i; | |
244 | ||
245 | assert(s); | |
246 | assert(m); | |
247 | ||
248 | while ((i = hashmap_steal_first(m->image_cache))) | |
249 | image_unref(i); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { | |
255 | _cleanup_free_ char *e = NULL; | |
256 | Manager *m = userdata; | |
257 | Image *image = NULL; | |
258 | const char *p; | |
259 | int r; | |
260 | ||
261 | assert(bus); | |
262 | assert(path); | |
263 | assert(interface); | |
264 | assert(found); | |
265 | ||
266 | p = startswith(path, "/org/freedesktop/machine1/image/"); | |
267 | if (!p) | |
268 | return 0; | |
269 | ||
270 | e = bus_label_unescape(p); | |
271 | if (!e) | |
272 | return -ENOMEM; | |
273 | ||
274 | image = hashmap_get(m->image_cache, e); | |
275 | if (image) { | |
276 | *found = image; | |
277 | return 1; | |
278 | } | |
279 | ||
280 | r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops); | |
281 | if (r < 0) | |
282 | return r; | |
283 | ||
284 | if (!m->image_cache_defer_event) { | |
285 | r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m); | |
286 | if (r < 0) | |
287 | return r; | |
288 | ||
289 | r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE); | |
290 | if (r < 0) | |
291 | return r; | |
292 | } | |
293 | ||
294 | r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT); | |
295 | if (r < 0) | |
296 | return r; | |
297 | ||
298 | r = image_find(e, &image); | |
299 | if (r <= 0) | |
300 | return r; | |
301 | ||
e3bff60a MP |
302 | image->userdata = m; |
303 | ||
e735f4d4 MP |
304 | r = hashmap_put(m->image_cache, image->name, image); |
305 | if (r < 0) { | |
306 | image_unref(image); | |
307 | return r; | |
308 | } | |
309 | ||
310 | *found = image; | |
311 | return 1; | |
312 | } | |
313 | ||
314 | char *image_bus_path(const char *name) { | |
315 | _cleanup_free_ char *e = NULL; | |
316 | ||
317 | assert(name); | |
318 | ||
319 | e = bus_label_escape(name); | |
320 | if (!e) | |
321 | return NULL; | |
322 | ||
323 | return strappend("/org/freedesktop/machine1/image/", e); | |
324 | } | |
325 | ||
326 | int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { | |
327 | _cleanup_(image_hashmap_freep) Hashmap *images = NULL; | |
328 | _cleanup_strv_free_ char **l = NULL; | |
329 | Image *image; | |
330 | Iterator i; | |
331 | int r; | |
332 | ||
333 | assert(bus); | |
334 | assert(path); | |
335 | assert(nodes); | |
336 | ||
337 | images = hashmap_new(&string_hash_ops); | |
338 | if (!images) | |
339 | return -ENOMEM; | |
340 | ||
341 | r = image_discover(images); | |
342 | if (r < 0) | |
343 | return r; | |
344 | ||
345 | HASHMAP_FOREACH(image, images, i) { | |
346 | char *p; | |
347 | ||
348 | p = image_bus_path(image->name); | |
349 | if (!p) | |
350 | return -ENOMEM; | |
351 | ||
352 | r = strv_consume(&l, p); | |
353 | if (r < 0) | |
354 | return r; | |
355 | } | |
356 | ||
357 | *nodes = l; | |
358 | l = NULL; | |
359 | ||
360 | return 1; | |
361 | } |