1 // SPDX-License-Identifier: GPL-2.0-or-later
10 #include "../kselftest.h"
12 int sys_fchmodat2(int dfd
, const char *filename
, mode_t mode
, int flags
)
14 int ret
= syscall(__NR_fchmodat2
, dfd
, filename
, mode
, flags
);
16 return ret
>= 0 ? ret
: -errno
;
19 int setup_testdir(void)
22 char dirname
[] = "/tmp/ksft-fchmodat2.XXXXXX";
24 /* Make the top-level directory. */
25 if (!mkdtemp(dirname
))
26 ksft_exit_fail_msg("%s: failed to create tmpdir\n", __func__
);
28 dfd
= open(dirname
, O_PATH
| O_DIRECTORY
);
30 ksft_exit_fail_msg("%s: failed to open tmpdir\n", __func__
);
32 ret
= openat(dfd
, "regfile", O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
34 ksft_exit_fail_msg("%s: failed to create file in tmpdir\n",
38 ret
= symlinkat("regfile", dfd
, "symlink");
40 ksft_exit_fail_msg("%s: failed to create symlink in tmpdir\n",
46 int expect_mode(int dfd
, const char *filename
, mode_t expect_mode
)
49 int ret
= fstatat(dfd
, filename
, &st
, AT_SYMLINK_NOFOLLOW
);
52 ksft_exit_fail_msg("%s: %s: fstatat failed\n",
55 return (st
.st_mode
== expect_mode
);
58 void test_regfile(void)
62 dfd
= setup_testdir();
64 ret
= sys_fchmodat2(dfd
, "regfile", 0640, 0);
67 ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__
);
69 if (!expect_mode(dfd
, "regfile", 0100640))
70 ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n",
73 ret
= sys_fchmodat2(dfd
, "regfile", 0600, AT_SYMLINK_NOFOLLOW
);
76 ksft_exit_fail_msg("%s: fchmodat2(AT_SYMLINK_NOFOLLOW) failed\n",
79 if (!expect_mode(dfd
, "regfile", 0100600))
80 ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n",
83 ksft_test_result_pass("fchmodat2(regfile)\n");
86 void test_symlink(void)
90 dfd
= setup_testdir();
92 ret
= sys_fchmodat2(dfd
, "symlink", 0640, 0);
95 ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__
);
97 if (!expect_mode(dfd
, "regfile", 0100640))
98 ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n",
101 if (!expect_mode(dfd
, "symlink", 0120777))
102 ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2\n",
105 ret
= sys_fchmodat2(dfd
, "symlink", 0600, AT_SYMLINK_NOFOLLOW
);
108 * On certain filesystems (xfs or btrfs), chmod operation fails. So we
109 * first check the symlink target but if the operation fails we mark the
112 * https://sourceware.org/legacy-ml/libc-alpha/2020-02/msg00467.html
114 if (ret
== 0 && !expect_mode(dfd
, "symlink", 0120600))
115 ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2 with nofollow\n",
118 if (!expect_mode(dfd
, "regfile", 0100640))
119 ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n",
123 ksft_test_result_skip("fchmodat2(symlink)\n");
125 ksft_test_result_pass("fchmodat2(symlink)\n");
130 int main(int argc
, char **argv
)
133 ksft_set_plan(NUM_TESTS
);
138 if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0)