]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfiles: do not follow copy source symlinks
authordongshengyuan <545258830@qq.com>
Wed, 15 Jul 2026 05:29:55 +0000 (13:29 +0800)
committerdongshengyuan <545258830@qq.com>
Thu, 23 Jul 2026 11:33:08 +0000 (19:33 +0800)
C lines copy symlinks as symlinks. The post-copy type check should
inspect the source symlink itself, not follow its target.

Reproducer:
  src=/tmp/tmpfiles-src-link.$$
  dst=/tmp/tmpfiles-dst-link.$$
  conf=/tmp/tmpfiles-conf.$$
  ln -s missing-target "$src"
  printf 'C %s - - - - %s\n' "$dst" "$src" >"$conf"
  systemd-tmpfiles --create "$conf"

Before:
  Failed to stat($src): No such file or directory
  status=73
  $dst -> missing-target already existed

Follow-up for 8f6fb95cd069884f4ce0a24eb20efc821ae3bc5e.

src/tmpfiles/tmpfiles.c
test/units/TEST-22-TMPFILES.03.sh

index 5c520ac0682a7f2ed647c14e797701d9e1cf0667..72781a49b72130686dcae9fee8eda76ac60ed708 100644 (file)
@@ -2249,8 +2249,8 @@ static int copy_files(Context *c, Item *i) {
         if (fstat(fd, &st) < 0)
                 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
 
-        if (stat(i->argument, &a) < 0)
-                return log_error_errno(errno, "Failed to stat(%s): %m", i->argument);
+        if (lstat(i->argument, &a) < 0)
+                return log_error_errno(errno, "Failed to lstat(%s): %m", i->argument);
 
         if (((st.st_mode ^ a.st_mode) & S_IFMT) != 0) {
                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
index c36f8f879052f22106cb65c1e8fd20ec152d9e68..390932ec974ef198118e9a67cdff8b946cecc092 100755 (executable)
@@ -209,6 +209,15 @@ test ! -e /tmp/C-copy-failure-dst/file
 chmod 755 /tmp/C-copy-failure-dst
 rm -rf /tmp/C-copy-failure-src /tmp/C-copy-failure-dst
 
+rm -f /tmp/C-copy-link-src /tmp/C-copy-link-dst
+ln -s missing-target /tmp/C-copy-link-src
+systemd-tmpfiles --create - <<EOF
+C     /tmp/C-copy-link-dst    - - - - /tmp/C-copy-link-src
+EOF
+test -L /tmp/C-copy-link-dst
+test "$(readlink /tmp/C-copy-link-dst)" = "missing-target"
+rm -f /tmp/C-copy-link-src /tmp/C-copy-link-dst
+
 #
 # 'w'
 #