]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/discover-image.c
Preset user units on first boot as well
[thirdparty/systemd.git] / src / shared / discover-image.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <linux/fs.h>
6 #include <linux/loop.h>
7 #include <linux/magic.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/file.h>
11 #include <sys/ioctl.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14
15 #include "alloc-util.h"
16 #include "blockdev-util.h"
17 #include "btrfs-util.h"
18 #include "chase.h"
19 #include "chattr-util.h"
20 #include "copy.h"
21 #include "dirent-util.h"
22 #include "discover-image.h"
23 #include "dissect-image.h"
24 #include "env-file.h"
25 #include "env-util.h"
26 #include "extension-util.h"
27 #include "fd-util.h"
28 #include "fs-util.h"
29 #include "hashmap.h"
30 #include "hostname-setup.h"
31 #include "id128-util.h"
32 #include "initrd-util.h"
33 #include "lock-util.h"
34 #include "log.h"
35 #include "loop-util.h"
36 #include "macro.h"
37 #include "mkdir.h"
38 #include "nulstr-util.h"
39 #include "os-util.h"
40 #include "path-util.h"
41 #include "rm-rf.h"
42 #include "stat-util.h"
43 #include "string-table.h"
44 #include "string-util.h"
45 #include "strv.h"
46 #include "time-util.h"
47 #include "utf8.h"
48 #include "vpick.h"
49 #include "xattr-util.h"
50
51 const char* const image_search_path[_IMAGE_CLASS_MAX] = {
52 [IMAGE_MACHINE] = "/etc/machines\0" /* only place symlinks here */
53 "/run/machines\0" /* and here too */
54 "/var/lib/machines\0" /* the main place for images */
55 "/var/lib/container\0" /* legacy */
56 "/usr/local/lib/machines\0"
57 "/usr/lib/machines\0",
58
59 [IMAGE_PORTABLE] = "/etc/portables\0" /* only place symlinks here */
60 "/run/portables\0" /* and here too */
61 "/var/lib/portables\0" /* the main place for images */
62 "/usr/local/lib/portables\0"
63 "/usr/lib/portables\0",
64
65 /* Note that we don't allow storing extensions under /usr/, unlike with other image types. That's
66 * because extension images are supposed to extend /usr/, so you get into recursive races, especially
67 * with directory-based extensions, as the kernel's OverlayFS explicitly checks for this and errors
68 * out with -ELOOP if it finds that a lowerdir= is a child of another lowerdir=. */
69 [IMAGE_SYSEXT] = "/etc/extensions\0" /* only place symlinks here */
70 "/run/extensions\0" /* and here too */
71 "/var/lib/extensions\0", /* the main place for images */
72
73 [IMAGE_CONFEXT] = "/run/confexts\0" /* only place symlinks here */
74 "/var/lib/confexts\0" /* the main place for images */
75 "/usr/local/lib/confexts\0"
76 "/usr/lib/confexts\0",
77 };
78
79 /* Inside the initrd, use a slightly different set of search path (i.e. include .extra/sysext/ and
80 * .extra/confext/ in extension search dir) */
81 static const char* const image_search_path_initrd[_IMAGE_CLASS_MAX] = {
82 /* (entries that aren't listed here will get the same search path as for the non initrd-case) */
83
84 [IMAGE_SYSEXT] = "/etc/extensions\0" /* only place symlinks here */
85 "/run/extensions\0" /* and here too */
86 "/var/lib/extensions\0" /* the main place for images */
87 "/.extra/sysext\0", /* put sysext picked up by systemd-stub last, since not trusted */
88
89 [IMAGE_CONFEXT] = "/run/confexts\0" /* only place symlinks here */
90 "/var/lib/confexts\0" /* the main place for images */
91 "/usr/local/lib/confexts\0"
92 "/.extra/confext\0", /* put confext picked up by systemd-stub last, since not trusted */
93 };
94
95 static const char* image_class_suffix_table[_IMAGE_CLASS_MAX] = {
96 [IMAGE_SYSEXT] = ".sysext",
97 [IMAGE_CONFEXT] = ".confext",
98 };
99
100 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(image_class_suffix, ImageClass);
101
102 static const char *const image_root_table[_IMAGE_CLASS_MAX] = {
103 [IMAGE_MACHINE] = "/var/lib/machines",
104 [IMAGE_PORTABLE] = "/var/lib/portables",
105 [IMAGE_SYSEXT] = "/var/lib/extensions",
106 [IMAGE_CONFEXT] = "/var/lib/confexts",
107 };
108
109 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(image_root, ImageClass);
110
111 static Image *image_free(Image *i) {
112 assert(i);
113
114 free(i->name);
115 free(i->path);
116
117 free(i->hostname);
118 strv_free(i->machine_info);
119 strv_free(i->os_release);
120 strv_free(i->sysext_release);
121 strv_free(i->confext_release);
122
123 return mfree(i);
124 }
125
126 DEFINE_TRIVIAL_REF_UNREF_FUNC(Image, image, image_free);
127 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, string_compare_func,
128 Image, image_unref);
129
130 static char **image_settings_path(Image *image) {
131 _cleanup_strv_free_ char **l = NULL;
132 _cleanup_free_ char *fn = NULL;
133 size_t i = 0;
134 int r;
135
136 assert(image);
137
138 l = new0(char*, 4);
139 if (!l)
140 return NULL;
141
142 fn = strjoin(image->name, ".nspawn");
143 if (!fn)
144 return NULL;
145
146 FOREACH_STRING(s, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
147 l[i] = path_join(s, fn);
148 if (!l[i])
149 return NULL;
150
151 i++;
152 }
153
154 r = file_in_same_dir(image->path, fn, l + i);
155 if (r == -ENOMEM)
156 return NULL;
157 if (r < 0)
158 log_debug_errno(r, "Failed to generate .nspawn settings path from image path, ignoring: %m");
159
160 strv_uniq(l);
161
162 return TAKE_PTR(l);
163 }
164
165 static int image_roothash_path(Image *image, char **ret) {
166 _cleanup_free_ char *fn = NULL;
167
168 assert(image);
169
170 fn = strjoin(image->name, ".roothash");
171 if (!fn)
172 return -ENOMEM;
173
174 return file_in_same_dir(image->path, fn, ret);
175 }
176
177 static int image_new(
178 ImageType t,
179 ImageClass c,
180 const char *pretty,
181 const char *path,
182 const char *filename,
183 bool read_only,
184 usec_t crtime,
185 usec_t mtime,
186 Image **ret) {
187
188 _cleanup_(image_unrefp) Image *i = NULL;
189
190 assert(t >= 0);
191 assert(t < _IMAGE_TYPE_MAX);
192 assert(pretty);
193 assert(filename);
194 assert(ret);
195
196 i = new(Image, 1);
197 if (!i)
198 return -ENOMEM;
199
200 *i = (Image) {
201 .n_ref = 1,
202 .type = t,
203 .class = c,
204 .read_only = read_only,
205 .crtime = crtime,
206 .mtime = mtime,
207 .usage = UINT64_MAX,
208 .usage_exclusive = UINT64_MAX,
209 .limit = UINT64_MAX,
210 .limit_exclusive = UINT64_MAX,
211 };
212
213 i->name = strdup(pretty);
214 if (!i->name)
215 return -ENOMEM;
216
217 i->path = path_join(path, filename);
218 if (!i->path)
219 return -ENOMEM;
220
221 path_simplify(i->path);
222
223 *ret = TAKE_PTR(i);
224
225 return 0;
226 }
227
228 static int extract_image_basename(
229 const char *path,
230 const char *class_suffix, /* e.g. ".sysext" (this is an optional suffix) */
231 char **format_suffixes, /* e.g. ".raw" (one of these will be required) */
232 char **ret_basename,
233 char **ret_suffix) {
234
235 _cleanup_free_ char *name = NULL, *suffix = NULL;
236 int r;
237
238 assert(path);
239
240 r = path_extract_filename(path, &name);
241 if (r < 0)
242 return r;
243
244 if (format_suffixes) {
245 char *e = endswith_strv(name, format_suffixes);
246 if (!e) /* Format suffix is required */
247 return -EINVAL;
248
249 if (ret_suffix) {
250 suffix = strdup(e);
251 if (!suffix)
252 return -ENOMEM;
253 }
254
255 *e = 0;
256 }
257
258 if (class_suffix) {
259 char *e = endswith(name, class_suffix);
260 if (e) { /* Class suffix is optional */
261 if (ret_suffix) {
262 _cleanup_free_ char *j = strjoin(e, suffix);
263 if (!j)
264 return -ENOMEM;
265
266 free_and_replace(suffix, j);
267 }
268
269 *e = 0;
270 }
271 }
272
273 if (!image_name_is_valid(name))
274 return -EINVAL;
275
276 if (ret_suffix)
277 *ret_suffix = TAKE_PTR(suffix);
278
279 if (ret_basename)
280 *ret_basename = TAKE_PTR(name);
281
282 return 0;
283 }
284
285 static int image_update_quota(Image *i, int fd) {
286 _cleanup_close_ int fd_close = -EBADF;
287 int r;
288
289 assert(i);
290
291 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
292 return -EROFS;
293
294 if (i->type != IMAGE_SUBVOLUME)
295 return -EOPNOTSUPP;
296
297 if (fd < 0) {
298 fd_close = open(i->path, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
299 if (fd_close < 0)
300 return -errno;
301 fd = fd_close;
302 }
303
304 r = btrfs_quota_scan_ongoing(fd);
305 if (r < 0)
306 return r;
307 if (r > 0)
308 return 0;
309
310 BtrfsQuotaInfo quota;
311 r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
312 if (r < 0)
313 return r;
314
315 i->usage = quota.referenced;
316 i->usage_exclusive = quota.exclusive;
317 i->limit = quota.referenced_max;
318 i->limit_exclusive = quota.exclusive_max;
319
320 return 1;
321 }
322
323 static int image_make(
324 ImageClass c,
325 const char *pretty,
326 int dfd,
327 const char *path,
328 const char *filename,
329 const struct stat *st,
330 Image **ret) {
331
332 _cleanup_free_ char *pretty_buffer = NULL, *parent = NULL;
333 struct stat stbuf;
334 bool read_only;
335 int r;
336
337 assert(dfd >= 0 || dfd == AT_FDCWD);
338 assert(path || dfd == AT_FDCWD);
339 assert(filename);
340
341 /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
342 * devices into /var/lib/machines/, and treat them normally.
343 *
344 * This function returns -ENOENT if we can't find the image after all, and -EMEDIUMTYPE if it's not a file we
345 * recognize. */
346
347 if (!st) {
348 if (fstatat(dfd, filename, &stbuf, 0) < 0)
349 return -errno;
350
351 st = &stbuf;
352 }
353
354 if (!path) {
355 if (dfd == AT_FDCWD)
356 (void) safe_getcwd(&parent);
357 else
358 (void) fd_get_path(dfd, &parent);
359 }
360
361 read_only =
362 (path && path_startswith(path, "/usr")) ||
363 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
364
365 if (S_ISDIR(st->st_mode)) {
366 _cleanup_close_ int fd = -EBADF;
367 unsigned file_attr = 0;
368 usec_t crtime = 0;
369
370 if (!ret)
371 return 0;
372
373 if (!pretty) {
374 r = extract_image_basename(
375 filename,
376 image_class_suffix_to_string(c),
377 /* format_suffix= */ NULL,
378 &pretty_buffer,
379 /* ret_suffix= */ NULL);
380 if (r < 0)
381 return r;
382
383 pretty = pretty_buffer;
384 }
385
386 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
387 if (fd < 0)
388 return -errno;
389
390 if (btrfs_might_be_subvol(st)) {
391
392 r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
393 if (r < 0)
394 return r;
395 if (r > 0) {
396 BtrfsSubvolInfo info;
397
398 /* It's a btrfs subvolume */
399
400 r = btrfs_subvol_get_info_fd(fd, 0, &info);
401 if (r < 0)
402 return r;
403
404 r = image_new(IMAGE_SUBVOLUME,
405 c,
406 pretty,
407 path,
408 filename,
409 info.read_only || read_only,
410 info.otime,
411 0,
412 ret);
413 if (r < 0)
414 return r;
415
416 (void) image_update_quota(*ret, fd);
417 return 0;
418 }
419 }
420
421 /* Get directory creation time (not available everywhere, but that's OK */
422 (void) fd_getcrtime(fd, &crtime);
423
424 /* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
425 * supported everywhere we ignore failures. */
426 (void) read_attr_fd(fd, &file_attr);
427
428 /* It's just a normal directory. */
429 r = image_new(IMAGE_DIRECTORY,
430 c,
431 pretty,
432 path,
433 filename,
434 read_only || (file_attr & FS_IMMUTABLE_FL),
435 crtime,
436 0, /* we don't use mtime of stat() here, since it's not the time of last change of the tree, but only of the top-level dir */
437 ret);
438 if (r < 0)
439 return r;
440
441 return 0;
442
443 } else if (S_ISREG(st->st_mode) && endswith(filename, ".raw")) {
444 usec_t crtime = 0;
445
446 /* It's a RAW disk image */
447
448 if (!ret)
449 return 0;
450
451 (void) fd_getcrtime_at(dfd, filename, AT_SYMLINK_FOLLOW, &crtime);
452
453 if (!pretty) {
454 r = extract_image_basename(
455 filename,
456 image_class_suffix_to_string(c),
457 STRV_MAKE(".raw"),
458 &pretty_buffer,
459 /* ret_suffix= */ NULL);
460 if (r < 0)
461 return r;
462
463 pretty = pretty_buffer;
464 }
465
466 r = image_new(IMAGE_RAW,
467 c,
468 pretty,
469 path,
470 filename,
471 !(st->st_mode & 0222) || read_only,
472 crtime,
473 timespec_load(&st->st_mtim),
474 ret);
475 if (r < 0)
476 return r;
477
478 (*ret)->usage = (*ret)->usage_exclusive = st->st_blocks * 512;
479 (*ret)->limit = (*ret)->limit_exclusive = st->st_size;
480
481 return 0;
482
483 } else if (S_ISBLK(st->st_mode)) {
484 _cleanup_close_ int block_fd = -EBADF;
485 uint64_t size = UINT64_MAX;
486
487 /* A block device */
488
489 if (!ret)
490 return 0;
491
492 if (!pretty) {
493 r = extract_image_basename(
494 filename,
495 /* class_suffix= */ NULL,
496 /* format_suffix= */ NULL,
497 &pretty_buffer,
498 /* ret_suffix= */ NULL);
499 if (r < 0)
500 return r;
501
502 pretty = pretty_buffer;
503 }
504
505 block_fd = openat(dfd, filename, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
506 if (block_fd < 0)
507 log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
508 else {
509 /* Refresh stat data after opening the node */
510 if (fstat(block_fd, &stbuf) < 0)
511 return -errno;
512 st = &stbuf;
513
514 if (!S_ISBLK(st->st_mode)) /* Verify that what we opened is actually what we think it is */
515 return -ENOTTY;
516
517 if (!read_only) {
518 int state = 0;
519
520 if (ioctl(block_fd, BLKROGET, &state) < 0)
521 log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
522 else if (state)
523 read_only = true;
524 }
525
526 r = blockdev_get_device_size(block_fd, &size);
527 if (r < 0)
528 log_debug_errno(r, "Failed to issue BLKGETSIZE64 on device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
529
530 block_fd = safe_close(block_fd);
531 }
532
533 r = image_new(IMAGE_BLOCK,
534 c,
535 pretty,
536 path,
537 filename,
538 !(st->st_mode & 0222) || read_only,
539 0,
540 0,
541 ret);
542 if (r < 0)
543 return r;
544
545 if (!IN_SET(size, 0, UINT64_MAX))
546 (*ret)->usage = (*ret)->usage_exclusive = (*ret)->limit = (*ret)->limit_exclusive = size;
547
548 return 0;
549 }
550
551 return -EMEDIUMTYPE;
552 }
553
554 static const char *pick_image_search_path(ImageClass class) {
555 if (class < 0 || class >= _IMAGE_CLASS_MAX)
556 return NULL;
557
558 /* Use the initrd search path if there is one, otherwise use the common one */
559 return in_initrd() && image_search_path_initrd[class] ? image_search_path_initrd[class] : image_search_path[class];
560 }
561
562 static char **make_possible_filenames(ImageClass class, const char *image_name) {
563 _cleanup_strv_free_ char **l = NULL;
564
565 assert(image_name);
566
567 FOREACH_STRING(v_suffix, "", ".v")
568 FOREACH_STRING(format_suffix, "", ".raw") {
569 _cleanup_free_ char *j = NULL;
570 const char *class_suffix;
571
572 class_suffix = image_class_suffix_to_string(class);
573 if (class_suffix) {
574 j = strjoin(image_name, class_suffix, format_suffix, v_suffix);
575 if (!j)
576 return NULL;
577
578 if (strv_consume(&l, TAKE_PTR(j)) < 0)
579 return NULL;
580 }
581
582 j = strjoin(image_name, format_suffix, v_suffix);
583 if (!j)
584 return NULL;
585
586 if (strv_consume(&l, TAKE_PTR(j)) < 0)
587 return NULL;
588 }
589
590 return TAKE_PTR(l);
591 }
592
593 int image_find(ImageClass class,
594 const char *name,
595 const char *root,
596 Image **ret) {
597
598 int r;
599
600 assert(class >= 0);
601 assert(class < _IMAGE_CLASS_MAX);
602 assert(name);
603
604 /* There are no images with invalid names */
605 if (!image_name_is_valid(name))
606 return -ENOENT;
607
608 _cleanup_strv_free_ char **names = make_possible_filenames(class, name);
609 if (!names)
610 return -ENOMEM;
611
612 NULSTR_FOREACH(path, pick_image_search_path(class)) {
613 _cleanup_free_ char *resolved = NULL;
614 _cleanup_closedir_ DIR *d = NULL;
615 struct stat st;
616 int flags;
617
618 r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
619 if (r == -ENOENT)
620 continue;
621 if (r < 0)
622 return r;
623
624 /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people
625 * to symlink block devices into the search path. (For now, we disable that when operating
626 * relative to some root directory.) */
627 flags = root ? AT_SYMLINK_NOFOLLOW : 0;
628
629 STRV_FOREACH(n, names) {
630 _cleanup_free_ char *fname_buf = NULL;
631 const char *fname = *n;
632
633 if (fstatat(dirfd(d), fname, &st, flags) < 0) {
634 if (errno != ENOENT)
635 return -errno;
636
637 continue; /* Vanished while we were looking at it */
638 }
639
640 if (endswith(fname, ".raw")) {
641 if (!S_ISREG(st.st_mode)) {
642 log_debug("Ignoring non-regular file '%s' with .raw suffix.", fname);
643 continue;
644 }
645
646 } else if (endswith(fname, ".v")) {
647
648 if (!S_ISDIR(st.st_mode)) {
649 log_debug("Ignoring non-directory file '%s' with .v suffix.", fname);
650 continue;
651 }
652
653 _cleanup_free_ char *suffix = NULL;
654 suffix = strdup(ASSERT_PTR(startswith(fname, name)));
655 if (!suffix)
656 return -ENOMEM;
657
658 *ASSERT_PTR(endswith(suffix, ".v")) = 0;
659
660 _cleanup_free_ char *vp = path_join(resolved, fname);
661 if (!vp)
662 return -ENOMEM;
663
664 PickFilter filter = {
665 .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR),
666 .basename = name,
667 .architecture = _ARCHITECTURE_INVALID,
668 .suffix = STRV_MAKE(suffix),
669 };
670
671 _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
672 r = path_pick(root,
673 /* toplevel_fd= */ AT_FDCWD,
674 vp,
675 &filter,
676 PICK_ARCHITECTURE|PICK_TRIES,
677 &result);
678 if (r < 0) {
679 log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp);
680 continue;
681 }
682 if (!result.path) {
683 log_debug("Found versioned directory '%s', without matching entry, skipping: %m", vp);
684 continue;
685 }
686
687 /* Refresh the stat data for the discovered target */
688 st = result.st;
689
690 _cleanup_free_ char *bn = NULL;
691 r = path_extract_filename(result.path, &bn);
692 if (r < 0) {
693 log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", result.path);
694 continue;
695 }
696
697 fname_buf = path_join(fname, bn);
698 if (!fname_buf)
699 return log_oom();
700
701 fname = fname_buf;
702
703 } else if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) {
704 log_debug("Ignoring non-directory and non-block device file '%s' without suffix.", fname);
705 continue;
706 }
707
708 r = image_make(class, name, dirfd(d), resolved, fname, &st, ret);
709 if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
710 continue;
711 if (r < 0)
712 return r;
713
714 if (ret)
715 (*ret)->discoverable = true;
716
717 return 1;
718 }
719 }
720
721 if (class == IMAGE_MACHINE && streq(name, ".host")) {
722 r = image_make(class, ".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret);
723 if (r < 0)
724 return r;
725
726 if (ret)
727 (*ret)->discoverable = true;
728
729 return 1;
730 }
731
732 return -ENOENT;
733 };
734
735 int image_from_path(const char *path, Image **ret) {
736
737 /* Note that we don't set the 'discoverable' field of the returned object, because we don't check here whether
738 * the image is in the image search path. And if it is we don't know if the path we used is actually not
739 * overridden by another, different image earlier in the search path */
740
741 if (path_equal(path, "/"))
742 return image_make(IMAGE_MACHINE, ".host", AT_FDCWD, NULL, "/", NULL, ret);
743
744 return image_make(_IMAGE_CLASS_INVALID, NULL, AT_FDCWD, NULL, path, NULL, ret);
745 }
746
747 int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) {
748 if (image_name_is_valid(name_or_path))
749 return image_find(class, name_or_path, root, ret);
750
751 return image_from_path(name_or_path, ret);
752 }
753
754 int image_discover(
755 ImageClass class,
756 const char *root,
757 Hashmap *h) {
758
759 int r;
760
761 assert(class >= 0);
762 assert(class < _IMAGE_CLASS_MAX);
763 assert(h);
764
765 NULSTR_FOREACH(path, pick_image_search_path(class)) {
766 _cleanup_free_ char *resolved = NULL;
767 _cleanup_closedir_ DIR *d = NULL;
768
769 r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
770 if (r == -ENOENT)
771 continue;
772 if (r < 0)
773 return r;
774
775 FOREACH_DIRENT_ALL(de, d, return -errno) {
776 _cleanup_free_ char *pretty = NULL, *fname_buf = NULL;
777 _cleanup_(image_unrefp) Image *image = NULL;
778 const char *fname = de->d_name;
779 struct stat st;
780 int flags;
781
782 if (dot_or_dot_dot(fname))
783 continue;
784
785 /* As mentioned above, we follow symlinks on this fstatat(), because we want to
786 * permit people to symlink block devices into the search path. */
787 flags = root ? AT_SYMLINK_NOFOLLOW : 0;
788 if (fstatat(dirfd(d), fname, &st, flags) < 0) {
789 if (errno == ENOENT)
790 continue;
791
792 return -errno;
793 }
794
795 if (S_ISREG(st.st_mode)) {
796 r = extract_image_basename(
797 fname,
798 image_class_suffix_to_string(class),
799 STRV_MAKE(".raw"),
800 &pretty,
801 /* suffix= */ NULL);
802 if (r < 0) {
803 log_debug_errno(r, "Skipping directory entry '%s', which doesn't look like an image.", fname);
804 continue;
805 }
806 } else if (S_ISDIR(st.st_mode)) {
807 const char *v;
808
809 v = endswith(fname, ".v");
810 if (v) {
811 _cleanup_free_ char *suffix = NULL, *nov = NULL;
812
813 nov = strndup(fname, v - fname); /* Chop off the .v */
814 if (!nov)
815 return -ENOMEM;
816
817 r = extract_image_basename(
818 nov,
819 image_class_suffix_to_string(class),
820 STRV_MAKE(".raw", ""),
821 &pretty,
822 &suffix);
823 if (r < 0) {
824 log_debug_errno(r, "Skipping directory entry '%s', which doesn't look like a versioned image.", fname);
825 continue;
826 }
827
828 _cleanup_free_ char *vp = path_join(resolved, fname);
829 if (!vp)
830 return -ENOMEM;
831
832 PickFilter filter = {
833 .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR),
834 .basename = pretty,
835 .architecture = _ARCHITECTURE_INVALID,
836 .suffix = STRV_MAKE(suffix),
837 };
838
839 _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
840 r = path_pick(root,
841 /* toplevel_fd= */ AT_FDCWD,
842 vp,
843 &filter,
844 PICK_ARCHITECTURE|PICK_TRIES,
845 &result);
846 if (r < 0) {
847 log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp);
848 continue;
849 }
850 if (!result.path) {
851 log_debug("Found versioned directory '%s', without matching entry, skipping: %m", vp);
852 continue;
853 }
854
855 /* Refresh the stat data for the discovered target */
856 st = result.st;
857
858 _cleanup_free_ char *bn = NULL;
859 r = path_extract_filename(result.path, &bn);
860 if (r < 0) {
861 log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", result.path);
862 continue;
863 }
864
865 fname_buf = path_join(fname, bn);
866 if (!fname_buf)
867 return log_oom();
868
869 fname = fname_buf;
870 } else {
871 r = extract_image_basename(
872 fname,
873 image_class_suffix_to_string(class),
874 /* format_suffix= */ NULL,
875 &pretty,
876 /* ret_suffix= */ NULL);
877 if (r < 0) {
878 log_debug_errno(r, "Skipping directory entry '%s', which doesn't look like an image.", fname);
879 continue;
880 }
881 }
882
883 } else if (S_ISBLK(st.st_mode)) {
884 r = extract_image_basename(
885 fname,
886 /* class_suffix= */ NULL,
887 /* format_suffix= */ NULL,
888 &pretty,
889 /* ret_v_suffix= */ NULL);
890 if (r < 0) {
891 log_debug_errno(r, "Skipping directory entry '%s', which doesn't look like an image.", fname);
892 continue;
893 }
894 } else {
895 log_debug("Skipping directory entry '%s', which is neither regular file, directory nor block device.", fname);
896 continue;
897 }
898
899 if (hashmap_contains(h, pretty))
900 continue;
901
902 r = image_make(class, pretty, dirfd(d), resolved, fname, &st, &image);
903 if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
904 continue;
905 if (r < 0)
906 return r;
907
908 image->discoverable = true;
909
910 r = hashmap_put(h, image->name, image);
911 if (r < 0)
912 return r;
913
914 TAKE_PTR(image);
915 }
916 }
917
918 if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
919 _cleanup_(image_unrefp) Image *image = NULL;
920
921 r = image_make(IMAGE_MACHINE, ".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image);
922 if (r < 0)
923 return r;
924
925 image->discoverable = true;
926
927 r = hashmap_put(h, image->name, image);
928 if (r < 0)
929 return r;
930
931 image = NULL;
932 }
933
934 return 0;
935 }
936
937 int image_remove(Image *i) {
938 _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
939 _cleanup_strv_free_ char **settings = NULL;
940 _cleanup_free_ char *roothash = NULL;
941 int r;
942
943 assert(i);
944
945 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
946 return -EROFS;
947
948 settings = image_settings_path(i);
949 if (!settings)
950 return -ENOMEM;
951
952 r = image_roothash_path(i, &roothash);
953 if (r < 0)
954 return r;
955
956 /* Make sure we don't interfere with a running nspawn */
957 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
958 if (r < 0)
959 return r;
960
961 switch (i->type) {
962
963 case IMAGE_SUBVOLUME:
964
965 /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
966 * big guns */
967 if (unlink(i->path) < 0) {
968 r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
969 if (r < 0)
970 return r;
971 }
972
973 break;
974
975 case IMAGE_DIRECTORY:
976 /* Allow deletion of read-only directories */
977 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
978 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
979 if (r < 0)
980 return r;
981
982 break;
983
984 case IMAGE_BLOCK:
985
986 /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
987 * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
988 * the thing (it's most likely a symlink after all). */
989
990 if (path_startswith(i->path, "/dev"))
991 break;
992
993 _fallthrough_;
994 case IMAGE_RAW:
995 if (unlink(i->path) < 0)
996 return -errno;
997 break;
998
999 default:
1000 return -EOPNOTSUPP;
1001 }
1002
1003 STRV_FOREACH(j, settings)
1004 if (unlink(*j) < 0 && errno != ENOENT)
1005 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
1006
1007 if (unlink(roothash) < 0 && errno != ENOENT)
1008 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
1009
1010 return 0;
1011 }
1012
1013 static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
1014 _cleanup_free_ char *fn = NULL, *rs = NULL;
1015 int r;
1016
1017 fn = strjoin(new_name, suffix);
1018 if (!fn)
1019 return -ENOMEM;
1020
1021 r = file_in_same_dir(path, fn, &rs);
1022 if (r < 0)
1023 return r;
1024
1025 return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
1026 }
1027
1028 int image_rename(Image *i, const char *new_name) {
1029 _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
1030 _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
1031 _cleanup_strv_free_ char **settings = NULL;
1032 unsigned file_attr = 0;
1033 int r;
1034
1035 assert(i);
1036
1037 if (!image_name_is_valid(new_name))
1038 return -EINVAL;
1039
1040 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
1041 return -EROFS;
1042
1043 settings = image_settings_path(i);
1044 if (!settings)
1045 return -ENOMEM;
1046
1047 r = image_roothash_path(i, &roothash);
1048 if (r < 0)
1049 return r;
1050
1051 /* Make sure we don't interfere with a running nspawn */
1052 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
1053 if (r < 0)
1054 return r;
1055
1056 /* Make sure nobody takes the new name, between the time we
1057 * checked it is currently unused in all search paths, and the
1058 * time we take possession of it */
1059 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
1060 if (r < 0)
1061 return r;
1062
1063 r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
1064 if (r >= 0)
1065 return -EEXIST;
1066 if (r != -ENOENT)
1067 return r;
1068
1069 switch (i->type) {
1070
1071 case IMAGE_DIRECTORY:
1072 /* Turn of the immutable bit while we rename the image, so that we can rename it */
1073 (void) read_attr_at(AT_FDCWD, i->path, &file_attr);
1074
1075 if (file_attr & FS_IMMUTABLE_FL)
1076 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
1077
1078 _fallthrough_;
1079 case IMAGE_SUBVOLUME:
1080 r = file_in_same_dir(i->path, new_name, &new_path);
1081 break;
1082
1083 case IMAGE_BLOCK:
1084
1085 /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
1086 if (path_startswith(i->path, "/dev"))
1087 return -EROFS;
1088
1089 r = file_in_same_dir(i->path, new_name, &new_path);
1090 break;
1091
1092 case IMAGE_RAW: {
1093 const char *fn;
1094
1095 fn = strjoina(new_name, ".raw");
1096
1097 r = file_in_same_dir(i->path, fn, &new_path);
1098 break;
1099 }
1100
1101 default:
1102 return -EOPNOTSUPP;
1103 }
1104 if (r < 0)
1105 return r;
1106
1107 nn = strdup(new_name);
1108 if (!nn)
1109 return -ENOMEM;
1110
1111 r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
1112 if (r < 0)
1113 return r;
1114
1115 /* Restore the immutable bit, if it was set before */
1116 if (file_attr & FS_IMMUTABLE_FL)
1117 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
1118
1119 free_and_replace(i->path, new_path);
1120 free_and_replace(i->name, nn);
1121
1122 STRV_FOREACH(j, settings) {
1123 r = rename_auxiliary_file(*j, new_name, ".nspawn");
1124 if (r < 0 && r != -ENOENT)
1125 log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
1126 }
1127
1128 r = rename_auxiliary_file(roothash, new_name, ".roothash");
1129 if (r < 0 && r != -ENOENT)
1130 log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
1131
1132 return 0;
1133 }
1134
1135 static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
1136 _cleanup_free_ char *fn = NULL, *rs = NULL;
1137 int r;
1138
1139 fn = strjoin(new_name, suffix);
1140 if (!fn)
1141 return -ENOMEM;
1142
1143 r = file_in_same_dir(path, fn, &rs);
1144 if (r < 0)
1145 return r;
1146
1147 return copy_file_atomic(path, rs, 0664, COPY_REFLINK);
1148 }
1149
1150 int image_clone(Image *i, const char *new_name, bool read_only) {
1151 _cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT;
1152 _cleanup_strv_free_ char **settings = NULL;
1153 _cleanup_free_ char *roothash = NULL;
1154 const char *new_path;
1155 int r;
1156
1157 assert(i);
1158
1159 if (!image_name_is_valid(new_name))
1160 return -EINVAL;
1161
1162 settings = image_settings_path(i);
1163 if (!settings)
1164 return -ENOMEM;
1165
1166 r = image_roothash_path(i, &roothash);
1167 if (r < 0)
1168 return r;
1169
1170 /* Make sure nobody takes the new name, between the time we
1171 * checked it is currently unused in all search paths, and the
1172 * time we take possession of it */
1173 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
1174 if (r < 0)
1175 return r;
1176
1177 r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
1178 if (r >= 0)
1179 return -EEXIST;
1180 if (r != -ENOENT)
1181 return r;
1182
1183 switch (i->type) {
1184
1185 case IMAGE_SUBVOLUME:
1186 case IMAGE_DIRECTORY:
1187 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
1188 * directory. */
1189
1190 new_path = strjoina("/var/lib/machines/", new_name);
1191
1192 r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, new_path,
1193 (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
1194 BTRFS_SNAPSHOT_FALLBACK_COPY |
1195 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
1196 BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
1197 BTRFS_SNAPSHOT_RECURSIVE |
1198 BTRFS_SNAPSHOT_QUOTA);
1199 if (r >= 0)
1200 /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
1201 (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
1202
1203 break;
1204
1205 case IMAGE_RAW:
1206 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
1207
1208 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644,
1209 COPY_REFLINK|COPY_CRTIME|COPY_NOCOW_AFTER);
1210 break;
1211
1212 case IMAGE_BLOCK:
1213 default:
1214 return -EOPNOTSUPP;
1215 }
1216
1217 if (r < 0)
1218 return r;
1219
1220 STRV_FOREACH(j, settings) {
1221 r = clone_auxiliary_file(*j, new_name, ".nspawn");
1222 if (r < 0 && r != -ENOENT)
1223 log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
1224 }
1225
1226 r = clone_auxiliary_file(roothash, new_name, ".roothash");
1227 if (r < 0 && r != -ENOENT)
1228 log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
1229
1230 return 0;
1231 }
1232
1233 int image_read_only(Image *i, bool b) {
1234 _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
1235 int r;
1236
1237 assert(i);
1238
1239 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
1240 return -EROFS;
1241
1242 /* Make sure we don't interfere with a running nspawn */
1243 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
1244 if (r < 0)
1245 return r;
1246
1247 switch (i->type) {
1248
1249 case IMAGE_SUBVOLUME:
1250
1251 /* Note that we set the flag only on the top-level
1252 * subvolume of the image. */
1253
1254 r = btrfs_subvol_set_read_only(i->path, b);
1255 if (r < 0)
1256 return r;
1257
1258 break;
1259
1260 case IMAGE_DIRECTORY:
1261 /* For simple directory trees we cannot use the access
1262 mode of the top-level directory, since it has an
1263 effect on the container itself. However, we can
1264 use the "immutable" flag, to at least make the
1265 top-level directory read-only. It's not as good as
1266 a read-only subvolume, but at least something, and
1267 we can read the value back. */
1268
1269 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL, NULL);
1270 if (r < 0)
1271 return r;
1272
1273 break;
1274
1275 case IMAGE_RAW: {
1276 struct stat st;
1277
1278 if (stat(i->path, &st) < 0)
1279 return -errno;
1280
1281 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
1282 return -errno;
1283
1284 /* If the images is now read-only, it's a good time to
1285 * defrag it, given that no write patterns will
1286 * fragment it again. */
1287 if (b)
1288 (void) btrfs_defrag(i->path);
1289 break;
1290 }
1291
1292 case IMAGE_BLOCK: {
1293 _cleanup_close_ int fd = -EBADF;
1294 struct stat st;
1295 int state = b;
1296
1297 fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
1298 if (fd < 0)
1299 return -errno;
1300
1301 if (fstat(fd, &st) < 0)
1302 return -errno;
1303 if (!S_ISBLK(st.st_mode))
1304 return -ENOTTY;
1305
1306 if (ioctl(fd, BLKROSET, &state) < 0)
1307 return -errno;
1308
1309 break;
1310 }
1311
1312 default:
1313 return -EOPNOTSUPP;
1314 }
1315
1316 i->read_only = b;
1317 return 0;
1318 }
1319
1320 static void make_lock_dir(void) {
1321 (void) mkdir_p("/run/systemd/nspawn", 0755);
1322 (void) mkdir("/run/systemd/nspawn/locks", 0700);
1323 }
1324
1325 int image_path_lock(
1326 const char *path,
1327 int operation,
1328 LockFile *ret_global,
1329 LockFile *ret_local) {
1330
1331 _cleanup_free_ char *p = NULL;
1332 LockFile t = LOCK_FILE_INIT;
1333 struct stat st;
1334 bool exclusive;
1335 int r;
1336
1337 assert(path);
1338 assert(ret_local);
1339
1340 /* Locks an image path. This actually creates two locks: one "local" one, next to the image path
1341 * itself, which might be shared via NFS. And another "global" one, in /run, that uses the
1342 * device/inode number. This has the benefit that we can even lock a tree that is a mount point,
1343 * correctly. */
1344
1345 if (!path_is_absolute(path))
1346 return -EINVAL;
1347
1348 switch (operation & (LOCK_SH|LOCK_EX)) {
1349 case LOCK_SH:
1350 exclusive = false;
1351 break;
1352 case LOCK_EX:
1353 exclusive = true;
1354 break;
1355 default:
1356 return -EINVAL;
1357 }
1358
1359 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
1360 *ret_local = LOCK_FILE_INIT;
1361 if (ret_global)
1362 *ret_global = LOCK_FILE_INIT;
1363 return 0;
1364 }
1365
1366 /* Prohibit taking exclusive locks on the host image. We can't allow this, since we ourselves are
1367 * running off it after all, and we don't want any images to manipulate the host image. We make an
1368 * exception for shared locks however: we allow those (and make them NOPs since there's no point in
1369 * taking them if there can't be exclusive locks). Strictly speaking these are questionable as well,
1370 * since it means changes made to the host might propagate to the container as they happen (and a
1371 * shared lock kinda suggests that no changes happen at all while it is in place), but it's too
1372 * useful not to allow read-only containers off the host root, hence let's support this, and trust
1373 * the user to do the right thing with this. */
1374 if (path_equal(path, "/")) {
1375 if (exclusive)
1376 return -EBUSY;
1377
1378 *ret_local = LOCK_FILE_INIT;
1379 if (ret_global)
1380 *ret_global = LOCK_FILE_INIT;
1381 return 0;
1382 }
1383
1384 if (ret_global) {
1385 if (stat(path, &st) >= 0) {
1386 if (S_ISBLK(st.st_mode))
1387 r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
1388 else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
1389 r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
1390 else
1391 return -ENOTTY;
1392 if (r < 0)
1393 return -ENOMEM;
1394 }
1395 }
1396
1397 /* For block devices we don't need the "local" lock, as the major/minor lock above should be
1398 * sufficient, since block devices are host local anyway. */
1399 if (!path_startswith(path, "/dev/")) {
1400 r = make_lock_file_for(path, operation, &t);
1401 if (r < 0) {
1402 if (!exclusive && r == -EROFS)
1403 log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path);
1404 else
1405 return r;
1406 }
1407 }
1408
1409 if (p) {
1410 make_lock_dir();
1411
1412 r = make_lock_file(p, operation, ret_global);
1413 if (r < 0) {
1414 release_lock_file(&t);
1415 return r;
1416 }
1417 } else if (ret_global)
1418 *ret_global = LOCK_FILE_INIT;
1419
1420 *ret_local = t;
1421 return 0;
1422 }
1423
1424 int image_set_limit(Image *i, uint64_t referenced_max) {
1425 int r;
1426
1427 assert(i);
1428
1429 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
1430 return -EROFS;
1431
1432 if (i->type != IMAGE_SUBVOLUME)
1433 return -EOPNOTSUPP;
1434
1435 /* We set the quota both for the subvolume as well as for the
1436 * subtree. The latter is mostly for historical reasons, since
1437 * we didn't use to have a concept of subtree quota, and hence
1438 * only modified the subvolume quota. */
1439
1440 (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
1441 (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
1442 r = btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
1443 if (r < 0)
1444 return r;
1445
1446 (void) image_update_quota(i, -EBADF);
1447 return 0;
1448 }
1449
1450 int image_read_metadata(Image *i, const ImagePolicy *image_policy) {
1451 _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
1452 int r;
1453
1454 assert(i);
1455
1456 r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
1457 if (r < 0)
1458 return r;
1459
1460 switch (i->type) {
1461
1462 case IMAGE_SUBVOLUME:
1463 case IMAGE_DIRECTORY: {
1464 _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **sysext_release = NULL, **confext_release = NULL;
1465 _cleanup_free_ char *hostname = NULL, *path = NULL;
1466 sd_id128_t machine_id = SD_ID128_NULL;
1467
1468 if (i->class == IMAGE_SYSEXT) {
1469 r = extension_has_forbidden_content(i->path);
1470 if (r < 0)
1471 return r;
1472 if (r > 0)
1473 return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
1474 "Conflicting content found in image %s, refusing.",
1475 i->name);
1476 }
1477
1478 r = chase("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path, NULL);
1479 if (r < 0 && r != -ENOENT)
1480 log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
1481 else if (r >= 0) {
1482 r = read_etc_hostname(path, &hostname);
1483 if (r < 0)
1484 log_debug_errno(r, "Failed to read /etc/hostname of image %s: %m", i->name);
1485 }
1486
1487 path = mfree(path);
1488
1489 r = id128_get_machine(i->path, &machine_id);
1490 if (r < 0)
1491 log_debug_errno(r, "Failed to read machine ID in image %s, ignoring: %m", i->name);
1492
1493 r = chase("/etc/machine-info", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path, NULL);
1494 if (r < 0 && r != -ENOENT)
1495 log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
1496 else if (r >= 0) {
1497 r = load_env_file_pairs(NULL, path, &machine_info);
1498 if (r < 0)
1499 log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
1500 }
1501
1502 r = load_os_release_pairs(i->path, &os_release);
1503 if (r < 0)
1504 log_debug_errno(r, "Failed to read os-release in image, ignoring: %m");
1505
1506 r = load_extension_release_pairs(i->path, IMAGE_SYSEXT, i->name, /* relax_extension_release_check= */ false, &sysext_release);
1507 if (r < 0)
1508 log_debug_errno(r, "Failed to read sysext-release in image, ignoring: %m");
1509
1510 r = load_extension_release_pairs(i->path, IMAGE_CONFEXT, i->name, /* relax_extension_release_check= */ false, &confext_release);
1511 if (r < 0)
1512 log_debug_errno(r, "Failed to read confext-release in image, ignoring: %m");
1513
1514 free_and_replace(i->hostname, hostname);
1515 i->machine_id = machine_id;
1516 strv_free_and_replace(i->machine_info, machine_info);
1517 strv_free_and_replace(i->os_release, os_release);
1518 strv_free_and_replace(i->sysext_release, sysext_release);
1519 strv_free_and_replace(i->confext_release, confext_release);
1520 break;
1521 }
1522
1523 case IMAGE_RAW:
1524 case IMAGE_BLOCK: {
1525 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
1526 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
1527 DissectImageFlags flags =
1528 DISSECT_IMAGE_GENERIC_ROOT |
1529 DISSECT_IMAGE_REQUIRE_ROOT |
1530 DISSECT_IMAGE_RELAX_VAR_CHECK |
1531 DISSECT_IMAGE_READ_ONLY |
1532 DISSECT_IMAGE_USR_NO_ROOT |
1533 DISSECT_IMAGE_ADD_PARTITION_DEVICES |
1534 DISSECT_IMAGE_PIN_PARTITION_DEVICES |
1535 DISSECT_IMAGE_VALIDATE_OS |
1536 DISSECT_IMAGE_VALIDATE_OS_EXT |
1537 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY;
1538
1539 r = loop_device_make_by_path(
1540 i->path,
1541 O_RDONLY,
1542 /* sector_size= */ UINT32_MAX,
1543 LO_FLAGS_PARTSCAN,
1544 LOCK_SH,
1545 &d);
1546 if (r < 0)
1547 return r;
1548
1549 r = dissect_loop_device(
1550 d,
1551 /* verity= */ NULL,
1552 /* mount_options= */ NULL,
1553 image_policy,
1554 flags,
1555 &m);
1556 if (r < 0)
1557 return r;
1558
1559 r = dissected_image_acquire_metadata(
1560 m,
1561 /* userns_fd= */ -EBADF,
1562 flags);
1563 if (r < 0)
1564 return r;
1565
1566 free_and_replace(i->hostname, m->hostname);
1567 i->machine_id = m->machine_id;
1568 strv_free_and_replace(i->machine_info, m->machine_info);
1569 strv_free_and_replace(i->os_release, m->os_release);
1570 strv_free_and_replace(i->sysext_release, m->sysext_release);
1571 strv_free_and_replace(i->confext_release, m->confext_release);
1572
1573 break;
1574 }
1575
1576 default:
1577 return -EOPNOTSUPP;
1578 }
1579
1580 i->metadata_valid = true;
1581
1582 return 0;
1583 }
1584
1585 int image_name_lock(const char *name, int operation, LockFile *ret) {
1586 const char *p;
1587
1588 assert(name);
1589 assert(ret);
1590
1591 /* Locks an image name, regardless of the precise path used. */
1592
1593 if (streq(name, ".host"))
1594 return -EBUSY;
1595
1596 if (!image_name_is_valid(name))
1597 return -EINVAL;
1598
1599 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
1600 *ret = (LockFile) LOCK_FILE_INIT;
1601 return 0;
1602 }
1603
1604 make_lock_dir();
1605
1606 p = strjoina("/run/systemd/nspawn/locks/name-", name);
1607 return make_lock_file(p, operation, ret);
1608 }
1609
1610 bool image_in_search_path(
1611 ImageClass class,
1612 const char *root,
1613 const char *image) {
1614
1615 assert(image);
1616
1617 NULSTR_FOREACH(path, pick_image_search_path(class)) {
1618 const char *p, *q;
1619 size_t k;
1620
1621 if (!empty_or_root(root)) {
1622 q = path_startswith(path, root);
1623 if (!q)
1624 continue;
1625 } else
1626 q = path;
1627
1628 p = path_startswith(q, path);
1629 if (!p)
1630 continue;
1631
1632 /* Make sure there's a filename following */
1633 k = strcspn(p, "/");
1634 if (k == 0)
1635 continue;
1636
1637 p += k;
1638
1639 /* Accept trailing slashes */
1640 if (p[strspn(p, "/")] == 0)
1641 return true;
1642 }
1643
1644 return false;
1645 }
1646
1647 int image_to_json(const struct Image *img, sd_json_variant **ret) {
1648 assert(img);
1649
1650 return sd_json_buildo(
1651 ret,
1652 SD_JSON_BUILD_PAIR_STRING("Type", image_type_to_string(img->type)),
1653 SD_JSON_BUILD_PAIR_STRING("Class", image_class_to_string(img->class)),
1654 SD_JSON_BUILD_PAIR_STRING("Name", img->name),
1655 SD_JSON_BUILD_PAIR_CONDITION(!!img->path, "Path", SD_JSON_BUILD_STRING(img->path)),
1656 SD_JSON_BUILD_PAIR_BOOLEAN("ReadOnly", img->read_only),
1657 SD_JSON_BUILD_PAIR_CONDITION(img->crtime != 0, "CreationTimestamp", SD_JSON_BUILD_UNSIGNED(img->crtime)),
1658 SD_JSON_BUILD_PAIR_CONDITION(img->mtime != 0, "ModificationTimestamp", SD_JSON_BUILD_UNSIGNED(img->mtime)),
1659 SD_JSON_BUILD_PAIR_CONDITION(img->usage != UINT64_MAX, "Usage", SD_JSON_BUILD_UNSIGNED(img->usage)),
1660 SD_JSON_BUILD_PAIR_CONDITION(img->usage_exclusive != UINT64_MAX, "UsageExclusive", SD_JSON_BUILD_UNSIGNED(img->usage_exclusive)),
1661 SD_JSON_BUILD_PAIR_CONDITION(img->limit != UINT64_MAX, "Limit", SD_JSON_BUILD_UNSIGNED(img->limit)),
1662 SD_JSON_BUILD_PAIR_CONDITION(img->limit_exclusive != UINT64_MAX, "LimitExclusive", SD_JSON_BUILD_UNSIGNED(img->limit_exclusive)));
1663 }
1664
1665 static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
1666 [IMAGE_DIRECTORY] = "directory",
1667 [IMAGE_SUBVOLUME] = "subvolume",
1668 [IMAGE_RAW] = "raw",
1669 [IMAGE_BLOCK] = "block",
1670 };
1671
1672 DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);