brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · e031941 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3#define _GNU_SOURCE4#include <fcntl.h>5#include <sys/stat.h>6#include <sys/types.h>7#include <syscall.h>8#include <unistd.h>9 10#include "../kselftest.h"11 12int sys_fchmodat2(int dfd, const char *filename, mode_t mode, int flags)13{14	int ret = syscall(__NR_fchmodat2, dfd, filename, mode, flags);15 16	return ret >= 0 ? ret : -errno;17}18 19int setup_testdir(void)20{21	int dfd, ret;22	char dirname[] = "/tmp/ksft-fchmodat2.XXXXXX";23 24	/* Make the top-level directory. */25	if (!mkdtemp(dirname))26		ksft_exit_fail_msg("%s: failed to create tmpdir\n", __func__);27 28	dfd = open(dirname, O_PATH | O_DIRECTORY);29	if (dfd < 0)30		ksft_exit_fail_msg("%s: failed to open tmpdir\n", __func__);31 32	ret = openat(dfd, "regfile", O_CREAT | O_WRONLY | O_TRUNC, 0644);33	if (ret < 0)34		ksft_exit_fail_msg("%s: failed to create file in tmpdir\n",35				__func__);36	close(ret);37 38	ret = symlinkat("regfile", dfd, "symlink");39	if (ret < 0)40		ksft_exit_fail_msg("%s: failed to create symlink in tmpdir\n",41				__func__);42 43	return dfd;44}45 46int expect_mode(int dfd, const char *filename, mode_t expect_mode)47{48	struct stat st;49	int ret = fstatat(dfd, filename, &st, AT_SYMLINK_NOFOLLOW);50 51	if (ret)52		ksft_exit_fail_msg("%s: %s: fstatat failed\n",53				__func__, filename);54 55	return (st.st_mode == expect_mode);56}57 58void test_regfile(void)59{60	int dfd, ret;61 62	dfd = setup_testdir();63 64	ret = sys_fchmodat2(dfd, "regfile", 0640, 0);65 66	if (ret < 0)67		ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__);68 69	if (!expect_mode(dfd, "regfile", 0100640))70		ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n",71				__func__);72 73	ret = sys_fchmodat2(dfd, "regfile", 0600, AT_SYMLINK_NOFOLLOW);74 75	if (ret < 0)76		ksft_exit_fail_msg("%s: fchmodat2(AT_SYMLINK_NOFOLLOW) failed\n",77				__func__);78 79	if (!expect_mode(dfd, "regfile", 0100600))80		ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n",81				__func__);82 83	ksft_test_result_pass("fchmodat2(regfile)\n");84}85 86void test_symlink(void)87{88	int dfd, ret;89 90	dfd = setup_testdir();91 92	ret = sys_fchmodat2(dfd, "symlink", 0640, 0);93 94	if (ret < 0)95		ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__);96 97	if (!expect_mode(dfd, "regfile", 0100640))98		ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n",99				__func__);100 101	if (!expect_mode(dfd, "symlink", 0120777))102		ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2\n",103				__func__);104 105	ret = sys_fchmodat2(dfd, "symlink", 0600, AT_SYMLINK_NOFOLLOW);106 107	/*108	 * On certain filesystems (xfs or btrfs), chmod operation fails. So we109	 * first check the symlink target but if the operation fails we mark the110	 * test as skipped.111	 *112	 * https://sourceware.org/legacy-ml/libc-alpha/2020-02/msg00467.html113	 */114	if (ret == 0 && !expect_mode(dfd, "symlink", 0120600))115		ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2 with nofollow\n",116				__func__);117 118	if (!expect_mode(dfd, "regfile", 0100640))119		ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n",120				__func__);121 122	if (ret != 0)123		ksft_test_result_skip("fchmodat2(symlink)\n");124	else125		ksft_test_result_pass("fchmodat2(symlink)\n");126}127 128#define NUM_TESTS 2129 130int main(int argc, char **argv)131{132	ksft_print_header();133	ksft_set_plan(NUM_TESTS);134 135	test_regfile();136	test_symlink();137 138	if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0)139		ksft_exit_fail();140	else141		ksft_exit_pass();142}143