sd_id128_t fsuuid, vuuid;
/* If a root hash is supplied, then we use the root partition that has a UUID that match the
- * first 128bit of the root hash. And we use the verity partition that has a UUID that match
- * the final 128bit. */
+ * first 128-bit of the root hash. And we use the verity partition that has a UUID that match
+ * the final 128-bit. */
if (verity->root_hash_size < sizeof(sd_id128_t))
return -EINVAL;
}
if (m->partitions[type.designator].found) {
+ int c;
+
/* For most partition types the first one we see wins. Except for the
* rootfs and /usr, where we do a version compare of the label, and
* let the newest version win. This permits a simple A/B versioning
* scheme in OS images. */
- if (compare_arch(type.arch, m->partitions[type.designator].architecture) <= 0)
+ c = compare_arch(type.arch, m->partitions[type.designator].architecture);
+ if (c < 0) /* the arch we already found is better than the one we found now */
continue;
-
- if (!partition_designator_is_versioned(type.designator) ||
- strverscmp_improved(m->partitions[type.designator].label, label) >= 0)
+ if (c == 0 && /* same arch? then go by version in label */
+ (!partition_designator_is_versioned(type.designator) ||
+ strverscmp_improved(label, m->partitions[type.designator].label) <= 0))
continue;
dissected_partition_done(m->partitions + type.designator);
return 1;
}
+static int mount_point_is_available(const char *where, const char *path, bool missing_ok) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ /* Check whether <path> is suitable as a mountpoint, i.e. is an empty directory
+ * or does not exist at all (when missing_ok). */
+
+ r = chase(path, where, CHASE_PREFIX_ROOT, &p, NULL);
+ if (r == -ENOENT)
+ return missing_ok;
+ if (r < 0)
+ return log_debug_errno(r, "Failed to chase \"%s\": %m", path);
+
+ r = dir_is_empty(p, /* ignore_hidden_or_backup= */ false);
+ if (r == -ENOTDIR)
+ return false;
+ if (r < 0)
+ return log_debug_errno(r, "Failed to check directory \"%s\": %m", p);
+ return true;
+}
+
int dissected_image_mount(
DissectedImage *m,
const char *where,
uid_t uid_range,
DissectImageFlags flags) {
- int r, xbootldr_mounted;
+ int r;
assert(m);
assert(where);
if (r < 0)
return r;
- xbootldr_mounted = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
- if (xbootldr_mounted < 0)
- return xbootldr_mounted;
+ int slash_boot_is_available;
+ r = slash_boot_is_available = mount_point_is_available(where, "/boot", /* missing_ok = */ true);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ r = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
+ if (r < 0)
+ return r;
+ slash_boot_is_available = !r;
+ }
if (m->partitions[PARTITION_ESP].found) {
- int esp_done = false;
+ const char *esp_path = NULL;
- /* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
- * exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
+ /* Mount the ESP to /boot/ if it exists and is empty and we didn't already mount the XBOOTLDR
+ * partition into it. Otherwise, use /efi instead, but only if it exists and is empty. */
- r = chase("/efi", where, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r < 0) {
- if (r != -ENOENT)
+ if (slash_boot_is_available) {
+ r = mount_point_is_available(where, "/boot", /* missing_ok = */ false);
+ if (r < 0)
return r;
-
- /* /efi doesn't exist. Let's see if /boot is suitable then */
-
- if (!xbootldr_mounted) {
- _cleanup_free_ char *p = NULL;
-
- r = chase("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else if (dir_is_empty(p, /* ignore_hidden_or_backup= */ false) > 0) {
- /* It exists and is an empty directory. Let's mount the ESP there. */
- r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, "/boot", uid_shift, uid_range, flags);
- if (r < 0)
- return r;
-
- esp_done = true;
- }
- }
+ if (r > 0)
+ esp_path = "/boot";
}
- if (!esp_done) {
- /* OK, let's mount the ESP now to /efi (possibly creating the dir if missing) */
+ if (!esp_path) {
+ r = mount_point_is_available(where, "/efi", /* missing_ok = */ true);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ esp_path = "/efi";
+ }
- r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, "/efi", uid_shift, uid_range, flags);
+ if (esp_path) {
+ /* OK, let's mount the ESP now (possibly creating the dir if missing) */
+ r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, esp_path, uid_shift, uid_range, flags);
if (r < 0)
return r;
}
try_again:
/* Device is being removed by another process. Let's wait for a while. */
- (void) usleep(2 * USEC_PER_MSEC);
+ (void) usleep_safe(2 * USEC_PER_MSEC);
}
/* All trials failed or a conflicting verity device exists. Let's try to activate with a unique name. */
return -EINVAL;
if (p->size > 4*1024*1024) /* Signature data cannot possible be larger than 4M, refuse that */
- return -EFBIG;
+ return log_debug_errno(SYNTHETIC_ERRNO(EFBIG), "Verity signature partition is larger than 4M, refusing.");
buf = new(char, p->size+1);
if (!buf)
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_(rmdir_and_freep) char *created_dir = NULL;
- _cleanup_free_ char *temp = NULL;
+ _cleanup_free_ char *dir = NULL;
int r;
/* Mounts an OS image at a temporary place, inside a newly created mount namespace of our own. This
* easily. */
assert(image);
- assert(ret_directory);
assert(ret_loop_device);
/* We intend to mount this right-away, hence add the partitions if needed and pin them. */
if (r < 0)
return log_error_errno(r, "Failed to load root hash data: %m");
- r = tempfn_random_child(NULL, program_invocation_short_name, &temp);
- if (r < 0)
- return log_error_errno(r, "Failed to generate temporary mount directory: %m");
-
r = loop_device_make_by_path(
image,
FLAGS_SET(flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR,
if (r < 0)
return log_error_errno(r, "Failed to detach mount namespace: %m");
- r = mkdir_p(temp, 0700);
+ r = mkdir_p("/run/systemd/mount-rootfs", 0555);
if (r < 0)
return log_error_errno(r, "Failed to create mount point: %m");
- created_dir = TAKE_PTR(temp);
-
- r = dissected_image_mount_and_warn(dissected_image, created_dir, UID_INVALID, UID_INVALID, flags);
+ r = dissected_image_mount_and_warn(
+ dissected_image,
+ "/run/systemd/mount-rootfs",
+ /* uid_shift= */ UID_INVALID,
+ /* uid_range= */ UID_INVALID,
+ flags);
if (r < 0)
return r;
if (r < 0)
return log_error_errno(r, "Failed to relinquish DM and loopback block devices: %m");
+ if (ret_directory) {
+ dir = strdup("/run/systemd/mount-rootfs");
+ if (!dir)
+ return log_oom();
+ }
+
if (ret_dir_fd) {
_cleanup_close_ int dir_fd = -EBADF;
- dir_fd = open(created_dir, O_CLOEXEC|O_DIRECTORY);
+ dir_fd = open("/run/systemd/mount-rootfs", O_CLOEXEC|O_DIRECTORY);
if (dir_fd < 0)
return log_error_errno(errno, "Failed to open mount point directory: %m");
*ret_dir_fd = TAKE_FD(dir_fd);
}
- *ret_directory = TAKE_PTR(created_dir);
- *ret_loop_device = TAKE_PTR(d);
+ if (ret_directory)
+ *ret_directory = TAKE_PTR(dir);
+ *ret_loop_device = TAKE_PTR(d);
return 0;
}