1 /*
2  * Copyright (C) 2013 Red Hat, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of version 2 of the GNU General Public
6  * License as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it
13  * is free of the rightful claim of any third person regarding
14  * infringement or the like.  Any license provided herein, whether
15  * implied or otherwise, applies only to this software file.  Patent
16  * licenses, if any, provided herein do not apply to combinations of
17  * this program with other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA.
23  */
24 
25 /*
26  * Basic tests for open(2) and make sure open(2) works and handles error
27  * conditions correctly.
28  *
29  * There are 28 test cases:
30  * 1. Open regular file O_RDONLY
31  * 2. Open regular file O_WRONLY
32  * 3. Open regular file O_RDWR
33  * 4. Open regular file O_RDWR | O_SYNC
34  * 5. Open regular file O_RDWR | O_TRUNC
35  * 6. Open dir O_RDONLY
36  * 7. Open dir O_RDWR, expect EISDIR
37  * 8. Open regular file O_DIRECTORY, expect ENOTDIR
38  * 9. Open hard link file O_RDONLY
39  * 10. Open hard link file O_WRONLY
40  * 11. Open hard link file O_RDWR
41  * 12. Open sym link file O_RDONLY
42  * 13. Open sym link file O_WRONLY
43  * 14. Open sym link file O_RDWR
44  * 15. Open sym link dir O_RDONLY
45  * 16. Open sym link dir O_WRONLY, expect EISDIR
46  * 17. Open sym link dir O_RDWR, expect EISDIR
47  * 18. Open device special file O_RDONLY
48  * 19. Open device special file O_WRONLY
49  * 20. Open device special file O_RDWR
50  * 21. Open non-existing regular file in existing dir
51  * 22. Open link file O_RDONLY | O_CREAT
52  * 23. Open symlink file O_RDONLY | O_CREAT
53  * 24. Open regular file O_RDONLY | O_CREAT
54  * 25. Open symlink dir O_RDONLY | O_CREAT, expect EISDIR
55  * 26. Open dir O_RDONLY | O_CREAT, expect EISDIR
56  * 27. Open regular file O_RDONLY | O_TRUNC, behaviour is undefined but should
57  *     not oops or hang
58  * 28. Open regular file(non-empty) O_RDONLY | O_TRUNC, behaviour is undefined
59  *     but should not oops or hang
60  */
61 
62 #define _GNU_SOURCE
63 #include "config.h"
64 #include <sys/types.h>
65 #include <sys/stat.h>
66 #include <sys/sysmacros.h>
67 #include <sys/wait.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <unistd.h>
71 #include <signal.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 
76 #include "test.h"
77 #include "safe_macros.h"
78 
79 char *TCID = "open11";
80 
81 /* Define test files */
82 #define T_REG "t_reg"			/* regular file with content */
83 #define T_REG_EMPTY "t_reg_empty"	/* empty regular file */
84 #define T_LINK_REG "t_link_reg"		/* hard link to T_REG */
85 #define T_NEW_REG "t_new_reg"		/* new regular file to be created */
86 #define T_SYMLINK_REG "t_symlink_reg"	/* symlink to T_REG */
87 #define T_DIR "t_dir"			/* test dir */
88 #define T_SYMLINK_DIR "t_symlink_dir"	/* symlink to T_DIR */
89 #define T_DEV "t_dev"			/* test device special file */
90 
91 #define T_MSG "this is a test string"
92 
93 static void setup(void);
94 static void cleanup(void);
95 
96 struct test_case {
97 	char *desc;
98 	char *path;
99 	int flags;
100 	mode_t mode;
101 	int err;
102 };
103 struct test_case tc[] = {
104 	/*
105 	 * Test open(2) regular file
106 	 */
107 	{	/* open regular file O_RDONLY */
108 		.desc = "Open regular file O_RDONLY",
109 		.path = T_REG_EMPTY,
110 		.flags = O_RDONLY,
111 		.mode = 0644,
112 		.err = 0,
113 	},
114 	{	/* open regular file O_WRONLY */
115 		.desc = "Open regular file O_WRONLY",
116 		.path = T_REG_EMPTY,
117 		.flags = O_WRONLY,
118 		.mode = 0644,
119 		.err = 0,
120 	},
121 	{	/* open regular file O_RDWR */
122 		.desc = "Open regular file O_RDWR",
123 		.path = T_REG_EMPTY,
124 		.flags = O_RDWR,
125 		.mode = 0644,
126 		.err = 0,
127 	},
128 	{	/* open regular file O_RDWR | O_SYNC*/
129 		.desc = "Open regular file O_RDWR | O_SYNC",
130 		.path = T_REG_EMPTY,
131 		.flags = O_RDWR | O_SYNC,
132 		.mode = 0644,
133 		.err = 0,
134 	},
135 	{	/* open regular file O_RDWR | O_TRUNC */
136 		.desc = "Open regular file O_RDWR | O_TRUNC",
137 		.path = T_REG_EMPTY,
138 		.flags = O_RDWR | O_TRUNC,
139 		.mode = 0644,
140 		.err = 0,
141 	},
142 	/*
143 	 * Test open(2) directory
144 	 */
145 	{	/* open dir O_RDONLY */
146 		.desc = "Open dir O_RDONLY",
147 		.path = T_DIR,
148 		.flags = O_RDONLY,
149 		.mode = 0755,
150 		.err = 0,
151 	},
152 	{	/* open dir O_RDWR */
153 		.desc = "Open dir O_RDWR, expect EISDIR",
154 		.path = T_DIR,
155 		.flags = O_RDWR,
156 		.mode = 0755,
157 		.err = EISDIR,
158 	},
159 	{	/* open regular file O_DIRECTORY */
160 		.desc = "Open regular file O_DIRECTORY, expect ENOTDIR",
161 		.path = T_REG_EMPTY,
162 		.flags = O_RDONLY | O_DIRECTORY,
163 		.mode = 0644,
164 		.err = ENOTDIR,
165 	},
166 	/*
167 	 * Test open(2) hard link
168 	 */
169 	{	/* open hard link file O_RDONLY */
170 		.desc = "Open hard link file O_RDONLY",
171 		.path = T_LINK_REG,
172 		.flags = O_RDONLY,
173 		.mode = 0644,
174 		.err = 0,
175 	},
176 	{	/* open hard link file O_WRONLY */
177 		.desc = "Open hard link file O_WRONLY",
178 		.path = T_LINK_REG,
179 		.flags = O_WRONLY,
180 		.mode = 0644,
181 		.err = 0,
182 	},
183 	{	/* open hard link file O_RDWR */
184 		.desc = "Open hard link file O_RDWR",
185 		.path = T_LINK_REG,
186 		.flags = O_RDWR,
187 		.mode = 0644,
188 		.err = 0,
189 	},
190 	/*
191 	 * Test open(2) sym link
192 	 */
193 	{	/* open sym link file O_RDONLY */
194 		.desc = "Open sym link file O_RDONLY",
195 		.path = T_SYMLINK_REG,
196 		.flags = O_RDONLY,
197 		.mode = 0644,
198 		.err = 0,
199 	},
200 	{	/* open sym link file O_WRONLY */
201 		.desc = "Open sym link file O_WRONLY",
202 		.path = T_SYMLINK_REG,
203 		.flags = O_WRONLY,
204 		.mode = 0644,
205 		.err = 0,
206 	},
207 	{	/* open sym link file O_RDWR */
208 		.desc = "Open sym link file O_RDWR",
209 		.path = T_SYMLINK_REG,
210 		.flags = O_RDWR,
211 		.mode = 0644,
212 		.err = 0,
213 	},
214 	{	/* open sym link dir O_RDONLY */
215 		.desc = "Open sym link dir O_RDONLY",
216 		.path = T_SYMLINK_DIR,
217 		.flags = O_RDONLY,
218 		.mode = 0644,
219 		.err = 0,
220 	},
221 	{	/* open sym link dir O_WRONLY */
222 		.desc = "Open sym link dir O_WRONLY, expect EISDIR",
223 		.path = T_SYMLINK_DIR,
224 		.flags = O_WRONLY,
225 		.mode = 0644,
226 		.err = EISDIR,
227 	},
228 	{	/* open sym link dir O_RDWR */
229 		.desc = "Open sym link dir O_RDWR, expect EISDIR",
230 		.path = T_SYMLINK_DIR,
231 		.flags = O_RDWR,
232 		.mode = 0644,
233 		.err = EISDIR,
234 	},
235 	/*
236 	 * Test open(2) device special
237 	 */
238 	{	/* open device special file O_RDONLY */
239 		.desc = "Open device special file O_RDONLY",
240 		.path = T_DEV,
241 		.flags = O_RDONLY,
242 		.mode = 0644,
243 		.err = 0,
244 	},
245 	{	/* open device special file O_WRONLY */
246 		.desc = "Open device special file O_WRONLY",
247 		.path = T_DEV,
248 		.flags = O_WRONLY,
249 		.mode = 0644,
250 		.err = 0,
251 	},
252 	{	/* open device special file O_RDWR */
253 		.desc = "Open device special file O_RDWR",
254 		.path = T_DEV,
255 		.flags = O_RDWR,
256 		.mode = 0644,
257 		.err = 0,
258 	},
259 	/*
260 	 * Test open(2) non-existing file
261 	 */
262 	{	/* open non-existing regular file in existing dir */
263 		.desc = "Open non-existing regular file in existing dir",
264 		.path = T_DIR"/"T_NEW_REG,
265 		.flags = O_RDWR | O_CREAT,
266 		.mode = 0644,
267 		.err = 0,
268 	},
269 	/*
270 	 * test open(2) with O_CREAT
271 	 */
272 	{	/* open hard link file O_RDONLY | O_CREAT */
273 		.desc = "Open link file O_RDONLY | O_CREAT",
274 		.path = T_LINK_REG,
275 		.flags = O_RDONLY | O_CREAT,
276 		.mode = 0644,
277 		.err = 0,
278 	},
279 	{	/* open sym link file O_RDONLY | O_CREAT */
280 		.desc = "Open symlink file O_RDONLY | O_CREAT",
281 		.path = T_SYMLINK_REG,
282 		.flags = O_RDONLY | O_CREAT,
283 		.mode = 0644,
284 		.err = 0,
285 	},
286 	{	/* open regular file O_RDONLY | O_CREAT */
287 		.desc = "Open regular file O_RDONLY | O_CREAT",
288 		.path = T_REG_EMPTY,
289 		.flags = O_RDONLY | O_CREAT,
290 		.mode = 0644,
291 		.err = 0,
292 	},
293 	{	/* open symlink dir O_RDONLY | O_CREAT */
294 		.desc = "Open symlink dir O_RDONLY | O_CREAT, expect EISDIR",
295 		.path = T_SYMLINK_DIR,
296 		.flags = O_RDONLY | O_CREAT,
297 		.mode = 0644,
298 		.err = EISDIR,
299 	},
300 	{	/* open dir O_RDONLY | O_CREAT */
301 		.desc = "Open dir O_RDONLY | O_CREAT, expect EISDIR",
302 		.path = T_DIR,
303 		.flags = O_RDONLY | O_CREAT,
304 		.mode = 0644,
305 		.err = EISDIR,
306 	},
307 	/*
308 	 * Other random open(2) tests
309 	 */
310 	{	/* open regular file O_RDONLY | O_TRUNC */
311 		.desc = "Open regular file O_RDONLY | O_TRUNC, "
312 			"behaviour is undefined but should not oops or hang",
313 		.path = T_REG_EMPTY,
314 		.flags = O_RDONLY | O_TRUNC,
315 		.mode = 0644,
316 		.err = -1,
317 	},
318 	{	/* open regular(non-empty) file O_RDONLY | O_TRUNC */
319 		.desc = "Open regular file(non-empty) O_RDONLY | O_TRUNC, "
320 			"behaviour is undefined but should not oops or hang",
321 		.path = T_REG,
322 		.flags = O_RDONLY | O_TRUNC,
323 		.mode = 0644,
324 		.err = -1,
325 	},
326 };
327 
328 int TST_TOTAL = sizeof(tc) / sizeof(tc[0]);
329 
330 int main(int argc, char *argv[])
331 {
332 	int lc;
333 	int i;
334 	int fd;
335 	int ret;
336 
337 	tst_parse_opts(argc, argv, NULL, NULL);
338 
339 	setup();
340 
341 	for (lc = 0; TEST_LOOPING(lc); lc++) {
342 		for (i = 0; i < TST_TOTAL; i++) {
343 			TEST(open(tc[i].path, tc[i].flags, tc[i].mode));
344 			fd = TEST_RETURN;
345 
346 			if (tc[i].err == -1 || TEST_ERRNO == tc[i].err) {
347 				tst_resm(TPASS, "%s", tc[i].desc);
348 			} else {
349 				tst_resm(TFAIL | TTERRNO,
350 					 "%s - expected errno %d - Got",
351 					 tc[i].desc, tc[i].err);
352 			}
353 			if (fd > 0) {
354 				ret = close(fd);
355 				if (ret < 0)
356 					tst_resm(TWARN, "%s - close failed: %s",
357 						 tc[i].desc, strerror(errno));
358 			}
359 		}
360 	}
361 
362 	cleanup();
363 	tst_exit();
364 }
365 
366 static void setup(void)
367 {
368 	int fd;
369 	int ret;
370 
371 	tst_require_root();
372 
373 	tst_tmpdir();
374 
375 	/* Create test files */
376 	fd = SAFE_OPEN(cleanup, T_REG, O_WRONLY | O_CREAT, 0644);
377 	ret = write(fd, T_MSG, sizeof(T_MSG));
378 	if (ret == -1) {
379 		close(fd);
380 		tst_brkm(TBROK | TERRNO, cleanup, "Write %s failed", T_REG);
381 	}
382 	close(fd);
383 
384 	fd = SAFE_CREAT(cleanup, T_REG_EMPTY, 0644);
385 	close(fd);
386 
387 	SAFE_LINK(cleanup, T_REG, T_LINK_REG);
388 	SAFE_SYMLINK(cleanup, T_REG, T_SYMLINK_REG);
389 	SAFE_MKDIR(cleanup, T_DIR, 0755);
390 	SAFE_SYMLINK(cleanup, T_DIR, T_SYMLINK_DIR);
391 
392 	ret = mknod(T_DEV, S_IFCHR, makedev(1, 5));
393 	if (ret == -1)
394 		tst_brkm(TBROK | TERRNO, cleanup, "Create char dev %s failed",
395 			 T_DEV);
396 
397 	TEST_PAUSE;
398 }
399 
400 static void cleanup(void)
401 {
402 	tst_rmdir();
403 }
404