* [pseudo] [PATCH v3 1/6] ports/linux/guts: Add open_tree wrapper
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
@ 2026-09-07 11:18 ` frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 2/6] test: Add open_tree test frezidok1
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
OPEN_TREE_CLONE is not handled since it requires CAP_SYS_ADMIN and is outside the common pseudo use case.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
ports/linux/guts/open_tree.c | 46 ++++++++++++++++++++++++++++++++++++
ports/linux/portdefs.h | 9 +++++++
ports/linux/wrapfuncs.in | 1 +
3 files changed, 56 insertions(+)
create mode 100644 ports/linux/guts/open_tree.c
diff --git a/ports/linux/guts/open_tree.c b/ports/linux/guts/open_tree.c
new file mode 100644
index 0000000..6c2aad9
--- /dev/null
+++ b/ports/linux/guts/open_tree.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2026 Yocto Project
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int open_tree(int dirfd, const char *path, unsigned int flags)
+ * int rc = -1;
+ */
+
+ struct stat64 buf;
+ int save_errno;
+ char *pseudo_path;
+
+ if (real_open_tree) {
+ pseudo_debug(PDBGF_SYSCALL, "open_tree, calling open_tree.\n");
+ rc = real_open_tree(dirfd, path, flags);
+ } else {
+ pseudo_debug(PDBGF_SYSCALL, "open_tree, calling syscall.\n");
+ rc = real_syscall(SYS_open_tree, dirfd, path, flags);
+ }
+
+ pseudo_path = pseudo_root_path(__func__, __LINE__, dirfd, path, 0);
+
+ if (rc != -1) {
+ save_errno = errno;
+ int stat_rc;
+
+ stat_rc = real___fxstatat64(_STAT_VER, dirfd, pseudo_path, &buf, (flags & AT_SYMLINK_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+
+ pseudo_debug(PDBGF_FILE, "open_tree(path %s), flags %o, stat rc %d, stat mode %o\n",
+ pseudo_path, flags, stat_rc, buf.st_mode);
+
+ if (stat_rc != -1) {
+ pseudo_client_op(OP_OPEN, 0, rc, dirfd, pseudo_path, &buf);
+ } else {
+ pseudo_debug(PDBGF_FILE, "open_tree(fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n",
+ rc, dirfd, pseudo_path, flags, strerror(errno));
+ pseudo_client_op(OP_OPEN, 0, rc, dirfd, pseudo_path, 0);
+ }
+ errno = save_errno;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h
index 1f1a41a..565fed9 100644
--- a/ports/linux/portdefs.h
+++ b/ports/linux/portdefs.h
@@ -82,3 +82,12 @@ extern int unshare(int flags);
#define SYS_openat2 __NR_openat2
#endif
+
+#ifndef SYS_open_tree
+
+#ifndef __NR_open_tree
+#define __NR_open_tree 428
+#endif
+
+#define SYS_open_tree __NR_open_tree
+#endif
diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in
index 3cea20a..a51e9a0 100644
--- a/ports/linux/wrapfuncs.in
+++ b/ports/linux/wrapfuncs.in
@@ -10,6 +10,7 @@ int lchown(const char *path, uid_t owner, gid_t group); /* flags=AT_SYMLINK_NOFO
int __fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags);
int openat(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=((flags&O_NOFOLLOW)||((flags&(O_CREAT|O_EXCL))==(O_CREAT|O_EXCL))), noignore_path=1 */
int __openat_2(int dirfd, const char *path, int flags); /* flags=((flags&O_NOFOLLOW)||((flags&(O_CREAT|O_EXCL))==(O_CREAT|O_EXCL))), noignore_path=1 */
+int open_tree(int dirfd, const char *path, unsigned int flags); /* noignore_path=1 */
int mknod(const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknod */
int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknodat */
int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */
^ permalink raw reply related [flat|nested] 7+ messages in thread* [pseudo] [PATCH v3 2/6] test: Add open_tree test
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 1/6] ports/linux/guts: Add open_tree wrapper frezidok1
@ 2026-09-07 11:18 ` frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 3/6] ports/linux/pseudo_wrappers.c: Add syscall support for open_tree() wrapper frezidok1
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
Covers basic open_tree wrapper functionality and the AT_EMPTY_PATH case.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
test/test-open_tree.c | 139 +++++++++++++++++++++++++++++++++++++++++
test/test-open_tree.sh | 5 ++
2 files changed, 144 insertions(+)
create mode 100644 test/test-open_tree.c
create mode 100755 test/test-open_tree.sh
diff --git a/test/test-open_tree.c b/test/test-open_tree.c
new file mode 100644
index 0000000..0fc02f4
--- /dev/null
+++ b/test/test-open_tree.c
@@ -0,0 +1,139 @@
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#define TEST_DIR "test-open-tree-dir"
+#define TEST_FILE "test-open-tree-file"
+
+static int test_no_flags(void) {
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ treefd = open_tree(AT_FDCWD, TEST_DIR, 0);
+ if (treefd == -1) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_relative_dirfd(void) {
+ int basefd = -1;
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ basefd = open(".", O_PATH | O_DIRECTORY);
+ if (basefd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = open_tree(basefd, TEST_DIR, 0);
+ if (treefd < 0) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (basefd != -1) {
+ close(basefd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_at_empty_path(void) {
+ int treefd = -1;
+ int dirfd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ dirfd = open(TEST_DIR, O_PATH | O_DIRECTORY);
+ if (dirfd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = open_tree(dirfd, "", AT_EMPTY_PATH);
+ if (treefd == -1) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (dirfd != -1) {
+ close(dirfd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static void cleanup(void) {
+ if (unlink(TEST_DIR "/" TEST_FILE) == -1 && errno != ENOENT) {
+ perror("unlink");
+ }
+ if (rmdir(TEST_DIR) == -1 && errno != ENOENT) {
+ perror("rmdir");
+ }
+}
+
+int main(void) {
+ cleanup();
+
+ if (mkdir(TEST_DIR, 0777) == -1) {
+ perror("mkdir");
+ return 1;
+ }
+
+ int rc = test_no_flags() || test_at_empty_path() || test_relative_dirfd();
+
+ cleanup();
+
+ return rc;
+}
diff --git a/test/test-open_tree.sh b/test/test-open_tree.sh
new file mode 100755
index 0000000..1654a0b
--- /dev/null
+++ b/test/test-open_tree.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./test/test-open_tree
+
+PSEUDO_IGNORE_PATHS=/ ./test/test-open_tree
\ No newline at end of file
^ permalink raw reply related [flat|nested] 7+ messages in thread* [pseudo] [PATCH v3 3/6] ports/linux/pseudo_wrappers.c: Add syscall support for open_tree() wrapper
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 1/6] ports/linux/guts: Add open_tree wrapper frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 2/6] test: Add open_tree test frezidok1
@ 2026-09-07 11:18 ` frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 4/6] test: Add open_tree syscall test frezidok1
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
ports/linux/pseudo_wrappers.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c
index b920cb2..33cba2d 100644
--- a/ports/linux/pseudo_wrappers.c
+++ b/ports/linux/pseudo_wrappers.c
@@ -102,6 +102,20 @@ syscall(long number, ...) {
#error SYS_openat2 not defined
#endif
+#ifdef SYS_open_tree
+ if (number == SYS_open_tree) {
+ pseudo_debug(PDBGF_SYSCALL, "syscall, faking open_tree.\n");
+ va_start(ap, number);
+ int dirfd = va_arg(ap, int);
+ const char *path = va_arg(ap, const char*);
+ unsigned int flags = va_arg(ap, unsigned int);
+
+ return wrap_open_tree(dirfd, path, flags);
+ }
+#else
+#error SYS_open_tree not defined
+#endif
+
#ifdef SYS_renameat2
/* Call out wrapper, expanding the variable arguments first */
if (number == SYS_renameat2) {
^ permalink raw reply related [flat|nested] 7+ messages in thread* [pseudo] [PATCH v3 4/6] test: Add open_tree syscall test
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
` (2 preceding siblings ...)
2026-09-07 11:18 ` [pseudo] [PATCH v3 3/6] ports/linux/pseudo_wrappers.c: Add syscall support for open_tree() wrapper frezidok1
@ 2026-09-07 11:18 ` frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 5/6] test: Add open_tree_attr " frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 6/6] ports/linux/guts: Add open_tree_attr wrapper frezidok1
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
Covers basic wrapper functionality when using syscall(SYS_open_tree, ...), also tests AT_EMPTY_PATH flag and related paths using dirfd != AT_FDCWD.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
test/test-open_tree-syscall.c | 152 +++++++++++++++++++++++++++++++++
test/test-open_tree-syscall.sh | 5 ++
2 files changed, 157 insertions(+)
create mode 100644 test/test-open_tree-syscall.c
create mode 100755 test/test-open_tree-syscall.sh
diff --git a/test/test-open_tree-syscall.c b/test/test-open_tree-syscall.c
new file mode 100644
index 0000000..03f5618
--- /dev/null
+++ b/test/test-open_tree-syscall.c
@@ -0,0 +1,152 @@
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+
+#define TEST_DIR "test-open-tree-dir"
+#define TEST_FILE "test-open-tree-file"
+
+static int do_open_tree_syscall(int dirfd, const char *path,
+ unsigned int flags)
+{
+#ifdef SYS_open_tree
+ return syscall(SYS_open_tree, dirfd, path, flags);
+#elif defined(__NR_open_tree)
+ return syscall(__NR_open_tree, dirfd, path, flags);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int test_no_flags(void) {
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ treefd = do_open_tree_syscall(AT_FDCWD, TEST_DIR, 0);
+ if (treefd == -1) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_relative_dirfd(void) {
+ int basefd = -1;
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ basefd = open(".", O_PATH | O_DIRECTORY);
+ if (basefd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = do_open_tree_syscall(basefd, TEST_DIR, 0);
+ if (treefd < 0) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+ out:
+ if (basefd != -1) {
+ close(basefd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_at_empty_path(void) {
+ int treefd = -1;
+ int dirfd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ dirfd = open(TEST_DIR, O_PATH | O_DIRECTORY);
+ if (dirfd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = do_open_tree_syscall(dirfd, "", AT_EMPTY_PATH);
+ if (treefd == -1) {
+ perror("open_tree");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (dirfd != -1) {
+ close(dirfd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static void cleanup(void) {
+ if (unlink(TEST_DIR "/" TEST_FILE) == -1 && errno != ENOENT) {
+ perror("unlink");
+ }
+ if (rmdir(TEST_DIR) == -1 && errno != ENOENT) {
+ perror("rmdir");
+ }
+}
+
+int main(void) {
+ cleanup();
+
+ if (mkdir(TEST_DIR, 0777) == -1) {
+ perror("mkdir");
+ return 1;
+ }
+
+ int rc = test_no_flags() || test_at_empty_path() || test_relative_dirfd();
+
+ cleanup();
+
+ return rc;
+}
diff --git a/test/test-open_tree-syscall.sh b/test/test-open_tree-syscall.sh
new file mode 100755
index 0000000..3cb4d96
--- /dev/null
+++ b/test/test-open_tree-syscall.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./test/test-open_tree-syscall
+
+PSEUDO_IGNORE_PATHS=/ ./test/test-open_tree-syscall
\ No newline at end of file
^ permalink raw reply related [flat|nested] 7+ messages in thread* [pseudo] [PATCH v3 5/6] test: Add open_tree_attr syscall test
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
` (3 preceding siblings ...)
2026-09-07 11:18 ` [pseudo] [PATCH v3 4/6] test: Add open_tree syscall test frezidok1
@ 2026-09-07 11:18 ` frezidok1
2026-09-07 11:18 ` [pseudo] [PATCH v3 6/6] ports/linux/guts: Add open_tree_attr wrapper frezidok1
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
Covers basic wrapper functionality when using syscall(SYS_open_tree_attr, ...), also tests AT_EMPTY_PATH flag and related paths using dirfd != AT_FDCWD.
The test uses attr == NULL, because using mount_attr in this call starts mount-specific privilege checks which end up with EPERM.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
test/test-open_tree_attr-syscall.c | 165 ++++++++++++++++++++++++++++
test/test-open_tree_attr-syscall.sh | 5 +
2 files changed, 170 insertions(+)
create mode 100644 test/test-open_tree_attr-syscall.c
create mode 100755 test/test-open_tree_attr-syscall.sh
diff --git a/test/test-open_tree_attr-syscall.c b/test/test-open_tree_attr-syscall.c
new file mode 100644
index 0000000..4b656cb
--- /dev/null
+++ b/test/test-open_tree_attr-syscall.c
@@ -0,0 +1,165 @@
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/mount.h>
+#include <sys/stat.h>
+
+#ifndef SYS_open_tree_attr
+
+#ifndef __NR_open_tree_attr
+#define __NR_open_tree_attr 467
+#endif
+
+#define SYS_open_tree_attr __NR_open_tree_attr
+#endif
+
+#define TEST_DIR "test-open-tree-dir"
+#define TEST_FILE "test-open-tree-file"
+
+static int do_open_tree_attr_syscall(int dirfd, const char *path,
+ unsigned int flags)
+{
+ /* Using mount_attr in this call starts mount-specific privilege checks
+ * which end up with EPERM.
+ * The functionality when using attr == NULL is equivalent to open_tree() */
+#ifdef SYS_open_tree_attr
+ return syscall(SYS_open_tree_attr, dirfd, path, flags, NULL, 0);
+#elif defined(__NR_open_tree_attr)
+ return syscall(__NR_open_tree_attr, dirfd, path, flags, NULL, 0);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int test_no_flags(void) {
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ treefd = do_open_tree_attr_syscall(AT_FDCWD, TEST_DIR, 0);
+ if (treefd == -1) {
+ perror("open_tree_attr");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_relative_dirfd(void) {
+ int basefd = -1;
+ int treefd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ basefd = open(".", O_PATH | O_DIRECTORY);
+ if (basefd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = do_open_tree_attr_syscall(basefd, TEST_DIR, 0);
+ if (treefd < 0) {
+ perror("open_tree_attr");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+ out:
+ if (basefd != -1) {
+ close(basefd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static int test_at_empty_path(void) {
+ int treefd = -1;
+ int dirfd = -1;
+ int fd = -1;
+ int rc = 1;
+
+ dirfd = open(TEST_DIR, O_PATH | O_DIRECTORY);
+ if (dirfd < 0) {
+ perror("open");
+ goto out;
+ }
+
+ treefd = do_open_tree_attr_syscall(dirfd, "", AT_EMPTY_PATH);
+ if (treefd == -1) {
+ perror("open_tree_attr");
+ goto out;
+ }
+
+ fd = openat(treefd, TEST_FILE, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("openat");
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (dirfd != -1) {
+ close(dirfd);
+ }
+ if (treefd != -1) {
+ close(treefd);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return rc;
+}
+
+static void cleanup(void) {
+ if (unlink(TEST_DIR "/" TEST_FILE) == -1 && errno != ENOENT) {
+ perror("unlink");
+ }
+ if (rmdir(TEST_DIR) == -1 && errno != ENOENT) {
+ perror("rmdir");
+ }
+}
+
+int main(void) {
+ cleanup();
+
+ if (mkdir(TEST_DIR, 0777) == -1) {
+ perror("mkdir");
+ return 1;
+ }
+
+ int rc = test_no_flags() || test_at_empty_path() || test_relative_dirfd();
+
+ cleanup();
+
+ return rc;
+}
diff --git a/test/test-open_tree_attr-syscall.sh b/test/test-open_tree_attr-syscall.sh
new file mode 100755
index 0000000..3e50ebe
--- /dev/null
+++ b/test/test-open_tree_attr-syscall.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./test/test-open_tree_attr-syscall
+
+PSEUDO_IGNORE_PATHS=/ ./test/test-open_tree_attr-syscall
^ permalink raw reply related [flat|nested] 7+ messages in thread* [pseudo] [PATCH v3 6/6] ports/linux/guts: Add open_tree_attr wrapper
2026-09-07 11:18 [pseudo] [PATCH v3 0/6] Add open_tree() wrapper frezidok1
` (4 preceding siblings ...)
2026-09-07 11:18 ` [pseudo] [PATCH v3 5/6] test: Add open_tree_attr " frezidok1
@ 2026-09-07 11:18 ` frezidok1
5 siblings, 0 replies; 7+ messages in thread
From: frezidok1 @ 2026-09-07 11:18 UTC (permalink / raw)
To: yocto-patches; +Cc: Dmitry Sakhonchik
From: Dmitry Sakhonchik <frezidok1@gmail.com>
[YOCTO #16379]
It mostly mirrors open_tree, with the additional
mount attribute arguments passed to the underlying syscall.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
ports/linux/guts/open_tree_attr.c | 48 +++++++++++++++++++++++++++++++
ports/linux/portdefs.h | 9 ++++++
ports/linux/pseudo_wrappers.c | 16 +++++++++++
ports/linux/wrapfuncs.in | 1 +
pseudo_wrappers.c | 1 +
5 files changed, 75 insertions(+)
create mode 100644 ports/linux/guts/open_tree_attr.c
diff --git a/ports/linux/guts/open_tree_attr.c b/ports/linux/guts/open_tree_attr.c
new file mode 100644
index 0000000..da0315c
--- /dev/null
+++ b/ports/linux/guts/open_tree_attr.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2026 Yocto Project
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int open_tree_attr(int dirfd, const char *path, unsigned int flags, struct mount_attr *attr, size_t size)
+ * int rc = -1;
+ */
+
+ /* Mostly based on open_tree wrapper */
+
+ struct stat64 buf;
+ int save_errno;
+ char *pseudo_path;
+
+ if (real_open_tree_attr) {
+ pseudo_debug(PDBGF_SYSCALL, "open_tree_attr, calling open_tree_attr.\n");
+ rc = real_open_tree_attr(dirfd, path, flags, attr, size);
+ } else {
+ pseudo_debug(PDBGF_SYSCALL, "open_tree_attr, calling syscall.\n");
+ rc = real_syscall(SYS_open_tree_attr, dirfd, path, flags, attr, size);
+ }
+
+ pseudo_path = pseudo_root_path(__func__, __LINE__, dirfd, path, 0);
+
+ if (rc != -1) {
+ save_errno = errno;
+ int stat_rc;
+
+ stat_rc = real___fxstatat64(_STAT_VER, dirfd, pseudo_path, &buf, (flags & AT_SYMLINK_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+
+ pseudo_debug(PDBGF_FILE, "open_tree_attr(path %s), flags %o, stat rc %d, stat mode %o\n",
+ pseudo_path, flags, stat_rc, buf.st_mode);
+
+ if (stat_rc != -1) {
+ pseudo_client_op(OP_OPEN, 0, rc, dirfd, pseudo_path, &buf);
+ } else {
+ pseudo_debug(PDBGF_FILE, "open_tree_attr(fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n",
+ rc, dirfd, pseudo_path, flags, strerror(errno));
+ pseudo_client_op(OP_OPEN, 0, rc, dirfd, pseudo_path, 0);
+ }
+ errno = save_errno;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h
index 565fed9..af8b8e8 100644
--- a/ports/linux/portdefs.h
+++ b/ports/linux/portdefs.h
@@ -91,3 +91,12 @@ extern int unshare(int flags);
#define SYS_open_tree __NR_open_tree
#endif
+
+#ifndef SYS_open_tree_attr
+
+#ifndef __NR_open_tree_attr
+#define __NR_open_tree_attr 467
+#endif
+
+#define SYS_open_tree_attr __NR_open_tree_attr
+#endif
diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c
index 33cba2d..4141556 100644
--- a/ports/linux/pseudo_wrappers.c
+++ b/ports/linux/pseudo_wrappers.c
@@ -116,6 +116,22 @@ syscall(long number, ...) {
#error SYS_open_tree not defined
#endif
+#ifdef SYS_open_tree_attr
+ if (number == SYS_open_tree_attr) {
+ pseudo_debug(PDBGF_SYSCALL, "syscall, faking open_tree_attr.\n");
+ va_start(ap, number);
+ int dirfd = va_arg(ap, int);
+ const char *path = va_arg(ap, const char*);
+ unsigned int flags = va_arg(ap, unsigned int);
+ struct mount_attr *attr = va_arg(ap, struct mount_attr*);
+ size_t size = va_arg(ap, size_t);
+
+ return wrap_open_tree_attr(dirfd, path, flags, attr, size);
+ }
+#else
+#error SYS_open_tree_attr not defined
+#endif
+
#ifdef SYS_renameat2
/* Call out wrapper, expanding the variable arguments first */
if (number == SYS_renameat2) {
diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in
index a51e9a0..639d9a5 100644
--- a/ports/linux/wrapfuncs.in
+++ b/ports/linux/wrapfuncs.in
@@ -11,6 +11,7 @@ int __fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags
int openat(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=((flags&O_NOFOLLOW)||((flags&(O_CREAT|O_EXCL))==(O_CREAT|O_EXCL))), noignore_path=1 */
int __openat_2(int dirfd, const char *path, int flags); /* flags=((flags&O_NOFOLLOW)||((flags&(O_CREAT|O_EXCL))==(O_CREAT|O_EXCL))), noignore_path=1 */
int open_tree(int dirfd, const char *path, unsigned int flags); /* noignore_path=1 */
+int open_tree_attr(int dirfd, const char *path, unsigned int flags, struct mount_attr *attr, size_t size); /* noignore_path=1 */
int mknod(const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknod */
int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknodat */
int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 112239b..78cdecf 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -37,6 +37,7 @@
#include <grp.h>
#include <pwd.h>
#include <utime.h>
+#include <sys/mount.h>
#ifdef PSEUDO_PORT_LINUX_STATVFS
#include <sys/statvfs.h>
#endif
^ permalink raw reply related [flat|nested] 7+ messages in thread