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