summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-03-06 12:00:45 +0100
committerLennart Poettering <lennart@poettering.net>2023-03-09 16:41:23 +0100
commit236d1fa210839eafe03250214f708667c20ddb7f (patch)
treef506d069128cad5f75d7ef8ba97861e97fc3c06d
parentdissect: add commands for attaching/detaching loopback devices (diff)
downloadsystemd-236d1fa210839eafe03250214f708667c20ddb7f.tar.xz
systemd-236d1fa210839eafe03250214f708667c20ddb7f.zip
dissect: allow setting "lo_file_name" field of loopback block devices
When attaching a loopback file this allows us to set an explicit name for it. This is useful since it allows a caller to pre-select a string that is directly attached to the loopback file. Via udev rules we'l later make the device accessible through this name. Note that "lo_file_name" is supposed to carry a file name of the backing file, but the kernel actually does not care or enforce any of that, it just stores the filename and returns it later. This makes it so useful, as userspace has total control of that field. "lo_file_name" should not be confused with the sysattr "loop/backing_file" which is actually maintained by the kernel itself, and always shows the file to the backing inode without userspace having direct control over the returned string. Because the sysattr is generated by the kernel it is subject to file system namespacing and everything, while "lo_file_name" is not, it's really just a string passed through the kernel.
-rw-r--r--man/systemd-dissect.xml19
-rw-r--r--src/dissect/dissect.c25
2 files changed, 44 insertions, 0 deletions
diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml
index 1d0532713d..06c57a22ec 100644
--- a/man/systemd-dissect.xml
+++ b/man/systemd-dissect.xml
@@ -386,6 +386,25 @@
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--loop-ref=</option></term>
+
+ <listitem><para>Configures the "reference" string the kernel shall report as backing file for the
+ loopback block device. While this is supposed to be a path or filename referencing the backing file,
+ this is not enforced and the kernel accepts arbitrary free-form strings, chosen by the user. Accepts
+ arbitrary strings up to a length of 63 characters. This sets the kernel's
+ <literal>.lo_file_name</literal> field for the block device. Note this is distinct from the
+ <filename>/sys/class/block/loopX/loop/backing_file</filename> attribute file that always reports a
+ path referring to the actual backing file. The latter is subject to mount namespace translation, the
+ former is not.</para>
+
+ <para>This setting is particularly useful in combination with the <option>--attach</option> command,
+ as it allows later referencing the allocated loop device via <filename>/dev/loop/by-ref/…</filename>
+ symlinks. Example: first, set up the loopback device via <command>systemd-dissect attach
+ --loop-ref=quux foo.raw</command>, and then reference it in a command via the specified filename:
+ <command>cfdisk /dev/loop/by-ref/quux</command>.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="no-legend" />
<xi:include href="standard-options.xml" xpointer="json" />
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 6f7b44f0aa..a688e6f32c 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -81,9 +81,11 @@ static bool arg_legend = true;
static bool arg_rmdir = false;
static bool arg_in_memory = false;
static char **arg_argv = NULL;
+static char *arg_loop_ref = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done);
STATIC_DESTRUCTOR_REGISTER(arg_argv, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_loop_ref, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
@@ -123,6 +125,7 @@ static int help(void) {
" not embedded in IMAGE\n"
" --json=pretty|short|off\n"
" Generate JSON output\n"
+ " --loop-ref=NAME Set reference string for loopback device\n"
"\n%3$sCommands:%4$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
@@ -214,6 +217,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DISCOVER,
ARG_ATTACH,
ARG_DETACH,
+ ARG_LOOP_REF,
};
static const struct option options[] = {
@@ -242,6 +246,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "copy-to", no_argument, NULL, 'a' },
{ "json", required_argument, NULL, ARG_JSON },
{ "discover", no_argument, NULL, ARG_DISCOVER },
+ { "loop-ref", required_argument, NULL, ARG_LOOP_REF },
{}
};
@@ -435,6 +440,20 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_DISCOVER;
break;
+ case ARG_LOOP_REF:
+ if (isempty(optarg)) {
+ arg_loop_ref = mfree(arg_loop_ref);
+ break;
+ }
+
+ if (strlen(optarg) >= sizeof_field(struct loop_info64, lo_file_name))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Loop device ref string '%s' is too long.", optarg);
+
+ r = free_and_strdup_warn(&arg_loop_ref, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;
@@ -1671,6 +1690,12 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device for %s: %m", arg_image);
+ if (arg_loop_ref) {
+ r = loop_device_set_filename(d, arg_loop_ref);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set loop reference string to '%s', ignoring: %m", arg_loop_ref);
+ }
+
r = dissect_loop_device_and_warn(
d,
&arg_verity_settings,