You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
systemd/SOURCES/0786-tmpfiles-Add-merge-sup...

97 lines
4.8 KiB

From 129f8896018377cfe9a64e2877517124b79ca87f Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 9 May 2023 13:45:16 +0200
Subject: [PATCH] tmpfiles: Add merge support for copy files action
If '+' is specified with 'C', let's merge the tree with any existing
tree.
(cherry picked from commit 1fd5ec5697680e2ec6277431bd74cabf48dbc94f)
Related: RHEL-27512
---
man/tmpfiles.d.xml | 22 +++++++++++-----------
src/tmpfiles/tmpfiles.c | 2 +-
test/units/testsuite-22.02.sh | 16 ++++++++++++++++
3 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index bd3bc33ab4..fe2a1dadab 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -58,10 +58,11 @@ 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 /empty/dir/to/remove - - - - -
-R /dir/to/remove/recursively - - - - -
+r /path-or-glob/to/remove - - - - -
+R /path-or-glob/to/remove/recursively - - - - -
z /path-or-glob/to/adjust/mode mode user group - -
Z /path-or-glob/to/adjust/mode/recursively mode user group - -
t /path-or-glob/to/set/xattrs - - - - xattrs
@@ -325,15 +326,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>
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 18bb75715b..ead5c49874 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1648,7 +1648,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);
fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
if (fd < 0) {
diff --git a/test/units/testsuite-22.02.sh b/test/units/testsuite-22.02.sh
index 49c55f136b..f233be2499 100755
--- a/test/units/testsuite-22.02.sh
+++ b/test/units/testsuite-22.02.sh
@@ -121,3 +121,19 @@ 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"