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