]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: add 'fsverity' flag for CopyFiles= lines 35401/head
authorAllison Karlitskaya <allison.karlitskaya@redhat.com>
Mon, 2 Dec 2024 09:50:02 +0000 (10:50 +0100)
committerAllison Karlitskaya <allison.karlitskaya@redhat.com>
Tue, 27 May 2025 07:26:02 +0000 (09:26 +0200)
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>
man/repart.d.xml
src/repart/repart.c

index fde83b09786ca443bcf6fff5b2ad461467f2de50..71c520d643f97eff217cc69edd57b5b4e71cce96 100644 (file)
       <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>
index f72876ddad20754949faebab887ae88b1120a09f..f3cc69ef1132c0289d374b643047717f12eadcd7 100644 (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",