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
52char *TCID = "read02";
53
54static int badfd = -1;
55static int fd2, fd3, fd4 = -1;
56static char buf[BUFSIZ];
57static void *outside_buf = (void *)-1;
58static void *addr4;
59static void *addr5;
60
61static long fs_type;
62
63static 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
78int TST_TOTAL = ARRAY_SIZE(TC);
79static void setup(void);
80static void cleanup(void);
81static void read_verify(const struct test_case_t *);
82
83int 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
101static 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
128static 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
157static 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