Merge pull request #26695 from poettering/dissect-mount-helper

make "systemd-dissect --mount" available as /sbin/mount.ddi
This commit is contained in:
Luca Boccassi
2023-03-07 20:07:17 +00:00
committed by GitHub
5 changed files with 136 additions and 4 deletions
+1 -1
View File
@@ -902,7 +902,7 @@ manpages = [
['systemd-debug-generator', '8', [], ''],
['systemd-delta', '1', [], ''],
['systemd-detect-virt', '1', [], ''],
['systemd-dissect', '1', [], 'HAVE_BLKID'],
['systemd-dissect', '1', ['mount.ddi'], 'HAVE_BLKID'],
['systemd-environment-d-generator',
'8',
['30-systemd-environment-d-generator'],
+47 -2
View File
@@ -18,6 +18,7 @@
<refnamediv>
<refname>systemd-dissect</refname>
<refname>mount.ddi</refname>
<refpurpose>Dissect Discoverable Disk Images (DDIs)</refpurpose>
</refnamediv>
@@ -99,6 +100,14 @@
what it operates with when mounting the image. To display the complete list of partitions use a tool such
as <citerefentry
project='man-pages'><refentrytitle>fdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para>The <command>systemd-dissect</command> command may be invoked as <command>mount.ddi</command> in
which case it implements the <citerefentry
project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> "external
helper" interface. This ensures disk images compatible with <command>systemd-dissect</command> can be
mounted directly by <command>mount</command> and <citerefentry
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
details see below.</para>
</refsect1>
<refsect1>
@@ -132,7 +141,13 @@
<para>All mounted file systems are checked with the appropriate <citerefentry
project='man-pages'><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>
implementation in automatic fixing mode, unless explicitly turned off (<option>--fsck=no</option>) or
read-only operation is requested (<option>--read-only</option>).</para></listitem>
read-only operation is requested (<option>--read-only</option>).</para>
<para>Note that this functionality is also available in <citerefentry
project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> via a
command such as <command>mount -t ddi myimage.raw targetdir/</command>, as well as in <citerefentry
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
details, see below.</para></listitem>
</varlistentry>
<varlistentry>
@@ -359,6 +374,35 @@
command is used the exit status of the invoked command is propagated.</para>
</refsect1>
<refsect1>
<title>Invocation as <command>/sbin/mount.ddi</command></title>
<para>The <command>systemd-dissect</command> executable may be symlinked to
<filename>/sbin/mount.ddi</filename>. If invoked through that it implements <citerefentry
project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
"external helper" interface for the (pseudo) file system type <literal>ddi</literal>. This means
conformant disk images may be mounted directly via</para>
<programlisting># mount -t ddi myimage.raw targetdir/</programlisting>
<para>in a fashion mostly equivalent to:</para>
<programlisting># systemd-dissect --mount myimage.raw targetdir/</programlisting>
<para>Note that since a single DDI may contain multiple file systems it should later be unmounted with
<command>umount -R targetdir/</command>, for recursive operation.</para>
<para>This functionality is particularly useful to mount DDIs automatically at boot via simple
<filename>/etc/fstab</filename> entries. For example:</para>
<programlisting>/path/to/myimage.raw /images/myimage/ ddi defaults 0 0</programlisting>
<para>When invoked this way the mount options <literal>ro</literal>, <literal>rw</literal>,
<literal>discard</literal>, <literal>nodiscard</literal> map to the corresponding options listed above
(i.e. <option>--read-only</option>, <option>--discard=all</option>,
<option>--discard=disabled</option>). Mount options are <emphasis>not</emphasis> generically passed on to
the file systems inside the images.</para>
</refsect1>
<refsect1>
<title>Examples</title>
@@ -366,7 +410,7 @@
<example>
<title>Generate a tarball from an OS disk image</title>
<programlisting>$ systemd-dissect --with foo.raw tar cz . >foo.tar.gz</programlisting>
<programlisting># systemd-dissect --with foo.raw tar cz . >foo.tar.gz</programlisting>
</example>
</refsect1>
@@ -377,6 +421,7 @@
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<ulink url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">Discoverable Partitions Specification</ulink>,
<citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>fdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
+4
View File
@@ -2478,6 +2478,10 @@ if conf.get('HAVE_BLKID') == 1
dependencies : [versiondep],
install_rpath : rootpkglibdir,
install : true)
meson.add_install_script(meson_make_symlink,
bindir / 'systemd-dissect',
rootsbindir / 'mount.ddi')
endif
if conf.get('ENABLE_RESOLVE') == 1
+78 -1
View File
@@ -522,6 +522,80 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
static int parse_argv_as_mount_helper(int argc, char *argv[]) {
const char *options = NULL;
bool fake = false;
int c, r;
/* Implements util-linux "external helper" command line interface, as per mount(8) man page. */
while ((c = getopt(argc, argv, "sfnvN:o:t:")) >= 0) {
switch(c) {
case 'f':
fake = true;
break;
case 'o':
options = optarg;
break;
case 't':
if (!streq(optarg, "ddi"))
log_debug("Unexpected file system type '%s', ignoring.", optarg);
break;
case 's': /* sloppy mount options */
case 'n': /* aka --no-mtab */
case 'v': /* aka --verbose */
log_debug("Ignoring option -%c, not implemented.", c);
break;
case 'N': /* aka --namespace= */
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Option -%c is not implemented, refusing.", c);
case '?':
return -EINVAL;
}
}
if (optind + 2 != argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path and target directory as only argument.");
for (const char *p = options;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, ",", EXTRACT_KEEP_QUOTE);
if (r < 0)
return log_error_errno(r, "Failed to extract mount option: %m");
if (r == 0)
break;
if (streq(word, "ro"))
SET_FLAG(arg_flags, DISSECT_IMAGE_READ_ONLY, true);
else if (streq(word, "rw"))
SET_FLAG(arg_flags, DISSECT_IMAGE_READ_ONLY, false);
else if (streq(word, "discard"))
SET_FLAG(arg_flags, DISSECT_IMAGE_DISCARD_ANY, true);
else if (streq(word, "nodiscard"))
SET_FLAG(arg_flags, DISSECT_IMAGE_DISCARD_ANY, false);
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown mount option '%s'.", word);
}
if (fake)
return 0;
arg_image = argv[optind];
arg_path = argv[optind+1];
arg_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
arg_action = ACTION_MOUNT;
return 1;
}
static int strv_pair_to_json(char **l, JsonVariant **ret) {
_cleanup_strv_free_ char **jl = NULL;
@@ -1420,7 +1494,10 @@ static int run(int argc, char *argv[]) {
log_setup();
r = parse_argv(argc, argv);
if (invoked_as(argv, "mount.ddi"))
r = parse_argv_as_mount_helper(argc, argv);
else
r = parse_argv(argc, argv);
if (r <= 0)
return r;
+6
View File
@@ -424,6 +424,12 @@ grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/
grep -q -F '{"name":"c","type":"raw","class":"extension","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
# Check that the /sbin/mount.ddi helper works
T="/tmp/mounthelper.$RANDOM"
mount -t ddi "${image}.gpt" "$T" -o ro,X-mount.mkdir,discard
umount -R "$T"
rmdir "$T"
echo OK >/testok
exit 0