Merge pull request #19391 from poettering/dissect-grow

optionally, grow file systems to partition size when mounting them via GPT auto-discovery
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-05-07 15:04:55 +02:00 committed by GitHub
commit ac2c088939
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 302 additions and 93 deletions

9
TODO
View file

@ -50,12 +50,6 @@ Features:
* systemd-sysext: optionally, run it in initrd already, before transitioning
into host, to open up possibility for services shipped like that.
* add a flag to the GPT spec that says "grow my fs to partition size", and make
it settable via systemd-repart. Add in growfs jobs in
systemd-gpt-auto-generator when it is set, and issue the ioctls while
mounting in systemd-npsawn --image=. That way systemd-repart suffices to
enlarge an image.
* add a new switch --auto-definitions=yes/no or so to systemd-repart. If
specified, synthesize a definition automatically if we can: enlarge last
partition on disk, but only if it is marked for growing and not read-only.
@ -355,9 +349,6 @@ Features:
* busctl: maybe expose a verb "ping" for pinging a dbus service to see if it
exists and responds.
* systemd-gpt-auto should probably set x-systemd.growfs on the mounts it
creates
* bootctl:
- teach it to prepare an ESP wholesale, i.e. with mkfs.vfat invocation
- teach it to copy in unified kernel images and maybe type #1 boot loader spec entries from host

View file

@ -94,24 +94,48 @@ localized.
## Partition Flags
For the root, `/usr/`, server data, home, variable data, temporary data and swap
partitions, the partition flag bit 63 ("*no-auto*") may be used to turn off
auto-discovery for the specific partition. If set, the partition will not be
automatically mounted or enabled.
This specification defines three GPT partition flags that may be set for the
partition types defined above:
For the root, `/usr/`, server data, home, variable data and temporary data
partitions, the partition flag bit 60 ("*read-only*") may be used to mark a
partition for read-only mounts only. If set, the partition will be mounted
read-only instead of read-write. Note that the variable data partition and the
temporary data partition will generally not be able to serve their purpose if
marked read-only, since by their very definition they are supposed to be
mutable. (The home and server data partitions are generally assumed to be
mutable as well, but the requirement for them is not equally strong.) Because
of that, while the read-only flag is defined and supported, it's almost never a
good idea to actually use it for these partitions.
1. For the root, `/usr/`, Verity, home, server data, variable data, temporary data,
swap and extended boot loader partitions, the partition flag bit 63
("*no-auto*") may be used to turn off auto-discovery for the specific
partition. If set, the partition will not be automatically mounted or
enabled.
Note that these two flag definitions happen to map nicely to the ones used by
Microsoft Basic Data Partitions.
2. For the root, `/usr/`, Verity, home, server data, variable data, temporary
data and extended boot loader partitions, the partition flag bit 60
("*read-only*") may be used to mark a partition for read-only mounts only.
If set, the partition will be mounted read-only instead of read-write. Note
that the variable data partition and the temporary data partition will
generally not be able to serve their purpose if marked read-only, since by
their very definition they are supposed to be mutable. (The home and server
data partitions are generally assumed to be mutable as well, but the
requirement for them is not equally strong.) Because of that, while the
read-only flag is defined and supported, it's almost never a good idea to
actually use it for these partitions. Also note that Verity partitions are
by their semantics always read-only. The flag is hence of little effect for
them, and it is recommended to set it unconditionally for the Verity
partition types.
3. For the root, `/usr/`, home, server data, variable data, temporary data and
extended boot loader partitions, the partition flag bit 59
("*grow-file-system*") may be used to mark a partition for automatic growing
of the contained file system to the size of the partition when
mounted. Tools that automatically mount disk image with a GPT partition
table are suggested to implicitly grow the contained file system to the
partition size they are contained in. This flag is without effect on
partitions marked read-only.
Note that the first two flag definitions happen to map nicely to the ones used
by Microsoft Basic Data Partitions.
All three of these flags generally affect only auto-discovery and automatic
mounting of disk images. If partitions marked with these flags are mounted
using low-level commands like
[mount(8)](https://man7.org/linux/man-pages/man2/mount.8.html) or directly with
[mount(2)](https://man7.org/linux/man-pages/man2/mount.2.html), they typically
have no effect.
## Suggested Mode of Operation

View file

@ -55,11 +55,13 @@
partition slot greater than the highest slot number currently in use. Any existing partitions that have
no matching partition file are left as they are.</para>
<para>Note that these definitions may only be used to created and initialize new partitions or grow
<para>Note that these definitions may only be used to create and initialize new partitions or to grow
existing ones. In the latter case it will not grow the contained files systems however; separate
mechanisms, such as
<citerefentry><refentrytitle>systemd-growfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> may be
used to grow the file systems inside of these partitions.</para>
used to grow the file systems inside of these partitions. Partitions may also be marked for automatic
growing via the <varname>GrowFileSystem=</varname> setting, in which case the file system is grown on
first mount by tools that respect this flag. See below for details.</para>
</refsect1>
<refsect1>
@ -580,13 +582,39 @@
<varlistentry>
<term><varname>ReadOnly=</varname></term>
<term><varname>GrowFileSystem=</varname></term>
<listitem><para>Configures the Read-Only partition flags (bit 60) of the partition table entry. This
option is a friendly way to set bit 60 of the partition flags value without setting any of the other
bits, and may be set via <varname>Flags=</varname> too, see above.</para>
<listitem><para>Configures the Read-Only and Grow-File-System partition flags (bit 60 and 59) of the
partition table entry, as defined by the <ulink
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>. Only
available for partition types supported by the specification. This option is a friendly way to set bit
60 and 59 of the partition flags value without setting any of the other bits, and may be set via
<varname>Flags=</varname> too, see above.</para>
<para>If both <varname>Flags=</varname> and <varname>ReadOnly=</varname> are set the latter controls
the value of the flag.</para></listitem>
<para>If <varname>Flags=</varname> is used in conjunction with one or both of
<varname>ReadOnly=</varname>/<varname>GrowFileSystem=</varname> the latter control the value of the
relevant flags, i.e. the high-level settings
<varname>ReadOnly=</varname>/<varname>GrowFileSystem=</varname> override the low-level setting
<varname>Flags=</varname>.</para>
<para>Note that the two flags affect only automatic partition mounting, as implemented by
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
or the <option>--image=</option> option of various commands (such as
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>). It
has no effect on explicit mounts, such as those done via <citerefentry
project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
<citerefentry
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></para>
<para>If both bit 50 and 59 are set for a partition (i.e. the partition is marked both read-only and
marked for file system growing) the latter is typically without effect: the read-only flag takes
precedence in most tools reading these flags, and since growing the file system involves writing to
the partition it is consequently ignored.</para>
<para><varname>ReadOnly=</varname> defaults to on for Verity partition
types. <varname>GrowFileSystem=</varname> defaults to on for all partition types that support it,
except if the partition is marked read-only (and thus effectively, defaults to off for Verity
partitions).</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View file

@ -194,6 +194,28 @@
<option>--fsck=no</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--growfs=no</option></term>
<listitem><para>Turn off automatic growing of accessed file systems to their partition size, if
marked for that in the GPT partition table. By default when an image is accessed for writing (by
<option>--mount</option> or <option>--copy-to</option>) the file systems contained in the OS image
are automatically grown to their partition sizes, if bit 59 in the GPT partition flags is set for
partition types that are defined by the <ulink
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>. This
behavior may be switched off using <option>--growfs=no</option>. File systems are grown automatically
on access if all of the following conditions are met:</para>
<orderedlist>
<listitem><para>The file system is mounted writable</para></listitem>
<listitem><para>The file system currently is smaller than the partition it is contained in (and thus can be grown)</para></listitem>
<listitem><para>The image contains a GPT partition table</para></listitem>
<listitem><para>The file system is stored on a partition defined by the Discoverable Partitions Specification</para></listitem>
<listitem><para>Bit 59 of the GPT partition flags for this partition is set, as per specification</para></listitem>
<listitem><para>The <option>--growfs=no</option> option is not passed.</para></listitem>
</orderedlist>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--mkdir</option></term>

View file

@ -1818,7 +1818,8 @@ int setup_namespace(
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_USR_NO_ROOT;
DISSECT_IMAGE_USR_NO_ROOT |
DISSECT_IMAGE_GROWFS;
size_t n_mounts;
int r;

View file

@ -49,7 +49,8 @@ static DissectImageFlags arg_flags =
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_USR_NO_ROOT;
DISSECT_IMAGE_USR_NO_ROOT |
DISSECT_IMAGE_GROWFS;
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
@ -75,6 +76,7 @@ static int help(void) {
" --no-legend Do not show the headers and footers\n"
" -r --read-only Mount read-only\n"
" --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"
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
" --root-hash=HASH Specify root hash for verity\n"
@ -112,6 +114,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_LEGEND,
ARG_DISCARD,
ARG_FSCK,
ARG_GROWFS,
ARG_ROOT_HASH,
ARG_ROOT_HASH_SIG,
ARG_VERITY_DATA,
@ -128,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "read-only", no_argument, NULL, 'r' },
{ "discard", required_argument, NULL, ARG_DISCARD },
{ "fsck", required_argument, NULL, ARG_FSCK },
{ "growfs", required_argument, NULL, ARG_GROWFS },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
@ -264,6 +268,14 @@ static int parse_argv(int argc, char *argv[]) {
SET_FLAG(arg_flags, DISSECT_IMAGE_FSCK, r);
break;
case ARG_GROWFS:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --growfs= parameter: %s", optarg);
SET_FLAG(arg_flags, DISSECT_IMAGE_GROWFS, r);
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
@ -467,7 +479,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
return log_oom();
}
t = table_new("rw", "designator", "partition uuid", "partition label", "fstype", "architecture", "verity", "node", "partno");
t = table_new("rw", "designator", "partition uuid", "partition label", "fstype", "architecture", "verity", "growfs", "node", "partno");
if (!t)
return log_oom();
@ -511,6 +523,10 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
if (r < 0)
return table_log_add_error(r);
r = table_add_many(t, TABLE_BOOLEAN, (int) p->growfs);
if (r < 0)
return table_log_add_error(r);
if (p->partno < 0) /* no partition table, naked file system */ {
r = table_add_cell(t, NULL, TABLE_STRING, arg_image);
if (r < 0)

View file

@ -1357,7 +1357,8 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
&unlink_dir,
&loop_device,
&decrypted_image);

View file

@ -194,6 +194,7 @@ static int add_mount(
const char *where,
const char *fstype,
bool rw,
bool growfs,
const char *options,
const char *description,
const char *post) {
@ -271,8 +272,18 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", p);
if (post)
return generator_add_symlink(arg_dest, post, "requires", unit);
if (growfs) {
r = generator_hook_up_growfs(arg_dest, where, post);
if (r < 0)
return r;
}
if (post) {
r = generator_add_symlink(arg_dest, post, "requires", unit);
if (r < 0)
return r;
}
return 0;
}
@ -321,6 +332,7 @@ static int add_partition_mount(
where,
p->fstype,
p->rw,
p->growfs,
NULL,
description,
SPECIAL_LOCAL_FS_TARGET);
@ -385,6 +397,7 @@ static int add_automount(
const char *where,
const char *fstype,
bool rw,
bool growfs,
const char *options,
const char *description,
usec_t timeout) {
@ -406,6 +419,7 @@ static int add_automount(
where,
fstype,
rw,
growfs,
opt,
description,
NULL);
@ -481,7 +495,8 @@ static int add_xbootldr(DissectedPartition *p) {
p->node,
"/boot",
p->fstype,
true,
/* rw= */ true,
/* growfs= */ false,
esp_or_xbootldr_options(p),
"Boot Loader Partition",
120 * USEC_PER_SEC);
@ -555,7 +570,8 @@ static int add_esp(DissectedPartition *p, bool has_xbootldr) {
p->node,
esp_path,
p->fstype,
true,
/* rw= */ true,
/* growfs= */ false,
esp_or_xbootldr_options(p),
"EFI System Partition Automount",
120 * USEC_PER_SEC);
@ -651,7 +667,8 @@ static int add_root_mount(void) {
"/dev/gpt-auto-root",
in_initrd() ? "/sysroot" : "/",
NULL,
arg_root_rw > 0,
/* rw= */ arg_root_rw > 0,
/* growfs= */ false,
NULL,
"Root Partition",
in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);

View file

@ -2154,7 +2154,7 @@ int main(int argc, char *argv[]) {
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK : DISSECT_IMAGE_READ_ONLY),
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS : DISSECT_IMAGE_READ_ONLY),
&unlink_dir,
&loop_device,
&decrypted_image);

View file

@ -146,7 +146,8 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
&unlink_dir,
&loop_device,
&decrypted_image);

View file

@ -3577,7 +3577,7 @@ static int outer_child(
DISSECT_IMAGE_MOUNT_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK)|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS)|
(arg_start_mode == START_BOOT ? DISSECT_IMAGE_VALIDATE_OS : 0));
if (r < 0)
return r;
@ -3670,7 +3670,7 @@ static int outer_child(
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK));
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS));
if (r == -EUCLEAN)
return log_error_errno(r, "File system check for image failed: %m");
if (r < 0)

View file

@ -170,6 +170,7 @@ struct Partition {
uint64_t gpt_flags;
int read_only;
int growfs;
LIST_FIELDS(Partition, partitions);
};
@ -243,6 +244,7 @@ static Partition *partition_new(void) {
.copy_blocks_fd = -1,
.copy_blocks_size = UINT64_MAX,
.read_only = -1,
.growfs = -1,
};
return p;
@ -1316,6 +1318,7 @@ static int partition_read_definition(Partition *p, const char *path) {
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
{}
};
int r;
@ -1363,6 +1366,11 @@ static int partition_read_definition(Partition *p, const char *path) {
p->read_only < 0)
p->read_only = true;
/* Default to "growfs" on, unless read-only */
if (gpt_partition_type_knows_growfs(p->type_uuid) &&
p->read_only <= 0)
p->growfs = true;
return 0;
}
@ -3255,6 +3263,38 @@ static int set_gpt_flags(struct fdisk_partition *q, uint64_t flags) {
return fdisk_partition_set_attrs(q, a);
}
static uint64_t partition_merge_flags(Partition *p) {
uint64_t f;
assert(p);
f = p->gpt_flags;
if (p->read_only >= 0) {
if (gpt_partition_type_knows_read_only(p->type_uuid))
SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only);
else {
char buffer[ID128_UUID_STRING_MAX];
log_warning("Configured ReadOnly=%s for partition type '%s' that doesn't support it, ignoring.",
yes_no(p->read_only),
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
}
}
if (p->growfs >= 0) {
if (gpt_partition_type_knows_growfs(p->type_uuid))
SET_FLAG(f, GPT_FLAG_GROWFS, p->growfs);
else {
char buffer[ID128_UUID_STRING_MAX];
log_warning("Configured GrowFileSystem=%s for partition type '%s' that doesn't support it, ignoring.",
yes_no(p->growfs),
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
}
}
return f;
}
static int context_mangle_partitions(Context *context) {
Partition *p;
int r;
@ -3323,7 +3363,6 @@ static int context_mangle_partitions(Context *context) {
_cleanup_(fdisk_unref_partitionp) struct fdisk_partition *q = NULL;
_cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
char ids[ID128_UUID_STRING_MAX];
uint64_t f;
assert(!p->new_partition);
assert(p->offset % 512 == 0);
@ -3371,19 +3410,8 @@ static int context_mangle_partitions(Context *context) {
if (r < 0)
return log_error_errno(r, "Failed to set partition label: %m");
/* Merge the read only setting with the literal flags */
f = p->gpt_flags;
if (p->read_only >= 0) {
if (gpt_partition_type_knows_read_only(p->type_uuid))
SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only);
else {
char buffer[ID128_UUID_STRING_MAX];
log_warning("Configured ReadOnly=yes for partition type '%s' that doesn't support it, ignoring.",
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
}
}
r = set_gpt_flags(q, f);
/* Merge the read only + growfs setting with the literal flags, and set them for the partition */
r = set_gpt_flags(q, partition_merge_flags(p));
if (r < 0)
return log_error_errno(r, "Failed to set GPT partition flags: %m");

View file

@ -65,9 +65,9 @@ device: $D/zzz
unit: sectors
first-lba: 2048
last-lba: 2097118
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first", attrs="GUID:59"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64", attrs="GUID:59"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2", attrs="GUID:59"
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
EOF
@ -100,9 +100,9 @@ device: $D/zzz
unit: sectors
first-lba: 2048
last-lba: 2097118
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first", attrs="GUID:59"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64", attrs="GUID:59"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2", attrs="GUID:59"
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
$D/zzz5 : start= 1908696, size= 188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name="custom_label"
EOF
@ -120,9 +120,9 @@ device: $D/zzz
unit: sectors
first-lba: 2048
last-lba: 4194270
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first", attrs="GUID:59"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64", attrs="GUID:59"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2", attrs="GUID:59"
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
$D/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name="custom_label"
EOF
@ -150,9 +150,9 @@ device: $D/zzz
unit: sectors
first-lba: 2048
last-lba: 6291422
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first", attrs="GUID:59"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64", attrs="GUID:59"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2", attrs="GUID:59"
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
$D/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name="custom_label"
$D/zzz6 : start= 4194264, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=2A1D97E1-D0A3-46CC-A26E-ADC643926617, name="block-copy"
@ -187,9 +187,9 @@ device: $D/zzz
unit: sectors
first-lba: 2048
last-lba: 6389726
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first", attrs="GUID:59"
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64", attrs="GUID:59"
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2", attrs="GUID:59"
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
$D/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name="custom_label"
$D/zzz6 : start= 4194264, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=2A1D97E1-D0A3-46CC-A26E-ADC643926617, name="block-copy"

View file

@ -46,6 +46,7 @@
#include "path-util.h"
#include "process-util.h"
#include "raw-clone.h"
#include "resize-fs.h"
#include "signal-util.h"
#include "stat-util.h"
#include "stdio-util.h"
@ -534,7 +535,8 @@ int dissect_image(
sd_id128_t usr_uuid = SD_ID128_NULL, usr_verity_uuid = SD_ID128_NULL;
#endif
bool is_gpt, is_mbr, multiple_generic = false,
generic_rw = false; /* initialize to appease gcc */
generic_rw = false, /* initialize to appease gcc */
generic_growfs = false;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
_cleanup_(blkid_free_probep) blkid_probe b = NULL;
@ -795,7 +797,7 @@ int dissect_image(
int architecture = _ARCHITECTURE_INVALID;
const char *stype, *sid, *fstype = NULL, *label;
sd_id128_t type_id, id;
bool rw = true;
bool rw = true, growfs = false;
sid = blkid_partition_get_uuid(pp);
if (!sid)
@ -813,23 +815,25 @@ int dissect_image(
if (sd_id128_equal(type_id, GPT_HOME)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
designator = PARTITION_HOME;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_SRV)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
designator = PARTITION_SRV;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_ESP)) {
@ -846,18 +850,19 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
designator = PARTITION_XBOOTLDR;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
}
#ifdef GPT_ROOT_NATIVE
else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -869,6 +874,7 @@ int dissect_image(
designator = PARTITION_ROOT;
architecture = native_architecture();
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
@ -892,7 +898,7 @@ int dissect_image(
#ifdef GPT_ROOT_SECONDARY
else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -904,6 +910,7 @@ int dissect_image(
designator = PARTITION_ROOT_SECONDARY;
architecture = SECONDARY_ARCHITECTURE;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
@ -927,7 +934,7 @@ int dissect_image(
#ifdef GPT_USR_NATIVE
else if (sd_id128_equal(type_id, GPT_USR_NATIVE)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -939,6 +946,7 @@ int dissect_image(
designator = PARTITION_USR;
architecture = native_architecture();
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_USR_NATIVE_VERITY)) {
@ -962,7 +970,7 @@ int dissect_image(
#ifdef GPT_USR_SECONDARY
else if (sd_id128_equal(type_id, GPT_USR_SECONDARY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -974,6 +982,7 @@ int dissect_image(
designator = PARTITION_USR_SECONDARY;
architecture = SECONDARY_ARCHITECTURE;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_USR_SECONDARY_VERITY)) {
@ -1006,7 +1015,7 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -1016,6 +1025,7 @@ int dissect_image(
else {
generic_nr = nr;
generic_rw = !(pflags & GPT_FLAG_READ_ONLY);
generic_growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
generic_uuid = id;
generic_node = strdup(node);
if (!generic_node)
@ -1024,17 +1034,18 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_TMP)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
designator = PARTITION_TMP;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
} else if (sd_id128_equal(type_id, GPT_VAR)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY|GPT_FLAG_GROWFS);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
@ -1062,6 +1073,7 @@ int dissect_image(
designator = PARTITION_VAR;
rw = !(pflags & GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, GPT_FLAG_GROWFS);
}
if (designator != _PARTITION_DESIGNATOR_INVALID) {
@ -1108,6 +1120,7 @@ int dissect_image(
.found = true,
.partno = nr,
.rw = rw,
.growfs = growfs,
.architecture = architecture,
.node = TAKE_PTR(n),
.fstype = TAKE_PTR(t),
@ -1131,6 +1144,7 @@ int dissect_image(
else {
generic_nr = nr;
generic_rw = true;
generic_growfs = false;
generic_node = strdup(node);
if (!generic_node)
return -ENOMEM;
@ -1166,6 +1180,7 @@ int dissect_image(
.found = true,
.partno = nr,
.rw = true,
.growfs = false,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(n),
.uuid = id,
@ -1254,6 +1269,7 @@ int dissect_image(
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = generic_rw,
.growfs = generic_growfs,
.partno = generic_nr,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(generic_node),
@ -1316,6 +1332,9 @@ int dissect_image(
if (p->fstype && fstype_is_ro(p->fstype))
p->rw = false;
if (!p->rw)
p->growfs = false;
}
*ret = TAKE_PTR(m);
@ -1411,6 +1430,43 @@ static int run_fsck(const char *node, const char *fstype) {
return 0;
}
static int fs_grow(const char *node_path, const char *mount_path) {
_cleanup_close_ int mount_fd = -1, node_fd = -1;
char fb[FORMAT_BYTES_MAX];
uint64_t size, newsize;
int r;
node_fd = open(node_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (node_fd < 0)
return log_debug_errno(errno, "Failed to open node device %s: %m", node_path);
if (ioctl(node_fd, BLKGETSIZE64, &size) != 0)
return log_debug_errno(errno, "Failed to get block device size of %s: %m", node_path);
mount_fd = open(mount_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (mount_fd < 0)
return log_debug_errno(errno, "Failed to open mountd file system %s: %m", mount_path);
log_debug("Resizing \"%s\" to %"PRIu64" bytes...", mount_path, size);
r = resize_fs(mount_fd, size, &newsize);
if (r < 0)
return log_debug_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m", mount_path, size);
if (newsize == size)
log_debug("Successfully resized \"%s\" to %s bytes.",
mount_path,
format_bytes(fb, sizeof fb, newsize));
else {
assert(newsize < size);
log_debug("Successfully resized \"%s\" to %s bytes (%"PRIu64" bytes lost due to blocksize).",
mount_path,
format_bytes(fb, sizeof fb, newsize),
size - newsize);
}
return 0;
}
static int mount_partition(
DissectedPartition *m,
const char *where,
@ -1519,6 +1575,9 @@ static int mount_partition(
if (r < 0)
return r;
if (rw && m->growfs && FLAGS_SET(flags, DISSECT_IMAGE_GROWFS))
(void) fs_grow(node, p);
return 1;
}

View file

@ -18,6 +18,7 @@ typedef struct VeritySettings VeritySettings;
struct DissectedPartition {
bool found:1;
bool rw:1;
bool growfs:1;
int partno; /* -1 if there was no partition and the images contains a file system directly */
int architecture; /* Intended architecture: either native, secondary or unset (-1). */
sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
@ -110,6 +111,7 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_MOUNT_READ_ONLY = 1 << 17, /* Make mounts read-only */
DISSECT_IMAGE_READ_ONLY = DISSECT_IMAGE_DEVICE_READ_ONLY |
DISSECT_IMAGE_MOUNT_READ_ONLY,
DISSECT_IMAGE_GROWFS = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
} DissectImageFlags;
struct DissectedImage {

View file

@ -503,6 +503,9 @@ int generator_hook_up_growfs(
const char *unit_file;
int r;
assert(dir);
assert(where);
escaped = cescape(where);
if (!escaped)
return log_oom();
@ -534,9 +537,10 @@ int generator_hook_up_growfs(
"BindsTo=%%i.mount\n"
"Conflicts=shutdown.target\n"
"After=%%i.mount\n"
"Before=shutdown.target %s\n",
"Before=shutdown.target%s%s\n",
program_invocation_short_name,
target);
target ? " " : "",
strempty(target));
if (empty_or_root(where)) /* Make sure the root fs is actually writable before we resize it */
fprintf(f,

View file

@ -163,3 +163,14 @@ bool gpt_partition_type_knows_read_only(sd_id128_t id) {
gpt_partition_type_is_root_verity(id) || /* pretty much implied, but let's set the bit to make things really clear */
gpt_partition_type_is_usr_verity(id); /* ditto */
}
bool gpt_partition_type_knows_growfs(sd_id128_t id) {
return gpt_partition_type_is_root(id) ||
gpt_partition_type_is_usr(id) ||
sd_id128_in_set(id,
GPT_HOME,
GPT_SRV,
GPT_VAR,
GPT_TMP,
GPT_XBOOTLDR);
}

View file

@ -112,7 +112,8 @@
* auto-discovery. These happen to be identical to what Microsoft defines for its own Basic Data Partitions,
* but that's just because we saw no point in defining any other values here. */
#define GPT_FLAG_READ_ONLY (1ULL << 60)
#define GPT_FLAG_NO_AUTO (1ULL << 63)
#define GPT_FLAG_NO_AUTO (1ULL << 63)
#define GPT_FLAG_GROWFS (1ULL << 59)
const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
const char *gpt_partition_type_uuid_to_string_harder(
@ -135,3 +136,4 @@ bool gpt_partition_type_is_usr(sd_id128_t id);
bool gpt_partition_type_is_usr_verity(sd_id128_t id);
bool gpt_partition_type_knows_read_only(sd_id128_t id);
bool gpt_partition_type_knows_growfs(sd_id128_t id);

View file

@ -1997,7 +1997,8 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
&unlink_dir,
&loop_device,
&decrypted_image);

View file

@ -3446,7 +3446,8 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
&unlink_dir,
&loop_device,
&decrypted_image);

View file

@ -130,8 +130,8 @@ losetup -d "${loop}"
ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)"
VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)"
systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$architecture"'","verity":"yes","node":'
systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$architecture"'","verity":null,"node":'
systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$architecture"'","verity":"yes",'
systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$architecture"'","verity":null,'
systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F "MARKER=1"
systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F -f <(sed 's/"//g' "$os_release")