1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2013 Red Hat, Inc.
4 * Copyright (c) Linux Test Project, 2013-2022
5 */
6
7 /*\
8 * [Description]
9 *
10 * Basic tests for open(2) and make sure open(2) works and handles error
11 * conditions correctly.
12 *
13 * There are 28 test cases:
14 *
15 * 1. Open regular file O_RDONLY
16 * 2. Open regular file O_WRONLY
17 * 3. Open regular file O_RDWR
18 * 4. Open regular file O_RDWR | O_SYNC
19 * 5. Open regular file O_RDWR | O_TRUNC
20 * 6. Open directory O_RDONLY
21 * 7. Open directory O_RDWR, expect EISDIR
22 * 8. Open regular file O_DIRECTORY, expect ENOTDIR
23 * 9. Open hard link file O_RDONLY
24 * 10. Open hard link file O_WRONLY
25 * 11. Open hard link file O_RDWR
26 * 12. Open symlink file O_RDONLY
27 * 13. Open symlink file O_WRONLY
28 * 14. Open symlink file O_RDWR
29 * 15. Open symlink directory O_RDONLY
30 * 16. Open symlink directory O_WRONLY, expect EISDIR
31 * 17. Open symlink directory O_RDWR, expect EISDIR
32 * 18. Open device special file O_RDONLY
33 * 19. Open device special file O_WRONLY
34 * 20. Open device special file O_RDWR
35 * 21. Open non-existing regular file in existing dir
36 * 22. Open link file O_RDONLY | O_CREAT
37 * 23. Open symlink file O_RDONLY | O_CREAT
38 * 24. Open regular file O_RDONLY | O_CREAT
39 * 25. Open symlink directory O_RDONLY | O_CREAT, expect EISDIR
40 * 26. Open directory O_RDONLY | O_CREAT, expect EISDIR
41 * 27. Open regular file O_RDONLY | O_TRUNC, behaviour is undefined but should
42 * not oops or hang
43 * 28. Open regular file(non-empty) O_RDONLY | O_TRUNC, behaviour is undefined
44 * but should not oops or hang
45 */
46
47 #define _GNU_SOURCE
48 #include <errno.h>
49 #include <sys/sysmacros.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54
55 #include "tst_test.h"
56
57 #define MNTPOINT "mntpoint"
58 #define T_REG "t_reg" /* regular file with content */
59 #define T_REG_EMPTY "t_reg_empty" /* empty regular file */
60 #define T_LINK_REG "t_link_reg" /* hard link to T_REG */
61 #define T_NEW_REG "t_new_reg" /* new regular file to be created */
62 #define T_SYMLINK_REG "t_symlink_reg" /* symlink to T_REG */
63 #define T_DIR "t_dir" /* test directory */
64 #define T_SYMLINK_DIR "t_symlink_dir" /* symlink to T_DIR */
65 #define T_DEV MNTPOINT"/t_dev" /* test device special file */
66
67 #define T_MSG "this is a test string"
68
69 static struct test_case {
70 char *desc;
71 char *path;
72 int flags;
73 mode_t mode;
74 int err;
75 } tc[] = {
76 /* Test open(2) regular file */
77 {
78 .desc = "open regular file O_RDONLY",
79 .path = T_REG_EMPTY,
80 .flags = O_RDONLY,
81 .mode = 0644,
82 },
83 {
84 .desc = "open regular file O_WRONLY",
85 .path = T_REG_EMPTY,
86 .flags = O_WRONLY,
87 .mode = 0644,
88 },
89 {
90 .desc = "open regular file O_RDWR",
91 .path = T_REG_EMPTY,
92 .flags = O_RDWR,
93 .mode = 0644,
94 },
95 {
96 .desc = "open regular file O_RDWR | O_SYNC",
97 .path = T_REG_EMPTY,
98 .flags = O_RDWR | O_SYNC,
99 .mode = 0644,
100 },
101 {
102 .desc = "open regular file O_RDWR | O_TRUNC",
103 .path = T_REG_EMPTY,
104 .flags = O_RDWR | O_TRUNC,
105 .mode = 0644,
106 },
107
108 /* Test open(2) directory */
109 {
110 .desc = "open directory O_RDONLY",
111 .path = T_DIR,
112 .flags = O_RDONLY,
113 .mode = 0755,
114 },
115 {
116 .desc = "open directory O_RDWR",
117 .path = T_DIR,
118 .flags = O_RDWR,
119 .mode = 0755,
120 .err = EISDIR,
121 },
122 {
123 .desc = "open regular file O_DIRECTORY",
124 .path = T_REG_EMPTY,
125 .flags = O_RDONLY | O_DIRECTORY,
126 .mode = 0644,
127 .err = ENOTDIR,
128 },
129 /* Test open(2) hard link */
130 {
131 .desc = "open hard link file O_RDONLY",
132 .path = T_LINK_REG,
133 .flags = O_RDONLY,
134 .mode = 0644,
135 },
136 {
137 .desc = "open hard link file O_WRONLY",
138 .path = T_LINK_REG,
139 .flags = O_WRONLY,
140 .mode = 0644,
141 },
142 {
143 .desc = "open hard link file O_RDWR",
144 .path = T_LINK_REG,
145 .flags = O_RDWR,
146 .mode = 0644,
147 },
148
149 /* Test open(2) symlink */
150 {
151 .desc = "open symlink file O_RDONLY",
152 .path = T_SYMLINK_REG,
153 .flags = O_RDONLY,
154 .mode = 0644,
155 },
156 {
157 .desc = "open symlink file O_WRONLY",
158 .path = T_SYMLINK_REG,
159 .flags = O_WRONLY,
160 .mode = 0644,
161 },
162 {
163 .desc = "open symlink file O_RDWR",
164 .path = T_SYMLINK_REG,
165 .flags = O_RDWR,
166 .mode = 0644,
167 },
168 {
169 .desc = "open symlink directory O_RDONLY",
170 .path = T_SYMLINK_DIR,
171 .flags = O_RDONLY,
172 .mode = 0644,
173 },
174 {
175 .desc = "open symlink directory O_WRONLY",
176 .path = T_SYMLINK_DIR,
177 .flags = O_WRONLY,
178 .mode = 0644,
179 .err = EISDIR,
180 },
181 {
182 .desc = "open symlink directory O_RDWR",
183 .path = T_SYMLINK_DIR,
184 .flags = O_RDWR,
185 .mode = 0644,
186 .err = EISDIR,
187 },
188
189 /* Test open(2) device special */
190 {
191 .desc = "open device special file O_RDONLY",
192 .path = T_DEV,
193 .flags = O_RDONLY,
194 .mode = 0644,
195 },
196 {
197 .desc = "open device special file O_WRONLY",
198 .path = T_DEV,
199 .flags = O_WRONLY,
200 .mode = 0644,
201 },
202 {
203 .desc = "open device special file O_RDWR",
204 .path = T_DEV,
205 .flags = O_RDWR,
206 .mode = 0644,
207 },
208
209 /* Test open(2) non-existing file */
210 {
211 .desc = "open non-existing regular file in existing dir",
212 .path = T_DIR"/"T_NEW_REG,
213 .flags = O_RDWR | O_CREAT,
214 .mode = 0644,
215 },
216
217 /* test open(2) with O_CREAT */
218 {
219 .desc = "open link file O_RDONLY | O_CREAT",
220 .path = T_LINK_REG,
221 .flags = O_RDONLY | O_CREAT,
222 .mode = 0644,
223 },
224 {
225 .desc = "open symlink file O_RDONLY | O_CREAT",
226 .path = T_SYMLINK_REG,
227 .flags = O_RDONLY | O_CREAT,
228 .mode = 0644,
229 },
230 {
231 .desc = "open regular file O_RDONLY | O_CREAT",
232 .path = T_REG_EMPTY,
233 .flags = O_RDONLY | O_CREAT,
234 .mode = 0644,
235 },
236 {
237 .desc = "open symlink directory O_RDONLY | O_CREAT",
238 .path = T_SYMLINK_DIR,
239 .flags = O_RDONLY | O_CREAT,
240 .mode = 0644,
241 .err = EISDIR,
242 },
243 {
244 .desc = "open directory O_RDONLY | O_CREAT",
245 .path = T_DIR,
246 .flags = O_RDONLY | O_CREAT,
247 .mode = 0644,
248 .err = EISDIR,
249 },
250
251 /* Other random open(2) tests */
252 {
253 .desc = "open regular file O_RDONLY | O_TRUNC, "
254 "behaviour is undefined but should not oops or hang",
255 .path = T_REG_EMPTY,
256 .flags = O_RDONLY | O_TRUNC,
257 .mode = 0644,
258 .err = -1,
259 },
260 {
261 .desc = "open regular file(non-empty) O_RDONLY | O_TRUNC, "
262 "behaviour is undefined but should not oops or hang",
263 .path = T_REG,
264 .flags = O_RDONLY | O_TRUNC,
265 .mode = 0644,
266 .err = -1,
267 },
268 };
269
verify_open(unsigned int n)270 static void verify_open(unsigned int n)
271 {
272 if (tc[n].err > 0) {
273 TST_EXP_FAIL2(open(tc[n].path, tc[n].flags, tc[n].mode),
274 tc[n].err, "%s", tc[n].desc);
275 } else if (tc[n].err == 0) {
276 TST_EXP_FD(open(tc[n].path, tc[n].flags, tc[n].mode),
277 "%s", tc[n].desc);
278 } else {
279 TEST(open(tc[n].path, tc[n].flags, tc[n].mode));
280 tst_res(TPASS, "%s", tc[n].desc);
281 }
282
283 if (TST_RET > 0)
284 SAFE_CLOSE(TST_RET);
285 }
286
setup(void)287 static void setup(void)
288 {
289 int fd;
290 int ret;
291
292 fd = SAFE_OPEN(T_REG, O_WRONLY | O_CREAT, 0644);
293 ret = write(fd, T_MSG, sizeof(T_MSG));
294 if (ret == -1) {
295 SAFE_CLOSE(fd);
296 tst_brk(TBROK | TERRNO, "Write %s failed", T_REG);
297 }
298 SAFE_CLOSE(fd);
299
300 SAFE_TOUCH(T_REG_EMPTY, 0644, NULL);
301 SAFE_LINK(T_REG, T_LINK_REG);
302 SAFE_SYMLINK(T_REG, T_SYMLINK_REG);
303 SAFE_MKDIR(T_DIR, 0755);
304 SAFE_SYMLINK(T_DIR, T_SYMLINK_DIR);
305 SAFE_MKNOD(T_DEV, S_IFCHR, makedev(1, 5));
306 }
307
308 static struct tst_test test = {
309 .tcnt = ARRAY_SIZE(tc),
310 .setup = setup,
311 .test = verify_open,
312 .needs_devfs = 1,
313 .mntpoint = MNTPOINT,
314 .needs_root = 1,
315 };
316