// SPDX-License-Identifier: GPL-2.0-or-later
+#define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
-#include "kselftest.h"
+#include "kselftest_harness.h"
#ifndef O_EMPTYPATH
#define O_EMPTYPATH (1 << 26)
#endif
-int main(void)
+#define EMPTYPATH_TEST_FILE "/tmp/emptypath_test"
+
+FIXTURE(emptypath) {
+ int opath_fd;
+};
+
+FIXTURE_SETUP(emptypath)
{
- int opath_fd, reopen_fd;
- const char *path = "/tmp/emptypath_test";
-
- ksft_print_header();
- ksft_set_plan(2);
-
- opath_fd = open(path, O_CREAT | O_WRONLY, S_IRWXU);
- if (opath_fd < 0)
- ksft_exit_fail_msg("create %s: %m\n", path);
- close(opath_fd);
-
- opath_fd = open(path, O_PATH);
- if (opath_fd < 0)
- ksft_exit_fail_msg("open %s O_PATH: %m\n", path);
-
- reopen_fd = openat(opath_fd, "", O_RDONLY);
- if (reopen_fd < 0 && errno == ENOENT)
- ksft_test_result_pass("empty path without O_EMPTYPATH returns ENOENT\n");
- else if (reopen_fd >= 0) {
- ksft_test_result_fail("empty path without O_EMPTYPATH unexpectedly succeeded\n");
- close(reopen_fd);
- } else {
- ksft_test_result_fail("empty path without O_EMPTYPATH: expected ENOENT, got %m\n");
+ int fd;
+
+ self->opath_fd = -1;
+
+ fd = open(EMPTYPATH_TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+ ASSERT_GE(fd, 0) {
+ TH_LOG("create %s: %s", EMPTYPATH_TEST_FILE, strerror(errno));
}
+ close(fd);
- reopen_fd = openat(opath_fd, "", O_RDONLY | O_EMPTYPATH);
+ self->opath_fd = open(EMPTYPATH_TEST_FILE, O_PATH);
+ ASSERT_GE(self->opath_fd, 0) {
+ TH_LOG("open %s O_PATH: %s", EMPTYPATH_TEST_FILE, strerror(errno));
+ }
+}
- if (reopen_fd < 0 && errno == EINVAL)
- ksft_exit_skip("O_EMPTYPATH not supported\n");
+FIXTURE_TEARDOWN(emptypath)
+{
+ if (self->opath_fd >= 0)
+ close(self->opath_fd);
+ unlink(EMPTYPATH_TEST_FILE);
+}
- if (reopen_fd >= 0) {
- ksft_test_result_pass("O_EMPTYPATH reopens O_PATH fd\n");
- close(reopen_fd);
- } else {
- ksft_test_result_fail("O_EMPTYPATH failed: %m\n");
+/* An empty path is rejected with ENOENT unless O_EMPTYPATH is set. */
+TEST_F(emptypath, without_flag_returns_enoent)
+{
+ int fd = openat(self->opath_fd, "", O_RDONLY);
+
+ if (fd >= 0)
+ close(fd);
+ ASSERT_LT(fd, 0) {
+ TH_LOG("empty path without O_EMPTYPATH unexpectedly succeeded");
+ }
+ EXPECT_EQ(errno, ENOENT) {
+ TH_LOG("expected ENOENT, got %s", strerror(errno));
}
+}
+
+/* O_EMPTYPATH reopens the O_PATH fd through an empty path. */
+TEST_F(emptypath, reopens_opath_fd)
+{
+ int fd = openat(self->opath_fd, "", O_RDONLY | O_EMPTYPATH);
+
+ if (fd < 0 && errno == EINVAL)
+ SKIP(return, "O_EMPTYPATH not supported");
- unlink(path);
- ksft_finished();
+ ASSERT_GE(fd, 0) {
+ TH_LOG("O_EMPTYPATH failed: %s", strerror(errno));
+ }
+ close(fd);
}
+
+TEST_HARNESS_MAIN