repart: add 'fsverity' flag for CopyFiles= lines

We currently pass the CopyFlags that we use to populate the temporary
directory in the form of a constant at each of the copy_tree_at() call
sites.  De-duplicate that and move it into the `CopyFilesLine` struct,
initializing it from the parser.

Add our first non-constant flag: `fsverity=`.  This can be set to `off`
(the default) or `copy`, in which case we copy the fs-verity state from
the source files.

This arrangement is amenable to the introduction of more flags to
`CopyFiles=` lines, if we want to add them in the future.

Update the `repart.d(5)` manpage.

Closes #35352

Signed-off-by: Allison Karlitskaya <allison.karlitskaya@redhat.com>
This commit is contained in:
Allison Karlitskaya
2024-12-02 10:50:02 +01:00
parent 80f00d67ad
commit eef63efcc3
2 changed files with 74 additions and 15 deletions

View File

@@ -426,18 +426,40 @@
<varlistentry>
<term><varname>CopyFiles=</varname></term>
<listitem><para>Takes a pair of colon separated absolute file system paths. The first path refers to
a source file or directory on the host, the second path refers to a target in the file system of the
newly created partition and formatted file system. This setting may be used to copy files or
directories from the host into the file system that is created due to the <varname>Format=</varname>
option. If <varname>CopyFiles=</varname> is used without <varname>Format=</varname> specified
explicitly, <literal>Format=</literal> with a suitable default is implied (currently
<literal>vfat</literal> for <literal>ESP</literal> and <literal>XBOOTLDR</literal> partitions, and
<literal>ext4</literal> otherwise, but this may change in the future). This option may be used
multiple times to copy multiple files or directories from host into the newly formatted file system.
The colon and second path may be omitted in which case the source path is also used as the target
path (relative to the root of the newly created file system). If the source path refers to a
directory it is copied recursively.</para>
<listitem><para>Takes a colon-separated triplet in the form
<literal><varname>source</varname>[:<varname>target</varname>[:<varname>options</varname>]]</literal>.
<varname>source</varname> is an absolute path which refers to a source file or directory on the host.
<varname>target</varname> is an absolute path in the file system of the newly created partition and
formatted file system. <varname>options</varname> is a comma-separated list of options where each
option is in the form <literal><varname>key</varname>[=<varname>value</varname>]</literal>.</para>
<para>This setting may be used to copy files or directories from the host into the file system that
is created due to the <varname>Format=</varname> option. If <varname>CopyFiles=</varname> is used
without <varname>Format=</varname> specified explicitly, <literal>Format=</literal> with a suitable
default is implied (currently <literal>vfat</literal> for <literal>ESP</literal> and
<literal>XBOOTLDR</literal> partitions, and <literal>ext4</literal> otherwise, but this may change in
the future). This option may be used multiple times to copy multiple files or directories from host
into the newly formatted file system.</para>
<para>The <varname>target</varname> path may be omitted in which case the <varname>source</varname>
path is also used as the target path (relative to the root of the newly created file system). If
the source path refers to a directory it is copied recursively.</para>
<para>The <varname>options</varname> may contain the following values:</para>
<variablelist>
<varlistentry>
<term><varname>fsverity=</varname></term>
<listitem><para>May be set to the value <literal>off</literal> (the default if the option is not
present) or <literal>copy</literal>. If set to <literal>off</literal> then no files copied into
the filesystem from this source will have fs-verity enabled. If set to <literal>copy</literal>
then the fs-verity information for each file will be copied from the corresponding source
file.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
<para>This option has no effect if the partition already exists: it cannot be used to copy additional
files into an existing partition, it may only be used to populate a file system created anew.</para>

View File

@@ -280,6 +280,7 @@ static PartitionEncryptedVolume* partition_encrypted_volume_free(PartitionEncryp
typedef struct CopyFiles {
char *source;
char *target;
CopyFlags flags;
} CopyFiles;
static void copy_files_free_many(CopyFiles *f, size_t n) {
@@ -1769,7 +1770,7 @@ static int config_parse_copy_files(
void *data,
void *userdata) {
_cleanup_free_ char *source = NULL, *buffer = NULL, *resolved_source = NULL, *resolved_target = NULL;
_cleanup_free_ char *source = NULL, *buffer = NULL, *resolved_source = NULL, *resolved_target = NULL, *options = NULL;
Partition *partition = ASSERT_PTR(data);
const char *p = rvalue, *target;
int r;
@@ -1792,9 +1793,38 @@ static int config_parse_copy_files(
else
target = buffer;
r = extract_first_word(&p, &options, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract options: %s", rvalue);
if (!isempty(p))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue);
CopyFlags flags = COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS;
for (const char *opts = options;;) {
_cleanup_free_ char *word = NULL;
const char *val;
r = extract_first_word(&opts, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CopyFile options: %s", options);
if (r == 0)
break;
if (isempty(word))
continue;
if ((val = startswith(word, "fsverity="))) {
if (streq(val, "copy"))
flags |= COPY_PRESERVE_FS_VERITY;
else if (streq(val, "off"))
flags &= ~COPY_PRESERVE_FS_VERITY;
else
log_syntax(unit, LOG_WARNING, filename, line, 0, "fsverity= expects either 'off' or 'copy'.");
} else
log_syntax(unit, LOG_WARNING, filename, line, 0, "Encountered unknown option '%s', ignoring.", word);
}
r = specifier_printf(source, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_source);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
@@ -1823,6 +1853,7 @@ static int config_parse_copy_files(
partition->copy_files[partition->n_copy_files++] = (CopyFiles) {
.source = TAKE_PTR(resolved_source),
.target = TAKE_PTR(resolved_target),
.flags = flags,
};
return 0;
@@ -2398,6 +2429,12 @@ static MakeFileSystemFlags partition_mkfs_flags(const Partition *p) {
if (streq(p->format, "erofs") && !DEBUG_LOGGING)
flags |= MKFS_QUIET;
FOREACH_ARRAY(cf, p->copy_files, p->n_copy_files)
if (cf->flags & COPY_PRESERVE_FS_VERITY) {
flags |= MKFS_FS_VERITY;
break;
}
return flags;
}
@@ -5783,14 +5820,14 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
sfd, ".",
pfd, fn,
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
line->flags,
denylist, subvolumes_by_source_inode);
} else
r = copy_tree_at(
sfd, ".",
tfd, ".",
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
line->flags,
denylist, subvolumes_by_source_inode);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",