Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : : #include <sys/stat.h>
5 : : #include <sys/types.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "alloc-util.h"
9 : : #include "bus-common-errors.h"
10 : : #include "bus-label.h"
11 : : #include "bus-util.h"
12 : : #include "fd-util.h"
13 : : #include "fileio.h"
14 : : #include "io-util.h"
15 : : #include "machine-image.h"
16 : : #include "missing_capability.h"
17 : : #include "portable.h"
18 : : #include "portabled-bus.h"
19 : : #include "portabled-image-bus.h"
20 : : #include "portabled-image.h"
21 : : #include "portabled.h"
22 : : #include "process-util.h"
23 : : #include "strv.h"
24 : : #include "user-util.h"
25 : :
26 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
# # ]
27 : :
28 : 0 : int bus_image_common_get_os_release(
29 : : Manager *m,
30 : : sd_bus_message *message,
31 : : const char *name_or_path,
32 : : Image *image,
33 : : sd_bus_error *error) {
34 : :
35 : : int r;
36 : :
37 [ # # # # ]: 0 : assert(name_or_path || image);
38 [ # # ]: 0 : assert(message);
39 : :
40 [ # # ]: 0 : if (!m) {
41 [ # # ]: 0 : assert(image);
42 : 0 : m = image->userdata;
43 : : }
44 : :
45 : 0 : r = bus_image_acquire(m,
46 : : message,
47 : : name_or_path,
48 : : image,
49 : : BUS_IMAGE_AUTHENTICATE_BY_PATH,
50 : : "org.freedesktop.portable1.inspect-images",
51 : : &image,
52 : : error);
53 [ # # ]: 0 : if (r < 0)
54 : 0 : return r;
55 [ # # ]: 0 : if (r == 0) /* Will call us back */
56 : 0 : return 1;
57 : :
58 [ # # ]: 0 : if (!image->metadata_valid) {
59 : 0 : r = image_read_metadata(image);
60 [ # # ]: 0 : if (r < 0)
61 : 0 : return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
62 : : }
63 : :
64 : 0 : return bus_reply_pair_array(message, image->os_release);
65 : : }
66 : :
67 : 0 : static int bus_image_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
68 : 0 : return bus_image_common_get_os_release(NULL, message, NULL, userdata, error);
69 : : }
70 : :
71 : 0 : static int append_fd(sd_bus_message *m, PortableMetadata *d) {
72 : 0 : _cleanup_fclose_ FILE *f = NULL;
73 : 0 : _cleanup_free_ char *buf = NULL;
74 : : size_t n;
75 : : int r;
76 : :
77 [ # # ]: 0 : assert(m);
78 [ # # ]: 0 : assert(d);
79 [ # # ]: 0 : assert(d->fd >= 0);
80 : :
81 : 0 : f = fdopen(d->fd, "r");
82 [ # # ]: 0 : if (!f)
83 : 0 : return -errno;
84 : :
85 : 0 : d->fd = -1;
86 : :
87 : 0 : r = read_full_stream(f, &buf, &n);
88 [ # # ]: 0 : if (r < 0)
89 : 0 : return r;
90 : :
91 : 0 : return sd_bus_message_append_array(m, 'y', buf, n);
92 : : }
93 : :
94 : 0 : int bus_image_common_get_metadata(
95 : : Manager *m,
96 : : sd_bus_message *message,
97 : : const char *name_or_path,
98 : : Image *image,
99 : : sd_bus_error *error) {
100 : :
101 : 0 : _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
102 : 0 : _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
103 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
104 : 0 : _cleanup_free_ PortableMetadata **sorted = NULL;
105 : 0 : _cleanup_strv_free_ char **matches = NULL;
106 : : size_t i;
107 : : int r;
108 : :
109 [ # # # # ]: 0 : assert(name_or_path || image);
110 [ # # ]: 0 : assert(message);
111 : :
112 [ # # ]: 0 : if (!m) {
113 [ # # ]: 0 : assert(image);
114 : 0 : m = image->userdata;
115 : : }
116 : :
117 : 0 : r = sd_bus_message_read_strv(message, &matches);
118 [ # # ]: 0 : if (r < 0)
119 : 0 : return r;
120 : :
121 : 0 : r = bus_image_acquire(m,
122 : : message,
123 : : name_or_path,
124 : : image,
125 : : BUS_IMAGE_AUTHENTICATE_BY_PATH,
126 : : "org.freedesktop.portable1.inspect-images",
127 : : &image,
128 : : error);
129 [ # # ]: 0 : if (r < 0)
130 : 0 : return r;
131 [ # # ]: 0 : if (r == 0) /* Will call us back */
132 : 0 : return 1;
133 : :
134 : 0 : r = portable_extract(
135 : 0 : image->path,
136 : : matches,
137 : : &os_release,
138 : : &unit_files,
139 : : error);
140 [ # # ]: 0 : if (r < 0)
141 : 0 : return r;
142 : :
143 : 0 : r = portable_metadata_hashmap_to_sorted_array(unit_files, &sorted);
144 [ # # ]: 0 : if (r < 0)
145 : 0 : return r;
146 : :
147 : 0 : r = sd_bus_message_new_method_return(message, &reply);
148 [ # # ]: 0 : if (r < 0)
149 : 0 : return r;
150 : :
151 : 0 : r = sd_bus_message_append(reply, "s", image->path);
152 [ # # ]: 0 : if (r < 0)
153 : 0 : return r;
154 : :
155 : 0 : r = append_fd(reply, os_release);
156 [ # # ]: 0 : if (r < 0)
157 : 0 : return r;
158 : :
159 : 0 : r = sd_bus_message_open_container(reply, 'a', "{say}");
160 [ # # ]: 0 : if (r < 0)
161 : 0 : return r;
162 : :
163 [ # # ]: 0 : for (i = 0; i < hashmap_size(unit_files); i++) {
164 : :
165 : 0 : r = sd_bus_message_open_container(reply, 'e', "say");
166 [ # # ]: 0 : if (r < 0)
167 : 0 : return r;
168 : :
169 : 0 : r = sd_bus_message_append(reply, "s", sorted[i]->name);
170 [ # # ]: 0 : if (r < 0)
171 : 0 : return r;
172 : :
173 : 0 : r = append_fd(reply, sorted[i]);
174 [ # # ]: 0 : if (r < 0)
175 : 0 : return r;
176 : :
177 : 0 : r = sd_bus_message_close_container(reply);
178 [ # # ]: 0 : if (r < 0)
179 : 0 : return r;
180 : : }
181 : :
182 : 0 : r = sd_bus_message_close_container(reply);
183 [ # # ]: 0 : if (r < 0)
184 : 0 : return r;
185 : :
186 : 0 : return sd_bus_send(NULL, reply, NULL);
187 : : }
188 : :
189 : 0 : static int bus_image_method_get_metadata(sd_bus_message *message, void *userdata, sd_bus_error *error) {
190 : 0 : return bus_image_common_get_metadata(NULL, message, NULL, userdata, error);
191 : : }
192 : :
193 : 0 : static int bus_image_method_get_state(
194 : : sd_bus_message *message,
195 : : void *userdata,
196 : : sd_bus_error *error) {
197 : :
198 : 0 : Image *image = userdata;
199 : : PortableState state;
200 : : int r;
201 : :
202 [ # # ]: 0 : assert(message);
203 [ # # ]: 0 : assert(image);
204 : :
205 : 0 : r = portable_get_state(
206 : : sd_bus_message_get_bus(message),
207 : 0 : image->path,
208 : : 0,
209 : : &state,
210 : : error);
211 [ # # ]: 0 : if (r < 0)
212 : 0 : return r;
213 : :
214 : 0 : return sd_bus_reply_method_return(message, "s", portable_state_to_string(state));
215 : : }
216 : :
217 : 0 : int bus_image_common_attach(
218 : : Manager *m,
219 : : sd_bus_message *message,
220 : : const char *name_or_path,
221 : : Image *image,
222 : : sd_bus_error *error) {
223 : :
224 : 0 : _cleanup_strv_free_ char **matches = NULL;
225 : 0 : PortableChange *changes = NULL;
226 : 0 : PortableFlags flags = 0;
227 : : const char *profile, *copy_mode;
228 : 0 : size_t n_changes = 0;
229 : : int runtime, r;
230 : :
231 [ # # ]: 0 : assert(message);
232 [ # # # # ]: 0 : assert(name_or_path || image);
233 : :
234 [ # # ]: 0 : if (!m) {
235 [ # # ]: 0 : assert(image);
236 : 0 : m = image->userdata;
237 : : }
238 : :
239 : 0 : r = sd_bus_message_read_strv(message, &matches);
240 [ # # ]: 0 : if (r < 0)
241 : 0 : return r;
242 : :
243 : 0 : r = sd_bus_message_read(message, "sbs", &profile, &runtime, ©_mode);
244 [ # # ]: 0 : if (r < 0)
245 : 0 : return r;
246 : :
247 [ # # ]: 0 : if (streq(copy_mode, "symlink"))
248 : 0 : flags |= PORTABLE_PREFER_SYMLINK;
249 [ # # ]: 0 : else if (streq(copy_mode, "copy"))
250 : 0 : flags |= PORTABLE_PREFER_COPY;
251 [ # # ]: 0 : else if (!isempty(copy_mode))
252 : 0 : return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode);
253 : :
254 [ # # ]: 0 : if (runtime)
255 : 0 : flags |= PORTABLE_RUNTIME;
256 : :
257 : 0 : r = bus_image_acquire(m,
258 : : message,
259 : : name_or_path,
260 : : image,
261 : : BUS_IMAGE_AUTHENTICATE_ALL,
262 : : "org.freedesktop.portable1.attach-images",
263 : : &image,
264 : : error);
265 [ # # ]: 0 : if (r < 0)
266 : 0 : return r;
267 [ # # ]: 0 : if (r == 0) /* Will call us back */
268 : 0 : return 1;
269 : :
270 : 0 : r = portable_attach(
271 : : sd_bus_message_get_bus(message),
272 : 0 : image->path,
273 : : matches,
274 : : profile,
275 : : flags,
276 : : &changes,
277 : : &n_changes,
278 : : error);
279 [ # # ]: 0 : if (r < 0)
280 : 0 : goto finish;
281 : :
282 : 0 : r = reply_portable_changes(message, changes, n_changes);
283 : :
284 : 0 : finish:
285 : 0 : portable_changes_free(changes, n_changes);
286 : 0 : return r;
287 : : }
288 : :
289 : 0 : static int bus_image_method_attach(sd_bus_message *message, void *userdata, sd_bus_error *error) {
290 : 0 : return bus_image_common_attach(NULL, message, NULL, userdata, error);
291 : : }
292 : :
293 : 0 : static int bus_image_method_detach(
294 : : sd_bus_message *message,
295 : : void *userdata,
296 : : sd_bus_error *error) {
297 : :
298 : 0 : PortableChange *changes = NULL;
299 : 0 : Image *image = userdata;
300 : 0 : Manager *m = image->userdata;
301 : 0 : size_t n_changes = 0;
302 : : int r, runtime;
303 : :
304 [ # # ]: 0 : assert(message);
305 [ # # ]: 0 : assert(image);
306 [ # # ]: 0 : assert(m);
307 : :
308 : 0 : r = sd_bus_message_read(message, "b", &runtime);
309 [ # # ]: 0 : if (r < 0)
310 : 0 : return r;
311 : :
312 : 0 : r = bus_verify_polkit_async(
313 : : message,
314 : : CAP_SYS_ADMIN,
315 : : "org.freedesktop.portable1.attach-images",
316 : : NULL,
317 : : false,
318 : : UID_INVALID,
319 : : &m->polkit_registry,
320 : : error);
321 [ # # ]: 0 : if (r < 0)
322 : 0 : return r;
323 [ # # ]: 0 : if (r == 0)
324 : 0 : return 1; /* Will call us back */
325 : :
326 : 0 : r = portable_detach(
327 : : sd_bus_message_get_bus(message),
328 : 0 : image->path,
329 [ # # ]: 0 : runtime ? PORTABLE_RUNTIME : 0,
330 : : &changes,
331 : : &n_changes,
332 : : error);
333 [ # # ]: 0 : if (r < 0)
334 : 0 : goto finish;
335 : :
336 : 0 : r = reply_portable_changes(message, changes, n_changes);
337 : :
338 : 0 : finish:
339 : 0 : portable_changes_free(changes, n_changes);
340 : 0 : return r;
341 : : }
342 : :
343 : 0 : int bus_image_common_remove(
344 : : Manager *m,
345 : : sd_bus_message *message,
346 : : const char *name_or_path,
347 : : Image *image,
348 : : sd_bus_error *error) {
349 : :
350 : 0 : _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
351 : 0 : _cleanup_(sigkill_waitp) pid_t child = 0;
352 : : PortableState state;
353 : : int r;
354 : :
355 [ # # ]: 0 : assert(message);
356 [ # # # # ]: 0 : assert(name_or_path || image);
357 : :
358 [ # # ]: 0 : if (!m) {
359 [ # # ]: 0 : assert(image);
360 : 0 : m = image->userdata;
361 : : }
362 : :
363 [ # # ]: 0 : if (m->n_operations >= OPERATIONS_MAX)
364 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
365 : :
366 : 0 : r = bus_image_acquire(m,
367 : : message,
368 : : name_or_path,
369 : : image,
370 : : BUS_IMAGE_AUTHENTICATE_ALL,
371 : : "org.freedesktop.portable1.manage-images",
372 : : &image,
373 : : error);
374 [ # # ]: 0 : if (r < 0)
375 : 0 : return r;
376 [ # # ]: 0 : if (r == 0)
377 : 0 : return 1; /* Will call us back */
378 : :
379 : 0 : r = portable_get_state(
380 : : sd_bus_message_get_bus(message),
381 : 0 : image->path,
382 : : 0,
383 : : &state,
384 : : error);
385 [ # # ]: 0 : if (r < 0)
386 : 0 : return r;
387 : :
388 [ # # ]: 0 : if (state != PORTABLE_DETACHED)
389 : 0 : return sd_bus_error_set_errnof(error, EBUSY, "Image '%s' is not detached, refusing.", image->path);
390 : :
391 [ # # ]: 0 : if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
392 : 0 : return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
393 : :
394 : 0 : r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
395 [ # # ]: 0 : if (r < 0)
396 : 0 : return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
397 [ # # ]: 0 : if (r == 0) {
398 : 0 : errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
399 : :
400 : 0 : r = image_remove(image);
401 [ # # ]: 0 : if (r < 0) {
402 : 0 : (void) write(errno_pipe_fd[1], &r, sizeof(r));
403 : 0 : _exit(EXIT_FAILURE);
404 : : }
405 : :
406 : 0 : _exit(EXIT_SUCCESS);
407 : : }
408 : :
409 : 0 : errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
410 : :
411 : 0 : r = operation_new(m, child, message, errno_pipe_fd[0], NULL);
412 [ # # ]: 0 : if (r < 0)
413 : 0 : return r;
414 : :
415 : 0 : child = 0;
416 : 0 : errno_pipe_fd[0] = -1;
417 : :
418 : 0 : return 1;
419 : : }
420 : :
421 : 0 : static int bus_image_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error) {
422 : 0 : return bus_image_common_remove(NULL, message, NULL, userdata, error);
423 : : }
424 : :
425 : 0 : int bus_image_common_mark_read_only(
426 : : Manager *m,
427 : : sd_bus_message *message,
428 : : const char *name_or_path,
429 : : Image *image,
430 : : sd_bus_error *error) {
431 : :
432 : : int r, read_only;
433 : :
434 [ # # ]: 0 : assert(message);
435 [ # # # # ]: 0 : assert(name_or_path || image);
436 : :
437 [ # # ]: 0 : if (!m) {
438 [ # # ]: 0 : assert(image);
439 : 0 : m = image->userdata;
440 : : }
441 : :
442 : 0 : r = sd_bus_message_read(message, "b", &read_only);
443 [ # # ]: 0 : if (r < 0)
444 : 0 : return r;
445 : :
446 : 0 : r = bus_image_acquire(m,
447 : : message,
448 : : name_or_path,
449 : : image,
450 : : BUS_IMAGE_AUTHENTICATE_ALL,
451 : : "org.freedesktop.portable1.manage-images",
452 : : &image,
453 : : error);
454 [ # # ]: 0 : if (r < 0)
455 : 0 : return r;
456 [ # # ]: 0 : if (r == 0)
457 : 0 : return 1; /* Will call us back */
458 : :
459 : 0 : r = image_read_only(image, read_only);
460 [ # # ]: 0 : if (r < 0)
461 : 0 : return r;
462 : :
463 : 0 : return sd_bus_reply_method_return(message, NULL);
464 : : }
465 : :
466 : 0 : static int bus_image_method_mark_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
467 : 0 : return bus_image_common_mark_read_only(NULL, message, NULL, userdata, error);
468 : : }
469 : :
470 : 0 : int bus_image_common_set_limit(
471 : : Manager *m,
472 : : sd_bus_message *message,
473 : : const char *name_or_path,
474 : : Image *image,
475 : : sd_bus_error *error) {
476 : :
477 : : uint64_t limit;
478 : : int r;
479 : :
480 [ # # ]: 0 : assert(message);
481 [ # # # # ]: 0 : assert(name_or_path || image);
482 : :
483 [ # # ]: 0 : if (!m) {
484 [ # # ]: 0 : assert(image);
485 : 0 : m = image->userdata;
486 : : }
487 : :
488 : 0 : r = sd_bus_message_read(message, "t", &limit);
489 [ # # ]: 0 : if (r < 0)
490 : 0 : return r;
491 [ # # ]: 0 : if (!FILE_SIZE_VALID_OR_INFINITY(limit))
492 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
493 : :
494 : 0 : r = bus_image_acquire(m,
495 : : message,
496 : : name_or_path,
497 : : image,
498 : : BUS_IMAGE_AUTHENTICATE_ALL,
499 : : "org.freedesktop.portable1.manage-images",
500 : : &image,
501 : : error);
502 [ # # ]: 0 : if (r < 0)
503 : 0 : return r;
504 [ # # ]: 0 : if (r == 0)
505 : 0 : return 1; /* Will call us back */
506 : :
507 : 0 : r = image_set_limit(image, limit);
508 [ # # ]: 0 : if (r < 0)
509 : 0 : return r;
510 : :
511 : 0 : return sd_bus_reply_method_return(message, NULL);
512 : : }
513 : :
514 : 0 : static int bus_image_method_set_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
515 : 0 : return bus_image_common_set_limit(NULL, message, NULL, userdata, error);
516 : : }
517 : :
518 : : const sd_bus_vtable image_vtable[] = {
519 : : SD_BUS_VTABLE_START(0),
520 : : SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
521 : : SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
522 : : SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
523 : : SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
524 : : SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
525 : : SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
526 : : SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
527 : : SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
528 : : SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
529 : : SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
530 : : SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
531 : : SD_BUS_METHOD("GetMetadata", "as", "saya{say}", bus_image_method_get_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
532 : : SD_BUS_METHOD("GetState", NULL, "s", bus_image_method_get_state, SD_BUS_VTABLE_UNPRIVILEGED),
533 : : SD_BUS_METHOD("Attach", "assbs", "a(sss)", bus_image_method_attach, SD_BUS_VTABLE_UNPRIVILEGED),
534 : : SD_BUS_METHOD("Detach", "b", "a(sss)", bus_image_method_detach, SD_BUS_VTABLE_UNPRIVILEGED),
535 : : SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
536 : : SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
537 : : SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
538 : : SD_BUS_VTABLE_END
539 : : };
540 : :
541 : 0 : int bus_image_path(Image *image, char **ret) {
542 [ # # ]: 0 : assert(image);
543 [ # # ]: 0 : assert(ret);
544 : :
545 [ # # ]: 0 : if (!image->discoverable)
546 : 0 : return -EINVAL;
547 : :
548 : 0 : return sd_bus_path_encode("/org/freedesktop/portable1/image", image->name, ret);
549 : : }
550 : :
551 : 0 : int bus_image_acquire(
552 : : Manager *m,
553 : : sd_bus_message *message,
554 : : const char *name_or_path,
555 : : Image *image,
556 : : ImageAcquireMode mode,
557 : : const char *polkit_action,
558 : : Image **ret,
559 : : sd_bus_error *error) {
560 : :
561 : 0 : _cleanup_(image_unrefp) Image *loaded = NULL;
562 : : Image *cached;
563 : : int r;
564 : :
565 [ # # ]: 0 : assert(m);
566 [ # # ]: 0 : assert(message);
567 [ # # # # ]: 0 : assert(name_or_path || image);
568 [ # # ]: 0 : assert(mode >= 0);
569 [ # # ]: 0 : assert(mode < _BUS_IMAGE_ACQUIRE_MODE_MAX);
570 [ # # # # ]: 0 : assert(polkit_action || mode == BUS_IMAGE_REFUSE_BY_PATH);
571 [ # # ]: 0 : assert(ret);
572 : :
573 : : /* Acquires an 'Image' object if not acquired yet, and enforces necessary authentication while doing so. */
574 : :
575 [ # # ]: 0 : if (mode == BUS_IMAGE_AUTHENTICATE_ALL) {
576 : 0 : r = bus_verify_polkit_async(
577 : : message,
578 : : CAP_SYS_ADMIN,
579 : : polkit_action,
580 : : NULL,
581 : : false,
582 : : UID_INVALID,
583 : : &m->polkit_registry,
584 : : error);
585 [ # # ]: 0 : if (r < 0)
586 : 0 : return r;
587 [ # # ]: 0 : if (r == 0) { /* Will call us back */
588 : 0 : *ret = NULL;
589 : 0 : return 0;
590 : : }
591 : : }
592 : :
593 : : /* Already passed in? */
594 [ # # ]: 0 : if (image) {
595 : 0 : *ret = image;
596 : 0 : return 1;
597 : : }
598 : :
599 : : /* Let's see if this image is already cached? */
600 : 0 : cached = manager_image_cache_get(m, name_or_path);
601 [ # # ]: 0 : if (cached) {
602 : 0 : *ret = cached;
603 : 0 : return 1;
604 : : }
605 : :
606 [ # # ]: 0 : if (image_name_is_valid(name_or_path)) {
607 : :
608 : : /* If it's a short name, let's search for it */
609 : 0 : r = image_find(IMAGE_PORTABLE, name_or_path, &loaded);
610 [ # # ]: 0 : if (r == -ENOENT)
611 : 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path);
612 : :
613 : : /* other errors are handled below… */
614 : : } else {
615 : : /* Don't accept path if this is always forbidden */
616 [ # # ]: 0 : if (mode == BUS_IMAGE_REFUSE_BY_PATH)
617 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Expected image name, not path in place of '%s'.", name_or_path);
618 : :
619 [ # # ]: 0 : if (!path_is_absolute(name_or_path))
620 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is not valid or not a valid path.", name_or_path);
621 : :
622 [ # # ]: 0 : if (!path_is_normalized(name_or_path))
623 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image path '%s' is not normalized.", name_or_path);
624 : :
625 [ # # ]: 0 : if (mode == BUS_IMAGE_AUTHENTICATE_BY_PATH) {
626 : 0 : r = bus_verify_polkit_async(
627 : : message,
628 : : CAP_SYS_ADMIN,
629 : : polkit_action,
630 : : NULL,
631 : : false,
632 : : UID_INVALID,
633 : : &m->polkit_registry,
634 : : error);
635 [ # # ]: 0 : if (r < 0)
636 : 0 : return r;
637 [ # # ]: 0 : if (r == 0) { /* Will call us back */
638 : 0 : *ret = NULL;
639 : 0 : return 0;
640 : : }
641 : : }
642 : :
643 : 0 : r = image_from_path(name_or_path, &loaded);
644 : : }
645 [ # # ]: 0 : if (r == -EMEDIUMTYPE) {
646 : 0 : sd_bus_error_setf(error, BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE, "Typ of image '%s' not recognized; supported image types are directories/btrfs subvolumes, block devices, and raw disk image files with suffix '.raw'.", name_or_path);
647 : 0 : return r;
648 : : }
649 [ # # ]: 0 : if (r < 0)
650 : 0 : return r;
651 : :
652 : : /* Add what we just loaded to the cache. This has as side-effect that the object stays in memory until the
653 : : * cache is purged again, i.e. at least for the current event loop iteration, which is all we need, and which
654 : : * means we don't actually need to ref the return object. */
655 : 0 : r = manager_image_cache_add(m, loaded);
656 [ # # ]: 0 : if (r < 0)
657 : 0 : return r;
658 : :
659 : 0 : *ret = loaded;
660 : 0 : return 1;
661 : : }
662 : :
663 : 0 : int bus_image_object_find(
664 : : sd_bus *bus,
665 : : const char *path,
666 : : const char *interface,
667 : : void *userdata,
668 : : void **found,
669 : : sd_bus_error *error) {
670 : :
671 : 0 : _cleanup_free_ char *e = NULL;
672 : 0 : Manager *m = userdata;
673 : 0 : Image *image = NULL;
674 : : int r;
675 : :
676 [ # # ]: 0 : assert(bus);
677 [ # # ]: 0 : assert(path);
678 [ # # ]: 0 : assert(interface);
679 [ # # ]: 0 : assert(found);
680 : :
681 : 0 : r = sd_bus_path_decode(path, "/org/freedesktop/portable1/image", &e);
682 [ # # ]: 0 : if (r < 0)
683 : 0 : return 0;
684 [ # # ]: 0 : if (r == 0)
685 : 0 : goto not_found;
686 : :
687 : 0 : r = bus_image_acquire(m, sd_bus_get_current_message(bus), e, NULL, BUS_IMAGE_REFUSE_BY_PATH, NULL, &image, error);
688 [ # # ]: 0 : if (r == -ENOENT)
689 : 0 : goto not_found;
690 [ # # ]: 0 : if (r < 0)
691 : 0 : return r;
692 : :
693 : 0 : *found = image;
694 : 0 : return 1;
695 : :
696 : 0 : not_found:
697 : 0 : *found = NULL;
698 : 0 : return 0;
699 : : }
700 : :
701 : 0 : int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
702 : 0 : _cleanup_hashmap_free_ Hashmap *images = NULL;
703 : 0 : _cleanup_strv_free_ char **l = NULL;
704 : 0 : size_t n_allocated = 0, n = 0;
705 : 0 : Manager *m = userdata;
706 : : Image *image;
707 : : Iterator i;
708 : : int r;
709 : :
710 [ # # ]: 0 : assert(bus);
711 [ # # ]: 0 : assert(path);
712 [ # # ]: 0 : assert(nodes);
713 : :
714 : 0 : images = hashmap_new(&image_hash_ops);
715 [ # # ]: 0 : if (!images)
716 : 0 : return -ENOMEM;
717 : :
718 : 0 : r = manager_image_cache_discover(m, images, error);
719 [ # # ]: 0 : if (r < 0)
720 : 0 : return r;
721 : :
722 [ # # ]: 0 : HASHMAP_FOREACH(image, images, i) {
723 : : char *p;
724 : :
725 : 0 : r = bus_image_path(image, &p);
726 [ # # ]: 0 : if (r < 0)
727 : 0 : return r;
728 : :
729 [ # # ]: 0 : if (!GREEDY_REALLOC(l, n_allocated, n+2)) {
730 : 0 : free(p);
731 : 0 : return -ENOMEM;
732 : : }
733 : :
734 : 0 : l[n++] = p;
735 : 0 : l[n] = NULL;
736 : : }
737 : :
738 : 0 : *nodes = TAKE_PTR(l);
739 : :
740 : 0 : return 1;
741 : : }
|