1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2001
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/*
21 * NAME
22 * 	readv02.c
23 *
24 * DESCRIPTION
25 *	Testcase to check the error conditions of the readv(2) system call.
26 *
27 * CALLS
28 * 	readv()
29 *
30 * ALGORITHM
31 *	Create a IO vector, and attempt to readv() various components of it.
32 *
33 * USAGE
34 *	readv02
35 *
36 * HISTORY
37 *	07/2001 Ported by Wayne Boyer
38 *
39 * RESTRICTIONS
40 * 	None
41 */
42#include <sys/types.h>
43#include <sys/uio.h>
44#include <sys/fcntl.h>
45#include <sys/mman.h>
46#include <memory.h>
47#include <errno.h>
48
49#include "test.h"
50
51#define	K_1	1024
52#define	M_1	K_1 * K_1
53#define	G_1	M_1 * K_1
54
55#define	NBUFS		4
56#define	CHUNK		64
57#define	MAX_IOVEC	16
58#define DATA_FILE	"readv_data_file"
59
60char buf1[K_1], buf2[K_1], buf3[K_1];
61
62struct iovec rd_iovec[MAX_IOVEC] = {
63	/* iov_base *//* iov_len */
64
65	/* Test case #1 */
66	{buf2, -1},
67	{(buf2 + CHUNK), CHUNK},
68	{(buf2 + CHUNK * 2), CHUNK},
69
70	/* Test case #2 */
71	{(buf2 + CHUNK * 3), G_1},
72	{(buf2 + CHUNK * 4), G_1},
73	{(buf2 + CHUNK * 5), G_1},
74
75	/* Test case #3 */
76	{(caddr_t) - 1, CHUNK},
77	{(buf2 + CHUNK * 6), CHUNK},
78	{(buf2 + CHUNK * 8), CHUNK},
79
80	/* Test case #4 */
81	{(buf2 + CHUNK * 9), CHUNK}
82};
83
84char f_name[K_1];
85
86int fd[4];
87char *buf_list[NBUFS];
88
89char *TCID = "readv02";
90int TST_TOTAL = 1;
91
92char *bad_addr = 0;
93
94int init_buffs(char **);
95int fill_mem(char *, int, int);
96long l_seek(int, long, int);
97char *getenv();
98void setup();
99void cleanup();
100
101int main(int ac, char **av)
102{
103	int lc;
104
105	tst_parse_opts(ac, av, NULL, NULL);
106
107	setup();
108
109	/* The following loop checks looping state if -i option given */
110	for (lc = 0; TEST_LOOPING(lc); lc++) {
111
112		/* reset tst_count in case we are looping */
113		tst_count = 0;
114
115//test1:
116		if (readv(fd[0], rd_iovec, 1) < 0) {
117			if (errno != EINVAL) {
118				tst_resm(TFAIL, "readv() set an illegal errno:"
119					 " expected: EINVAL, got %d", errno);
120			} else {
121				tst_resm(TPASS, "got EINVAL");
122			}
123		} else {
124			tst_resm(TFAIL, "Error: readv returned a positive "
125				 "value");
126		}
127
128//test2:
129		l_seek(fd[0], CHUNK * 6, 0);
130		if (readv(fd[0], (rd_iovec + 6), 3) < 0) {
131			if (errno != EFAULT) {
132				tst_resm(TFAIL, "expected errno = EFAULT, "
133					 "got %d", errno);
134			} else {
135				tst_resm(TPASS, "got EFAULT");
136			}
137			if (memcmp((buf_list[0] + CHUNK * 6),
138				   (buf_list[1] + CHUNK * 6), CHUNK * 3) != 0) {
139				tst_resm(TFAIL, "Error: readv() partially "
140					 "overlaid buf[2]");
141			}
142		} else {
143			tst_resm(TFAIL, "Error: readv returned a positive "
144				 "value");
145		}
146
147//test3:
148		if (readv(fd[1], (rd_iovec + 9), 1) < 0) {
149			if (errno != EBADF) {
150				tst_resm(TFAIL, "expected errno = EBADF, "
151					 "got %d", errno);
152			} else {
153				tst_resm(TPASS, "got EBADF");
154			}
155		} else {
156			tst_resm(TFAIL, "Error: readv returned a positive "
157				 "value");
158		}
159
160//test4:
161		l_seek(fd[0], CHUNK * 10, 0);
162		if (readv(fd[0], (rd_iovec + 10), -1) < 0) {
163			if (errno != EINVAL) {
164				tst_resm(TFAIL, "expected errno = EINVAL, "
165					 "got %d", errno);
166			} else {
167				tst_resm(TPASS, "got EINVAL");
168			}
169		} else {
170			tst_resm(TFAIL, "Error: readv returned a positive "
171				 "value");
172		}
173
174	}
175	close(fd[0]);
176	close(fd[1]);
177	cleanup();
178	tst_exit();
179
180}
181
182/*
183 * setup() - performs all ONE TIME setup for this test.
184 */
185void setup(void)
186{
187	int nbytes;
188
189	tst_sig(NOFORK, DEF_HANDLER, cleanup);
190
191	TEST_PAUSE;
192
193	/* make a temporary directory and cd to it */
194	tst_tmpdir();
195
196	buf_list[0] = buf1;
197	buf_list[1] = buf2;
198	buf_list[2] = buf3;
199	buf_list[3] = NULL;
200
201	init_buffs(buf_list);
202
203	sprintf(f_name, "%s.%d", DATA_FILE, getpid());
204
205	if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
206		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
207			 "errno = %d", f_name, errno);
208	} else {
209		if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
210			tst_brkm(TBROK, cleanup, "write failed: nbytes "
211				 "= %d " "errno = %d", nbytes, errno);
212		}
213	}
214
215	if (close(fd[0]) < 0) {
216		tst_brkm(TBROK, cleanup, "close failed: errno = %d", errno);
217	}
218
219	if ((fd[0] = open(f_name, O_RDONLY, 0666)) < 0) {
220		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
221			 "errno = %d", f_name, errno);
222	}
223
224	fd[1] = -1;		/* Invalid file descriptor */
225
226	bad_addr = mmap(0, 1, PROT_NONE,
227			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
228	if (bad_addr == MAP_FAILED) {
229		tst_brkm(TBROK, cleanup, "mmap failed");
230	}
231	rd_iovec[6].iov_base = bad_addr;
232}
233
234/*
235 * cleanup() - performs all ONE TIME cleanup for this test at
236 *	       completion or premature exit.
237 */
238void cleanup(void)
239{
240	if (unlink(f_name) < 0) {
241		tst_brkm(TBROK, NULL, "unlink FAILED: file %s, errno %d",
242			 f_name, errno);
243	}
244	tst_rmdir();
245
246}
247
248int init_buffs(char *pbufs[])
249{
250	int i;
251
252	for (i = 0; pbufs[i] != NULL; i++) {
253		switch (i) {
254		case 0:
255		 /*FALLTHROUGH*/ case 1:
256			fill_mem(pbufs[i], 0, 1);
257			break;
258
259		case 2:
260			fill_mem(pbufs[i], 1, 0);
261			break;
262
263		default:
264			tst_brkm(TBROK, cleanup, "Error in init_buffs()");
265		}
266	}
267	return 0;
268}
269
270int fill_mem(char *c_ptr, int c1, int c2)
271{
272	int count;
273
274	for (count = 1; count <= K_1 / CHUNK; count++) {
275		if (count & 0x01) {	/* if odd */
276			memset(c_ptr, c1, CHUNK);
277		} else {	/* if even */
278			memset(c_ptr, c2, CHUNK);
279		}
280	}
281	return 0;
282}
283
284long l_seek(int fdesc, long offset, int whence)
285{
286	if (lseek(fdesc, offset, whence) < 0) {
287		tst_brkm(TBROK, cleanup, "lseek Failed : errno = %d", errno);
288	}
289	return 0;
290}
291