summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2022-08-04 02:02:55 +0200
committerGitHub <noreply@github.com>2022-08-04 02:02:55 +0200
commit33b7d7b284928bec88015aa2c6ca60e9c9599382 (patch)
tree34bba2b9d8cd90d5b89d089aa810bfcbf360077e
parentintegritysetup: do not use crypt_init_data_device after crypt_init (diff)
parentdissect: Add systemd-dissect --umount (diff)
downloadsystemd-33b7d7b284928bec88015aa2c6ca60e9c9599382.tar.xz
systemd-33b7d7b284928bec88015aa2c6ca60e9c9599382.zip
Merge pull request #24141 from DaanDeMeyer/dissect-umount
dissect: Add systemd-dissect --umount
-rw-r--r--man/systemd-dissect.xml38
-rw-r--r--src/dissect/dissect.c115
-rw-r--r--src/shared/blockdev-util.c165
-rw-r--r--src/shared/blockdev-util.h7
-rw-r--r--src/shared/dissect-image.c63
-rw-r--r--src/shared/loop-util.c5
-rw-r--r--src/shared/loop-util.h1
-rw-r--r--src/udev/udevadm-lock.c44
-rwxr-xr-xtest/units/testsuite-50.sh10
9 files changed, 339 insertions, 109 deletions
diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml
index 4cdac2b013..6430501bdf 100644
--- a/man/systemd-dissect.xml
+++ b/man/systemd-dissect.xml
@@ -29,6 +29,9 @@
<command>systemd-dissect <arg choice="opt" rep="repeat">OPTIONS</arg> <option>--mount</option> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="plain"><replaceable>PATH</replaceable></arg></command>
</cmdsynopsis>
<cmdsynopsis>
+ <command>systemd-dissect <arg choice="opt" rep="repeat">OPTIONS</arg> <option>--umount</option> <arg choice="plain"><replaceable>PATH</replaceable></arg></command>
+ </cmdsynopsis>
+ <cmdsynopsis>
<command>systemd-dissect <arg choice="opt" rep="repeat">OPTIONS</arg> <option>--copy-from</option> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="plain"><replaceable>PATH</replaceable></arg> <arg choice="opt"><replaceable>TARGET</replaceable></arg></command>
</cmdsynopsis>
<cmdsynopsis>
@@ -40,7 +43,7 @@
<title>Description</title>
<para><command>systemd-dissect</command> is a tool for introspecting and interacting with file system OS
- disk images. It supports four different operations:</para>
+ disk images. It supports five different operations:</para>
<orderedlist>
<listitem><para>Show general OS image information, including the image's
@@ -51,6 +54,10 @@
mount the included partitions according to their designation onto a directory and possibly
sub-directories.</para></listitem>
+ <listitem><para>Unmount an OS image from a local directory. In this mode it will recursively unmount
+ the mounted partitions and remove the underlying loop device, including all the partition sub-devices.
+ </para></listitem>
+
<listitem><para>Copy files and directories in and out of an OS image.</para></listitem>
</orderedlist>
@@ -103,10 +110,7 @@
multiple nested mounts are established. This command expects two arguments: a path to an image file
and a path to a directory where to mount the image.</para>
- <para>To unmount an OS image mounted like this use <citerefentry
- project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
- <option>-R</option> switch (for recursive operation), so that the OS image and all nested partition
- mounts are unmounted.</para>
+ <para>To unmount an OS image mounted like this use the <option>--umount</option> operation.</para>
<para>When the OS image contains LUKS encrypted or Verity integrity protected file systems
appropriate volumes are automatically set up and marked for automatic disassembly when the image is
@@ -129,6 +133,23 @@
</varlistentry>
<varlistentry>
+ <term><option>--umount</option></term>
+ <term><option>-u</option></term>
+
+ <listitem><para>Unmount an OS image from the specified directory. This command expects one argument:
+ a directory where an OS image was mounted.</para>
+
+ <para>All mounted partitions will be recursively unmounted, and the underlying loop device will be
+ removed, along with all it's partition sub-devices.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-U</option></term>
+
+ <listitem><para>This is a shortcut for <option>--umount --rmdir</option>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--copy-from</option></term>
<term><option>-x</option></term>
@@ -225,6 +246,13 @@
</varlistentry>
<varlistentry>
+ <term><option>--rmdir</option></term>
+
+ <listitem><para>If combined with <option>--umount</option> the specified directory where the OS image
+ is mounted is removed after unmounting the OS image.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--discard=</option></term>
<listitem><para>Takes one of <literal>disabled</literal>, <literal>loop</literal>,
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 4e39f959cf..d9f3fab835 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -8,7 +8,10 @@
#include <sys/ioctl.h>
#include <sys/mount.h>
+#include "sd-device.h"
+
#include "architecture.h"
+#include "blockdev-util.h"
#include "chase-symlinks.h"
#include "copy.h"
#include "dissect-image.h"
@@ -24,6 +27,7 @@
#include "main-func.h"
#include "mkdir.h"
#include "mount-util.h"
+#include "mountpoint-util.h"
#include "namespace-util.h"
#include "parse-argument.h"
#include "parse-util.h"
@@ -40,6 +44,7 @@
static enum {
ACTION_DISSECT,
ACTION_MOUNT,
+ ACTION_UMOUNT,
ACTION_COPY_FROM,
ACTION_COPY_TO,
} arg_action = ACTION_DISSECT;
@@ -58,6 +63,7 @@ static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
+static bool arg_rmdir = false;
STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done);
@@ -81,6 +87,7 @@ static int help(void) {
" --fsck=BOOL Run fsck before mounting\n"
" --growfs=BOOL Grow file system to partition size, if marked\n"
" --mkdir Make mount directory before mounting, if missing\n"
+ " --rmdir Remove mount directory after unmounting\n"
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
" --root-hash=HASH Specify root hash for verity\n"
" --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
@@ -96,6 +103,8 @@ static int help(void) {
" --version Show package version\n"
" -m --mount Mount the image to the specified directory\n"
" -M Shortcut for --mount --mkdir\n"
+ " -u --umount Unmount the image from the specified directory\n"
+ " -U Shortcut for --umount --rmdir\n"
" -x --copy-from Copy files from image to host\n"
" -a --copy-to Copy files from host to image\n"
"\nSee the %2$s for details.\n",
@@ -122,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ROOT_HASH_SIG,
ARG_VERITY_DATA,
ARG_MKDIR,
+ ARG_RMDIR,
ARG_JSON,
};
@@ -131,6 +141,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "mount", no_argument, NULL, 'm' },
+ { "umount", no_argument, NULL, 'u' },
{ "read-only", no_argument, NULL, 'r' },
{ "discard", required_argument, NULL, ARG_DISCARD },
{ "fsck", required_argument, NULL, ARG_FSCK },
@@ -139,6 +150,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
{ "mkdir", no_argument, NULL, ARG_MKDIR },
+ { "rmdir", no_argument, NULL, ARG_RMDIR },
{ "copy-from", no_argument, NULL, 'x' },
{ "copy-to", no_argument, NULL, 'a' },
{ "json", required_argument, NULL, ARG_JSON },
@@ -150,7 +162,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hmrMxa", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "hmurMUxa", options, NULL)) >= 0) {
switch (c) {
@@ -182,6 +194,20 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags |= DISSECT_IMAGE_MKDIR;
break;
+ case 'u':
+ arg_action = ACTION_UMOUNT;
+ break;
+
+ case ARG_RMDIR:
+ arg_rmdir = true;
+ break;
+
+ case 'U':
+ /* Shortcut combination of the above two */
+ arg_action = ACTION_UMOUNT;
+ arg_rmdir = true;
+ break;
+
case 'x':
arg_action = ACTION_COPY_FROM;
arg_flags |= DISSECT_IMAGE_READ_ONLY;
@@ -316,6 +342,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
break;
+ case ACTION_UMOUNT:
+ if (optind + 1 != argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Expected a mount point path as only argument.");
+
+ arg_path = argv[optind];
+ break;
+
case ACTION_COPY_FROM:
if (argc < optind + 2 || argc > optind + 3)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -823,6 +857,82 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
return 0;
}
+static int action_umount(const char *path) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *canonical = NULL;
+ dev_t devno;
+ const char *devname;
+ _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+ int r, k;
+
+ fd = chase_symlinks_and_open(path, NULL, 0, O_DIRECTORY, &canonical);
+ if (fd == -ENOTDIR)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "'%s' is not a directory", path);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to resolve path '%s': %m", path);
+
+ r = fd_is_mount_point(fd, NULL, 0);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'%s' is not a mount point", canonical);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether '%s' is a mount point: %m", canonical);
+
+ r = fd_get_whole_disk(fd, /*backing=*/ true, &devno);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find backing block device for '%s': %m", canonical);
+
+ r = sd_device_new_from_devnum(&device, 'b', devno);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create sd-device object for block device %u:%u: %m",
+ major(devno), minor(devno));
+
+ r = sd_device_get_devname(device, &devname);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get devname of block device %u:%u: %m",
+ major(devno), minor(devno));
+
+ r = loop_device_open(devname, 0, &d);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open loop device '%s': %m", devname);
+
+ r = loop_device_flock(d, LOCK_EX);
+ if (r < 0)
+ return log_error_errno(r, "Failed to lock loop device '%s': %m", devname);
+
+ /* We've locked the loop device, now we're ready to unmount. To allow the unmount to succeed, we have
+ * to close the O_PATH fd we opened earlier. */
+ fd = safe_close(fd);
+
+ r = umount_recursive(canonical, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to unmount '%s': %m", canonical);
+
+ /* We managed to lock and unmount successfully? That means we can try to remove the loop device.*/
+ loop_device_unrelinquish(d);
+
+ if (arg_rmdir) {
+ k = RET_NERRNO(rmdir(canonical));
+ if (k < 0)
+ log_error_errno(k, "Failed to remove mount directory '%s': %m", canonical);
+ } else
+ k = 0;
+
+ /* Before loop_device_unrefp() kicks in, let's explicitly remove all the partition subdevices of the
+ * loop device. We do this to ensure that all traces of the loop device are gone by the time this
+ * command exits. */
+ r = block_device_remove_all_partitions(d->fd);
+ if (r == -EBUSY) {
+ log_error_errno(r, "One or more partitions of '%s' are busy, ignoring", devname);
+ r = 0;
+ }
+ if (r < 0)
+ log_error_errno(r, "Failed to remove one or more partitions of '%s': %m", devname);
+
+
+ return k < 0 ? k : r;
+}
+
static int run(int argc, char *argv[]) {
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
@@ -835,6 +945,9 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
+ if (arg_action == ACTION_UMOUNT)
+ return action_umount(arg_path);
+
r = verity_settings_load(
&arg_verity_settings,
arg_image, NULL, NULL);
diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c
index c3b90bb227..0d921cc045 100644
--- a/src/shared/blockdev-util.c
+++ b/src/shared/blockdev-util.c
@@ -1,13 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <linux/blkpg.h>
#include <sys/file.h>
+#include <sys/ioctl.h>
#include <unistd.h>
+#include "sd-device.h"
+
#include "alloc-util.h"
#include "blockdev-util.h"
#include "btrfs-util.h"
+#include "device-util.h"
#include "devnum-util.h"
#include "dirent-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "missing_magic.h"
@@ -377,3 +383,162 @@ int path_is_encrypted(const char *path) {
return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
}
+
+int fd_get_whole_disk(int fd, bool backing, dev_t *ret) {
+ dev_t devt;
+ struct stat st;
+ int r;
+
+ assert(ret);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (S_ISBLK(st.st_mode))
+ devt = st.st_rdev;
+ else if (!backing)
+ return -ENOTBLK;
+ else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
+ return -ENOTBLK;
+ else if (major(st.st_dev) != 0)
+ devt = st.st_dev;
+ else {
+ _cleanup_close_ int regfd = -1;
+
+ /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
+ * handing, to get the backing device node. */
+
+ regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ if (regfd < 0)
+ return regfd;
+
+ r = btrfs_get_block_device_fd(regfd, &devt);
+ if (r == -ENOTTY)
+ return -ENOTBLK;
+ if (r < 0)
+ return r;
+ }
+
+ return block_get_whole_disk(devt, ret);
+}
+
+int path_get_whole_disk(const char *path, bool backing, dev_t *ret) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_CLOEXEC|O_PATH);
+ if (fd < 0)
+ return -errno;
+
+ return fd_get_whole_disk(fd, backing, ret);
+}
+
+int block_device_add_partition(int fd, const char *name, int nr, uint64_t start, uint64_t size) {
+ assert(fd >= 0);
+ assert(name);
+ assert(nr > 0);
+
+ struct blkpg_partition bp = {
+ .pno = nr,
+ .start = start,
+ .length = size,
+ };
+
+ struct blkpg_ioctl_arg ba = {
+ .op = BLKPG_ADD_PARTITION,
+ .data = &bp,
+ .datalen = sizeof(bp),
+ };
+
+ if (strlen(name) >= sizeof(bp.devname))
+ return -EINVAL;
+
+ strcpy(bp.devname, name);
+
+ return RET_NERRNO(ioctl(fd, BLKPG, &ba));
+}
+
+int block_device_remove_partition(int fd, const char *name, int nr) {
+ assert(fd >= 0);
+ assert(name);
+ assert(nr > 0);
+
+ struct blkpg_partition bp = {
+ .pno = nr,
+ };
+
+ struct blkpg_ioctl_arg ba = {
+ .op = BLKPG_DEL_PARTITION,
+ .data = &bp,
+ .datalen = sizeof(bp),
+ };
+
+ if (strlen(name) >= sizeof(bp.devname))
+ return -EINVAL;
+
+ strcpy(bp.devname, name);
+
+ return RET_NERRNO(ioctl(fd, BLKPG, &ba));
+}
+
+int block_device_remove_all_partitions(int fd) {
+ struct stat stat;
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *part;
+ int r, k = 0;
+
+ if (fstat(fd, &stat) < 0)
+ return -errno;
+
+ r = sd_device_new_from_devnum(&dev, 'b', stat.st_rdev);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_parent(e, dev);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_subsystem(e, "block", true);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition");
+ if (r < 0)
+ return r;
+
+ FOREACH_DEVICE(e, part) {
+ const char *v, *devname;
+ int nr;
+
+ r = sd_device_get_devname(part, &devname);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_property_value(part, "PARTN", &v);
+ if (r < 0)
+ return r;
+
+ r = safe_atoi(v, &nr);
+ if (r < 0)
+ return r;
+
+ r = block_device_remove_partition(fd, devname, nr);
+ if (r == -ENODEV) {
+ log_debug("Kernel removed partition %s before us, ignoring", devname);
+ continue;
+ }
+ if (r < 0) {
+ log_debug_errno(r, "Failed to remove partition %s: %m", devname);
+ k = k ?: r;
+ continue;
+ }
+
+ log_debug("Removed partition %s", devname);
+ }
+
+ return k;
+}
diff --git a/src/shared/blockdev-util.h b/src/shared/blockdev-util.h
index 05501f2657..8c9401b4a7 100644
--- a/src/shared/blockdev-util.h
+++ b/src/shared/blockdev-util.h
@@ -27,3 +27,10 @@ int blockdev_partscan_enabled(int fd);
int fd_is_encrypted(int fd);
int path_is_encrypted(const char *path);
+
+int fd_get_whole_disk(int fd, bool backing, dev_t *ret);
+int path_get_whole_disk(const char *path, bool backing, dev_t *ret);
+
+int block_device_add_partition(int fd, const char *name, int nr, uint64_t start, uint64_t size);
+int block_device_remove_partition(int fd, const char *name, int nr);
+int block_device_remove_all_partitions(int fd);
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index c7a336d432..87712abfb3 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -4,7 +4,6 @@
#include <valgrind/memcheck.h>
#endif
-#include <linux/blkpg.h>
#include <linux/dm-ioctl.h>
#include <linux/loop.h>
#include <sys/file.h>
@@ -149,29 +148,6 @@ static void check_partition_flags(
log_debug("Unexpected partition flag %llu set on %s!", bit, node);
}
}
-
-static int ioctl_partition_remove(int fd, const char *name, int nr) {
- assert(fd >= 0);
- assert(name);
- assert(nr > 0);
-
- struct blkpg_partition bp = {
- .pno = nr,
- };
-
- struct blkpg_ioctl_arg ba = {
- .op = BLKPG_DEL_PARTITION,
- .data = &bp,
- .datalen = sizeof(bp),
- };
-
- if (strlen(name) >= sizeof(bp.devname))
- return -EINVAL;
-
- strcpy(bp.devname, name);
-
- return RET_NERRNO(ioctl(fd, BLKPG, &ba));
-}
#endif
static void dissected_partition_done(int fd, DissectedPartition *p) {
@@ -182,7 +158,7 @@ static void dissected_partition_done(int fd, DissectedPartition *p) {
if (p->node && p->partno > 0 && !p->relinquished) {
int r;
- r = ioctl_partition_remove(fd, p->node, p->partno);
+ r = block_device_remove_partition(fd, p->node, p->partno);
if (r < 0)
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
}
@@ -202,37 +178,6 @@ static void dissected_partition_done(int fd, DissectedPartition *p) {
}
#if HAVE_BLKID
-static int ioctl_partition_add(
- int fd,
- const char *name,
- int nr,
- uint64_t start,
- uint64_t size) {
-
- assert(fd >= 0);
- assert(name);
- assert(nr > 0);
-
- struct blkpg_partition bp = {
- .pno = nr,
- .start = start,
- .length = size,
- };
-
- struct blkpg_ioctl_arg ba = {
- .op = BLKPG_ADD_PARTITION,
- .data = &bp,
- .datalen = sizeof(bp),
- };
-
- if (strlen(name) >= sizeof(bp.devname))
- return -EINVAL;
-
- strcpy(bp.devname, name);
-
- return RET_NERRNO(ioctl(fd, BLKPG, &ba));
-}
-
static int make_partition_devname(
const char *whole_devname,
int nr,
@@ -548,7 +493,7 @@ int dissect_image(
* Kernel returns EBUSY if there's already a partition by that number or an overlapping
* partition already existent. */
- r = ioctl_partition_add(fd, node, nr, (uint64_t) start * 512, (uint64_t) size * 512);
+ r = block_device_add_partition(fd, node, nr, (uint64_t) start * 512, (uint64_t) size * 512);
if (r < 0) {
if (r != -EBUSY)
return log_debug_errno(r, "BLKPG_ADD_PARTITION failed: %m");
@@ -831,7 +776,7 @@ int dissect_image(
if (!PARTITION_DESIGNATOR_VERSIONED(designator) ||
strverscmp_improved(m->partitions[designator].label, label) >= 0) {
- r = ioctl_partition_remove(fd, node, nr);
+ r = block_device_remove_partition(fd, node, nr);
if (r < 0)
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
continue;
@@ -908,7 +853,7 @@ int dissect_image(
/* First one wins */
if (m->partitions[PARTITION_XBOOTLDR].found) {
- r = ioctl_partition_remove(fd, node, nr);
+ r = block_device_remove_partition(fd, node, nr);
if (r < 0)
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
continue;
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index 530688fc97..a5ad914577 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -768,6 +768,11 @@ void loop_device_relinquish(LoopDevice *d) {
d->relinquished = true;
}
+void loop_device_unrelinquish(LoopDevice *d) {
+ assert(d);
+ d->relinquished = false;
+}
+
int loop_device_open(const char *loop_path, int open_flags, LoopDevice **ret) {
_cleanup_close_ int loop_fd = -1;
_cleanup_free_ char *p = NULL;
diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h
index 964ce3ed08..a33d7e3e59 100644
--- a/src/shared/loop-util.h
+++ b/src/shared/loop-util.h
@@ -27,6 +27,7 @@ LoopDevice* loop_device_unref(LoopDevice *d);
DEFINE_TRIVIAL_CLEANUP_FUNC(LoopDevice*, loop_device_unref);
void loop_device_relinquish(LoopDevice *d);
+void loop_device_unrelinquish(LoopDevice *d);
int loop_device_refresh_size(LoopDevice *d, uint64_t offset, uint64_t size);
diff --git a/src/udev/udevadm-lock.c b/src/udev/udevadm-lock.c
index 60d6507aaf..a1e04f6516 100644
--- a/src/udev/udevadm-lock.c
+++ b/src/udev/udevadm-lock.c
@@ -144,9 +144,7 @@ static int find_devno(
const char *device,
bool backing) {
- _cleanup_close_ int fd = -1;
- dev_t devt, whole_devt;
- struct stat st;
+ dev_t devt;
int r;
assert(devnos);
@@ -154,51 +152,19 @@ static int find_devno(
assert(*devnos || *n_devnos == 0);
assert(device);
- fd = open(device, O_CLOEXEC|O_PATH);
- if (fd < 0)
- return log_error_errno(errno, "Failed to open '%s': %m", device);
-
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Failed to stat '%s': %m", device);
-
- if (S_ISBLK(st.st_mode))
- devt = st.st_rdev;
- else if (!backing)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Not a block device: %s", device);
- else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
- return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Not a block device, regular file or directory: %s", device);
- else if (major(st.st_dev) != 0)
- devt = st.st_dev;
- else {
- _cleanup_close_ int regfd = -1;
-
- /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
- * handing, to get the backing device node. */
-
- regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
- if (regfd < 0)
- return log_error_errno(regfd, "Failed to open '%s': %m", device);
-
- r = btrfs_get_block_device_fd(regfd, &devt);
- if (r == -ENOTTY)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Path '%s' not backed by block device.", device);
- if (r < 0)
- return log_error_errno(r, "Failed to acquire btrfs backing device of '%s': %m", device);
- }
-
- r = block_get_whole_disk(devt, &whole_devt);
+ r = path_get_whole_disk(device, backing, &devt);
if (r < 0)
return log_error_errno(r, "Failed to find whole block device for '%s': %m", device);
- if (typesafe_bsearch(&whole_devt, *devnos, *n_devnos, devt_compare_func)) {
- log_debug("Device %u:%u already listed for locking, ignoring.", major(whole_devt), minor(whole_devt));
+ if (typesafe_bsearch(&devt, *devnos, *n_devnos, devt_compare_func)) {
+ log_debug("Device %u:%u already listed for locking, ignoring.", major(devt), minor(devt));
return 0;
}
if (!GREEDY_REALLOC(*devnos, *n_devnos + 1))
return log_oom();
- (*devnos)[(*n_devnos)++] = whole_devt;
+ (*devnos)[(*n_devnos)++] = devt;
/* Immediately sort again, to ensure the binary search above will work for the next device we add */
typesafe_qsort(*devnos, *n_devnos, devt_compare_func);
diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh
index 2f1844ccf7..31cb52064e 100755
--- a/test/units/testsuite-50.sh
+++ b/test/units/testsuite-50.sh
@@ -58,8 +58,8 @@ if [ "${verity_count}" -lt 1 ]; then
echo "Verity device ${image}.raw not found in /dev/mapper/"
exit 1
fi
-umount "${image_dir}/mount"
-umount "${image_dir}/mount2"
+systemd-dissect --umount "${image_dir}/mount"
+systemd-dissect --umount "${image_dir}/mount2"
systemd-run -P -p RootImage="${image}.raw" cat /usr/lib/os-release | grep -q -F "MARKER=1"
mv "${image}.verity" "${image}.fooverity"
@@ -207,7 +207,7 @@ systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" "${image_dir}/m
grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release"
grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release"
grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release"
-umount "${image_dir}/mount"
+systemd-dissect --umount "${image_dir}/mount"
# add explicit -p MountAPIVFS=yes once to test the parser
systemd-run -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
@@ -350,8 +350,8 @@ RemainAfterExit=yes
EOF
systemctl start testservice-50f.service
systemctl is-active testservice-50f.service
-umount "${image_dir}/app0"
-umount "${image_dir}/app1"
+systemd-dissect --umount "${image_dir}/app0"
+systemd-dissect --umount "${image_dir}/app1"
echo OK >/testok