1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2021 SUSE LLC
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci/*\
6f08c3bdfSopenharmony_ci * [Description]
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * - First check close_range works on a valid range.
9f08c3bdfSopenharmony_ci * - Then check close_range does not accept invalid paramters.
10f08c3bdfSopenharmony_ci * - Then check it accepts a large lower fd.
11f08c3bdfSopenharmony_ci * - Finally check CLOEXEC works
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci */
14f08c3bdfSopenharmony_ci
15f08c3bdfSopenharmony_ci#include <stdlib.h>
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci#include "tst_test.h"
18f08c3bdfSopenharmony_ci#include "tst_clone.h"
19f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
20f08c3bdfSopenharmony_ci#include "lapi/close_range.h"
21f08c3bdfSopenharmony_ci#include "lapi/sched.h"
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_cistatic int try_close_range(int fd, int flags)
24f08c3bdfSopenharmony_ci{
25f08c3bdfSopenharmony_ci	int res;
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci	TEST(close_range(fd, fd, flags));
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci	if (TST_RET == -1 && TST_ERR == EINVAL)
30f08c3bdfSopenharmony_ci		res = TCONF;
31f08c3bdfSopenharmony_ci	else if (TST_RET == -1)
32f08c3bdfSopenharmony_ci		res = TFAIL;
33f08c3bdfSopenharmony_ci	else
34f08c3bdfSopenharmony_ci		res = TPASS;
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ci	return res;
37f08c3bdfSopenharmony_ci}
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic void run(unsigned int n)
40f08c3bdfSopenharmony_ci{
41f08c3bdfSopenharmony_ci	const struct tst_clone_args args = {
42f08c3bdfSopenharmony_ci		.flags = CLONE_FILES,
43f08c3bdfSopenharmony_ci		.exit_signal = SIGCHLD,
44f08c3bdfSopenharmony_ci	};
45f08c3bdfSopenharmony_ci	int fd = -1, res;
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci	switch (n) {
48f08c3bdfSopenharmony_ci	case 0:
49f08c3bdfSopenharmony_ci		fd = SAFE_OPEN("/", O_PATH);
50f08c3bdfSopenharmony_ci		SAFE_DUP2(fd, 100);
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci		TST_EXP_PASS(close_range(fd, 100, 0),
53f08c3bdfSopenharmony_ci			     "close_range(%d, 100, 0)", fd);
54f08c3bdfSopenharmony_ci		TST_EXP_FAIL(fcntl(fd, F_GETFD), EBADF,
55f08c3bdfSopenharmony_ci			     "fcntl(%d, F_GETFD)", fd);
56f08c3bdfSopenharmony_ci		TST_EXP_FAIL(fcntl(100, F_GETFD), EBADF);
57f08c3bdfSopenharmony_ci		break;
58f08c3bdfSopenharmony_ci	case 1:
59f08c3bdfSopenharmony_ci		TST_EXP_FAIL(close_range(4, 3, 0), EINVAL);
60f08c3bdfSopenharmony_ci		break;
61f08c3bdfSopenharmony_ci	case 2:
62f08c3bdfSopenharmony_ci		TST_EXP_FAIL(close_range(3, ~0U, ~0U), EINVAL);
63f08c3bdfSopenharmony_ci		break;
64f08c3bdfSopenharmony_ci	case 3:
65f08c3bdfSopenharmony_ci		TST_EXP_PASS(close_range(~0U, ~0U, 0));
66f08c3bdfSopenharmony_ci		break;
67f08c3bdfSopenharmony_ci	case 4:
68f08c3bdfSopenharmony_ci		fd = SAFE_OPEN("/", O_PATH);
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci		res = try_close_range(fd, CLOSE_RANGE_CLOEXEC);
71f08c3bdfSopenharmony_ci		tst_res(res | TTERRNO,
72f08c3bdfSopenharmony_ci			"close_range(%d, %d, CLOSE_RANGE_CLOEXEC)", fd, fd);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci		if (res != TPASS)
75f08c3bdfSopenharmony_ci			break;
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci		TST_EXP_FD_SILENT(fcntl(fd, F_GETFD), "fcntl(%d, F_GETFD)", fd);
78f08c3bdfSopenharmony_ci		if (TST_RET & FD_CLOEXEC)
79f08c3bdfSopenharmony_ci			tst_res(TPASS, "FD_CLOEXEC was set on %d", fd);
80f08c3bdfSopenharmony_ci		else
81f08c3bdfSopenharmony_ci			tst_res(TFAIL, "FD_CLOEXEC not set on %d", fd);
82f08c3bdfSopenharmony_ci		break;
83f08c3bdfSopenharmony_ci	case 5:
84f08c3bdfSopenharmony_ci		fd = SAFE_OPEN("/", O_PATH);
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci		if (!SAFE_CLONE(&args)) {
87f08c3bdfSopenharmony_ci			res = try_close_range(fd, CLOSE_RANGE_UNSHARE);
88f08c3bdfSopenharmony_ci			tst_res(res | TTERRNO,
89f08c3bdfSopenharmony_ci				"close_range(%d, %d, CLOSE_RANGE_UNSHARE)",
90f08c3bdfSopenharmony_ci				fd, fd);
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci			if (res != TPASS)
93f08c3bdfSopenharmony_ci				exit(0);
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci			TST_EXP_FAIL(fcntl(fd, F_GETFD), EBADF,
96f08c3bdfSopenharmony_ci				     "fcntl(%d, F_GETFD)", fd);
97f08c3bdfSopenharmony_ci			exit(0);
98f08c3bdfSopenharmony_ci		}
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci		tst_reap_children();
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci		TST_EXP_PASS(fcntl(fd, F_GETFD), "%d is open", fd);
103f08c3bdfSopenharmony_ci	}
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	if (fd > -1)
106f08c3bdfSopenharmony_ci		TST_EXP_PASS_SILENT(close_range(fd, fd, 0),
107f08c3bdfSopenharmony_ci				    "close_range(%d, %d, 0)", fd, fd);
108f08c3bdfSopenharmony_ci}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_cistatic struct tst_test test = {
111f08c3bdfSopenharmony_ci	.tcnt = 6,
112f08c3bdfSopenharmony_ci	.forks_child = 1,
113f08c3bdfSopenharmony_ci	.test = run,
114f08c3bdfSopenharmony_ci	.setup = close_range_supported_by_kernel,
115f08c3bdfSopenharmony_ci};
116