1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  *	07/2001 Ported by Wayne Boyer
4  *
5  * This program is free software;  you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  * the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program;  if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 /*
20  * DESCRIPTION
21  *	test 1:
22  *	Read with an invalid file descriptor, and expect an EBADF.
23  *
24  *	test 2:
25  *	The parameter passed to read is a directory, check if the errno is
26  *	set to EISDIR.
27  *
28  *	test 3:
29  *	Buf is outside the accessible address space, expect an EFAULT.
30  *
31  *	test 4:
32  *	The file was opened with the O_DIRECT flag, and transfer sizes was not
33  *	multiples of the logical block size of the file system, expect an
34  *	EINVAL.
35  *
36  *	test 5:
37  *	The file was opened with the O_DIRECT flag, and the alignment of the
38  *	user buffer was not multiples of the logical block size of the file
39  *	system, expect an EINVAL.
40  */
41 
42 #define _GNU_SOURCE
43 
44 #include <stdio.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <sys/mman.h>
49 #include "test.h"
50 #include "safe_macros.h"
51 
52 char *TCID = "read02";
53 
54 static int badfd = -1;
55 static int fd2, fd3, fd4 = -1;
56 static char buf[BUFSIZ];
57 static void *outside_buf = (void *)-1;
58 static void *addr4;
59 static void *addr5;
60 
61 static long fs_type;
62 
63 static struct test_case_t {
64 	int *fd;
65 	void **buf;
66 	size_t count;
67 	int exp_error;
68 } TC[] = {
69 	{&badfd, (void **)&buf, 1, EBADF},
70 	{&fd2, (void **)&buf, 1, EISDIR},
71 #ifndef UCLINUX
72 	{&fd3, &outside_buf, 1, EFAULT},
73 #endif
74 	{&fd4, &addr4, 1, EINVAL},
75 	{&fd4, &addr5, 4096, EINVAL},
76 };
77 
78 int TST_TOTAL = ARRAY_SIZE(TC);
79 static void setup(void);
80 static void cleanup(void);
81 static void read_verify(const struct test_case_t *);
82 
main(int ac,char ** av)83 int main(int ac, char **av)
84 {
85 	int i;
86 	int lc;
87 
88 	tst_parse_opts(ac, av, NULL, NULL);
89 
90 	setup();
91 
92 	for (lc = 0; TEST_LOOPING(lc); lc++) {
93 		tst_count = 0;
94 		for (i = 0; i < TST_TOTAL; i++)
95 			read_verify(&TC[i]);
96 	}
97 	cleanup();
98 	tst_exit();
99 }
100 
setup(void)101 static void setup(void)
102 {
103 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
104 
105 	TEST_PAUSE;
106 
107 	tst_tmpdir();
108 
109 	fd2 = SAFE_OPEN(cleanup, ".", O_DIRECTORY);
110 
111 	SAFE_FILE_PRINTF(cleanup, "test_file", "A");
112 
113 	fd3 = SAFE_OPEN(cleanup, "test_file", O_RDWR);
114 
115 #if !defined(UCLINUX)
116 	outside_buf = SAFE_MMAP(cleanup, 0, 1, PROT_NONE,
117 				MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
118 #endif
119 
120 	addr4 = SAFE_MEMALIGN(cleanup, getpagesize(), (4096 * 10));
121 	addr5 = addr4 + 1;
122 
123 	fs_type = tst_fs_type(cleanup, ".");
124 	if (fs_type != TST_TMPFS_MAGIC)
125 		fd4 = SAFE_OPEN(cleanup, "test_file", O_RDWR | O_DIRECT);
126 }
127 
read_verify(const struct test_case_t * test)128 static void read_verify(const struct test_case_t *test)
129 {
130 	if (test->fd == &fd4 && *test->fd == -1) {
131 		tst_resm(TCONF, "O_DIRECT not supported on %s filesystem",
132 		         tst_fs_type_name(fs_type));
133 		return;
134 	}
135 
136 	TEST(read(*test->fd, *test->buf, test->count));
137 
138 	if (*test->fd == fd4 && TEST_RETURN >= 0) {
139 		tst_resm(TPASS,
140 			 "O_DIRECT unaligned reads fallbacks to buffered I/O");
141 		return;
142 	}
143 
144 	if (TEST_RETURN != -1) {
145 		tst_resm(TFAIL, "call succeeded unexpectedly");
146 		return;
147 	}
148 
149 	if (TEST_ERRNO == test->exp_error) {
150 		tst_resm(TPASS | TTERRNO, "expected failure");
151 	} else {
152 		tst_resm(TFAIL | TTERRNO, "unexpected error expected %d",
153 			 test->exp_error);
154 	}
155 }
156 
cleanup(void)157 static void cleanup(void)
158 {
159 	free(addr4);
160 
161 	if (fd4 > 0)
162 		close(fd4);
163 
164 	if (fd3 > 0)
165 		close(fd3);
166 
167 	if (fd2 > 0)
168 		close(fd2);
169 
170 	tst_rmdir();
171 }
172