tmpfiles: Add merge support for copy files action

If '+' is specified with 'C', let's merge the tree with any existing
tree.
This commit is contained in:
Daan De Meyer 2023-05-09 13:45:16 +02:00
parent e57b7020d2
commit 1fd5ec5697
3 changed files with 26 additions and 10 deletions

View file

@ -58,6 +58,7 @@ c+ /dev/char-device-to-[re]create mode user group - major
b /dev/block-device-to-create mode user group - major:minor
b+ /dev/block-device-to-[re]create mode user group - major:minor
C /target/to/create - - - cleanup-age /source/to/copy
C+ /target/to/create - - - cleanup-age /source/to/copy
x /path-or-glob/to/ignore/recursively - - - cleanup-age -
X /path-or-glob/to/ignore - - - cleanup-age -
r /path-or-glob/to/remove - - - - -
@ -326,15 +327,14 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<varlistentry>
<term><varname>C</varname></term>
<listitem><para>Recursively copy a file or directory, if the
destination files or directories do not exist yet or the
destination directory is empty. Note that this command will not
descend into subdirectories if the destination directory already
exists and is not empty. Instead, the entire copy operation is
skipped. If the argument is omitted, files from the source directory
<filename>/usr/share/factory/</filename> with the same name
are copied. Does not follow symlinks. Contents of the directories
are subject to time-based cleanup if the age argument is specified.
<term><varname>C+</varname></term>
<listitem><para>Recursively copy a file or directory, if the destination files or directories do
not exist yet or the destination directory is empty. Note that this command will not descend into
subdirectories if the destination directory already exists and is not empty, unless the action is
suffixed with <varname>+</varname>. Instead, the entire copy operation is skipped. If the argument
is omitted, files from the source directory <filename>/usr/share/factory/</filename> with the same
name are copied. Does not follow symlinks. Contents of the directories are subject to time-based
cleanup if the age argument is specified.
</para></listitem>
</varlistentry>

View file

@ -1803,7 +1803,7 @@ static int copy_files(Item *i) {
dfd, bn,
i->uid_set ? i->uid : UID_INVALID,
i->gid_set ? i->gid : GID_INVALID,
COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS,
COPY_REFLINK | ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS,
NULL);
fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);

View file

@ -122,6 +122,22 @@ EOF
test "$(stat -c %U:%G:%a /tmp/C/3/f1)" = "root:root:644"
test ! -e /tmp/C/4
touch /tmp/C/3-origin/f{2,3,4}
echo -n ABC > /tmp/C/3/f1
systemd-tmpfiles --create - <<EOF
C+ /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin
EOF
# Test that the trees got merged, even though /tmp/C/3 already exists.
test -e /tmp/C/3/f1
test -e /tmp/C/3/f2
test -e /tmp/C/3/f3
test -e /tmp/C/3/f4
# Test that /tmp/C/3/f1 did not get overwritten.
test "$(cat /tmp/C/3/f1)" = "ABC"
# Check that %U expands to 0, both in the path and in the argument.
home='/tmp/C'
systemd-tmpfiles --create - <<EOF