]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: wire up XAT_FDROOT
authorLennart Poettering <lennart@poettering.net>
Mon, 8 Dec 2025 12:32:09 +0000 (13:32 +0100)
committerLennart Poettering <lennart@poettering.net>
Sat, 17 Jan 2026 11:37:39 +0000 (12:37 +0100)
src/basic/chase.c
src/test/test-chase.c

index 0199f5dd69db3efe99df5fd666e9a9ef178d4d04..969f88afd298444f10cef8b6ec2cf48a1373b085 100644 (file)
@@ -135,7 +135,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR));
         assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
         assert(!FLAGS_SET(flags, CHASE_NO_AUTOFS|CHASE_TRIGGER_AUTOFS));
-        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
 
         if (FLAGS_SET(flags, CHASE_STEP))
                 assert(!ret_fd);
@@ -218,7 +218,15 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
          *    the mount point is emitted. CHASE_WARN cannot be used in PID 1.
          */
 
-        if (FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) {
+        _cleanup_close_ int _dir_fd = -EBADF;
+        if (dir_fd == XAT_FDROOT) {
+                _dir_fd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+                if (_dir_fd < 0)
+                        return -errno;
+
+                dir_fd = _dir_fd;
+                flags &= ~CHASE_AT_RESOLVE_IN_ROOT;
+        } else if (FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) {
                 /* If we get AT_FDCWD or dir_fd points to "/", then we always resolve symlinks relative to
                  * the host's root. Hence, CHASE_AT_RESOLVE_IN_ROOT is meaningless. */
 
@@ -656,9 +664,13 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path,
                                       "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
                                       absolute, root);
 
-        fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
-        if (fd < 0)
-                return -errno;
+        if (empty_or_root(root))
+                fd = XAT_FDROOT;
+        else {
+                fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
+                if (fd < 0)
+                        return -errno;
+        }
 
         r = chaseat(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL);
         if (r < 0)
index 89705b4ffdeafeb284e9630f6931aa9829693ef9..2dc554ebd18cf4fb8bd4f8a2e514efa7db4d46f3 100644 (file)
@@ -499,6 +499,17 @@ TEST(chaseat) {
 
         fd = safe_close(fd);
 
+        /* Same but with XAT_FDROOT */
+        ASSERT_OK(chaseat(XAT_FDROOT, p, 0, &result, NULL));
+        ASSERT_STREQ(result, "/usr");
+        result = mfree(result);
+
+        ASSERT_OK(chaseat(XAT_FDROOT, p, CHASE_AT_RESOLVE_IN_ROOT, &result, NULL));
+        ASSERT_STREQ(result, "/usr");
+        result = mfree(result);
+
+        fd = safe_close(fd);
+
         /* If the file descriptor does not point to the root directory, the result will be relative
          * unless the result is outside of the specified file descriptor. */