#include "hexdecoct.h"
#include "hostname-util.h"
#include "id128-util.h"
+#include "mkdir.h"
#include "mount-util.h"
#include "mountpoint-util.h"
+#include "namespace-util.h"
#include "nulstr-util.h"
#include "os-util.h"
#include "path-util.h"
break;
r = -errno;
if (r == -EINVAL) {
- struct loop_info64 info;
+ /* If we are running on a block device that has partition scanning off, return an
+ * explicit recognizable error about this, so that callers can generate a proper
+ * message explaining the situation. */
- /* If we are running on a loop device that has partition scanning off, return
- * an explicit recognizable error about this, so that callers can generate a
- * proper message explaining the situation. */
-
- if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0) {
-#if HAVE_VALGRIND_MEMCHECK_H
- /* Valgrind currently doesn't know LOOP_GET_STATUS64. Remove this once it does */
- VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info));
-#endif
+ r = blockdev_partscan_enabled(fd);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return log_debug_errno(EPROTONOSUPPORT,
+ "Device is a loop device and partition scanning is off!");
- if ((info.lo_flags & LO_FLAGS_PARTSCAN) == 0)
- return log_debug_errno(EPROTONOSUPPORT,
- "Device is a loop device and partition scanning is off!");
- }
+ return -EINVAL; /* original error */
}
if (r != -EBUSY)
return r;
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
+ const MountOptions *mount_options,
DissectImageFlags flags,
DissectedImage **ret) {
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
- _cleanup_free_ char *t = NULL, *n = NULL;
- const char *fstype = NULL;
+ _cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
+ const char *fstype = NULL, *options = NULL;
/* OK, we have found a file system, that's our root partition then. */
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
m->verity = root_hash && verity_data;
m->can_verity = !!verity_data;
+ options = mount_options_from_part(mount_options, 0);
+ if (options) {
+ o = strdup(options);
+ if (!o)
+ return -ENOMEM;
+ }
+
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = !m->verity,
.architecture = _ARCHITECTURE_INVALID,
.fstype = TAKE_PTR(t),
.node = TAKE_PTR(n),
+ .mount_options = TAKE_PTR(o),
};
m->encrypted = streq_ptr(fstype, "crypto_LUKS");
}
if (designator != _PARTITION_DESIGNATOR_INVALID) {
- _cleanup_free_ char *t = NULL, *n = NULL;
+ _cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
+ const char *options = NULL;
/* First one wins */
if (m->partitions[designator].found)
if (!n)
return -ENOMEM;
+ options = mount_options_from_part(mount_options, nr);
+ if (options) {
+ o = strdup(options);
+ if (!o)
+ return -ENOMEM;
+ }
+
m->partitions[designator] = (DissectedPartition) {
.found = true,
.partno = nr,
.node = TAKE_PTR(n),
.fstype = TAKE_PTR(t),
.uuid = id,
+ .mount_options = TAKE_PTR(o),
};
}
break;
case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
- _cleanup_free_ char *n = NULL;
+ _cleanup_free_ char *n = NULL, *o = NULL;
sd_id128_t id = SD_ID128_NULL;
- const char *sid;
+ const char *sid, *options = NULL;
/* First one wins */
if (m->partitions[PARTITION_XBOOTLDR].found)
if (!n)
return -ENOMEM;
+ options = mount_options_from_part(mount_options, nr);
+ if (options) {
+ o = strdup(options);
+ if (!o)
+ return -ENOMEM;
+ }
+
m->partitions[PARTITION_XBOOTLDR] = (DissectedPartition) {
.found = true,
.partno = nr,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(n),
.uuid = id,
+ .mount_options = TAKE_PTR(o),
};
break;
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
} else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
+ _cleanup_free_ char *o = NULL;
+ const char *options = NULL;
/* If the root has was set, then we won't fallback to a generic node, because the root hash
* decides */
if (multiple_generic)
return -ENOTUNIQ;
+ options = mount_options_from_part(mount_options, generic_nr);
+ if (options) {
+ o = strdup(options);
+ if (!o)
+ return -ENOMEM;
+ }
+
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = generic_rw,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(generic_node),
.uuid = generic_uuid,
+ .mount_options = TAKE_PTR(o),
};
}
}
free(m->partitions[i].node);
free(m->partitions[i].decrypted_fstype);
free(m->partitions[i].decrypted_node);
+ free(m->partitions[i].mount_options);
}
free(m->hostname);
return -ENOMEM;
}
+ if (!isempty(m->mount_options))
+ if (!strextend_with_separator(&options, ",", m->mount_options, NULL))
+ return -ENOMEM;
+
r = mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
if (r < 0)
return r;
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
+ const MountOptions *mount_options,
DissectImageFlags flags,
DissectedImage **ret) {
name = buffer;
}
- r = dissect_image(fd, root_hash, root_hash_size, verity_data, flags, ret);
+ r = dissect_image(fd, root_hash, root_hash_size, verity_data, mount_options, flags, ret);
switch (r) {
return k >= 0 && image->partitions[k].found;
}
+MountOptions* mount_options_free_all(MountOptions *options) {
+ MountOptions *m;
+
+ while ((m = options)) {
+ LIST_REMOVE(mount_options, options, m);
+ free(m->options);
+ free(m);
+ }
+
+ return NULL;
+}
+
+const char* mount_options_from_part(const MountOptions *options, unsigned int partition_number) {
+ MountOptions *m;
+
+ LIST_FOREACH(mount_options, m, (MountOptions *)options)
+ if (partition_number == m->partition_number && !isempty(m->options))
+ return m->options;
+
+ return NULL;
+}
+
+int mount_image_privately_interactively(
+ const char *image,
+ DissectImageFlags flags,
+ char **ret_directory,
+ LoopDevice **ret_loop_device,
+ DecryptedImage **ret_decrypted_image) {
+
+ _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+ _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
+ _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
+ _cleanup_(rmdir_and_freep) char *created_dir = NULL;
+ _cleanup_free_ char *temp = NULL;
+ int r;
+
+ /* Mounts an OS image at a temporary place, inside a newly created mount namespace of our own. This
+ * is used by tools such as systemd-tmpfiles or systemd-firstboot to operate on some disk image
+ * easily. */
+
+ assert(image);
+ assert(ret_directory);
+ assert(ret_loop_device);
+ assert(ret_decrypted_image);
+
+ 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_READ_ONLY) ? O_RDONLY : O_RDWR,
+ FLAGS_SET(flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN,
+ &d);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up loopback device: %m");
+
+ r = dissect_image_and_warn(d->fd, image, NULL, 0, NULL, NULL, flags, &dissected_image);
+ if (r < 0)
+ return r;
+
+ r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, flags, &decrypted_image);
+ if (r < 0)
+ return r;
+
+ r = detach_mount_namespace();
+ if (r < 0)
+ return log_error_errno(r, "Failed to detach mount namespace: %m");
+
+ r = mkdir_p(temp, 0700);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create mount point: %m");
+
+ created_dir = TAKE_PTR(temp);
+
+ r = dissected_image_mount(dissected_image, created_dir, UID_INVALID, flags);
+ if (r == -EUCLEAN)
+ return log_error_errno(r, "File system check on image failed: %m");
+ if (r < 0)
+ return log_error_errno(r, "Failed to mount image: %m");
+
+ if (decrypted_image) {
+ r = decrypted_image_relinquish(decrypted_image);
+ if (r < 0)
+ return log_error_errno(r, "Failed to relinquish DM devices: %m");
+ }
+
+ loop_device_relinquish(d);
+
+ *ret_directory = TAKE_PTR(created_dir);
+ *ret_loop_device = TAKE_PTR(d);
+ *ret_decrypted_image = TAKE_PTR(decrypted_image);
+
+ return 0;
+}
+
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",