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 * writev05.c
23 *
24 * DESCRIPTION
25 * These testcases are written to test writev() on sparse files. This
26 * is same as writev02.c. But the initial write() with valid data is
27 * done at the beginning of the file.
28 *
29 * USAGE: <for command-line>
30 * writev05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
31 * where, -c n : Run n copies concurrently.
32 * -e : Turn on errno logging.
33 * -i n : Execute test n times.
34 * -I x : Execute test for x seconds.
35 * -P x : Pause for x seconds between iterations.
36 * -t : Turn on syscall timing.
37 *
38 * History
39 * 07/2001 John George
40 * -Ported
41 * 04/2002 wjhuie sigset cleanups
42 *
43 * Restrictions
44 * NONE
45 */
46
47 #include <sys/types.h>
48 #include <signal.h>
49 #include <sys/uio.h>
50 #include <fcntl.h>
51 #include <memory.h>
52 #include <errno.h>
53 #include "test.h"
54 #include <sys/mman.h>
55
56 #define K_1 8192
57
58 #define NBUFS 2
59 #define CHUNK K_1 /* single chunk */
60 #define MAX_IOVEC 2
61 #define DATA_FILE "writev_data_file"
62
63 char buf1[K_1];
64 char buf2[K_1];
65 char buf3[K_1];
66
67 char *bad_addr = 0;
68
69 struct iovec wr_iovec[MAX_IOVEC] = {
70 {(caddr_t) - 1, CHUNK},
71 {NULL, 0}
72 };
73
74 char name[K_1], f_name[K_1];
75 int fd[2], in_sighandler;
76 char *buf_list[NBUFS];
77
78 char *TCID = "writev05";
79 int TST_TOTAL = 1;
80
81 void sighandler(int);
82 long l_seek(int, long, int);
83 void setup(void);
84 void cleanup(void);
85 int fail;
86
87 #if !defined(UCLINUX)
88
main(int argc,char ** argv)89 int main(int argc, char **argv)
90 {
91 int lc;
92
93 int nbytes;
94
95 tst_parse_opts(argc, argv, NULL, NULL);
96
97 setup(); /* set "tstdir", and "testfile" vars */
98
99 /* The following loop checks looping state if -i option given */
100 for (lc = 0; TEST_LOOPING(lc); lc++) {
101
102 /* reset tst_count in case we are looping */
103 tst_count = 0;
104
105 buf_list[0] = buf1;
106 buf_list[1] = buf2;
107
108 fd[1] = -1; /* Invalid file descriptor */
109
110 if (signal(SIGTERM, sighandler) == SIG_ERR) {
111 perror("signal");
112 tst_resm(TFAIL, "signal() SIGTERM FAILED");
113 cleanup();
114 }
115
116 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
117 perror("signal");
118 tst_resm(TFAIL, "signal() SIGPIPE FAILED");
119 cleanup();
120 }
121
122 /* Fill the buf_list[0] and buf_list[1] with 0 zeros */
123 memset(buf_list[0], 0, K_1);
124 memset(buf_list[1], 0, K_1);
125
126 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
127 tst_resm(TFAIL, "open(2) failed: fname = %s, "
128 "errno = %d", f_name, errno);
129 cleanup();
130 } else {
131 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) {
132 tst_resm(TFAIL, "write(2) failed: nbytes "
133 "= %d, errno = %d", nbytes, errno);
134 cleanup();
135 }
136 }
137
138 if (close(fd[0]) < 0) {
139 tst_resm(TFAIL, "close failed: errno = %d", errno);
140 cleanup();
141 }
142
143 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
144 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
145 f_name, errno);
146 cleanup();
147 }
148
149 /*
150 * In this block we are trying to call writev() with invalid
151 * vector to be written in a sparse file. This will return
152 * EFAULT. At the same time, check should be made whether
153 * the scheduled write() with valid data is done correctly
154 * or not.
155 */
156 //block1:
157 tst_resm(TINFO, "Enter block 1");
158 fail = 0;
159
160 l_seek(fd[0], 0, 0);
161 TEST(writev(fd[0], wr_iovec, 2));
162 if (TEST_RETURN < 0) {
163 if (TEST_ERRNO == EFAULT) {
164 tst_resm(TINFO, "Received EFAULT as expected");
165 } else {
166 tst_resm(TFAIL, "Expected EFAULT, got %d",
167 TEST_ERRNO);
168 fail = 1;
169 }
170 l_seek(fd[0], K_1, 0);
171 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 0) {
172 tst_resm(TFAIL, "Expected nbytes = 0, got "
173 "%d", nbytes);
174 fail = 1;
175 }
176 } else {
177 tst_resm(TFAIL, "Error writev returned a positive "
178 "value");
179 fail = 1;
180 }
181 if (fail) {
182 tst_resm(TINFO, "block 1 FAILED");
183 } else {
184 tst_resm(TINFO, "block 1 PASSED");
185 }
186 tst_resm(TINFO, "Exit block 1");
187 }
188 close(fd[0]);
189 close(fd[1]);
190 cleanup();
191 tst_exit();
192
193 }
194
195 #else
196
main(void)197 int main(void)
198 {
199 tst_resm(TINFO, "test is not available on uClinux");
200 tst_exit();
201 }
202
203 #endif /* if !defined(UCLINUX) */
204
205 /*
206 * setup()
207 * performs all ONE TIME setup for this test
208 */
setup(void)209 void setup(void)
210 {
211
212 tst_sig(FORK, DEF_HANDLER, cleanup);
213
214 /* Pause if that option was specified.
215 * TEST_PAUSE contains the code to fork the test with the -i option.
216 * You want to make sure you do this before you create your temporary
217 * directory.
218 */
219 TEST_PAUSE;
220
221 /* Create a unique temporary directory and chdir() to it. */
222 tst_tmpdir();
223
224 strcpy(name, DATA_FILE);
225 sprintf(f_name, "%s.%d", name, getpid());
226
227 bad_addr = mmap(0, 1, PROT_NONE,
228 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
229 if (bad_addr == MAP_FAILED) {
230 printf("mmap failed\n");
231 }
232 wr_iovec[0].iov_base = bad_addr;
233
234 }
235
236 /*
237 * cleanup()
238 * performs all ONE TIME cleanup for this test at
239 * completion or premature exit
240 */
cleanup(void)241 void cleanup(void)
242 {
243
244 if (unlink(f_name) < 0) {
245 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
246 f_name, errno);
247 }
248 tst_rmdir();
249
250 }
251
252 /*
253 * sighandler()
254 * Signal handler for SIGTERM and SIGPIPE
255 */
sighandler(int sig)256 void sighandler(int sig)
257 {
258 switch (sig) {
259 case SIGTERM:
260 break;
261 case SIGPIPE:
262 ++in_sighandler;
263 return;
264 default:
265 tst_resm(TFAIL, "sighandler() received invalid signal "
266 ": %d", sig);
267 break;
268 }
269
270 if ((unlink(f_name) < 0) && (errno != ENOENT)) {
271 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
272 f_name, errno);
273 cleanup();
274 }
275 exit(sig);
276 }
277
278 /*
279 * l_seek()
280 * Wrap around for regular lseek() to give error message on failure
281 */
l_seek(int fdesc,long offset,int whence)282 long l_seek(int fdesc, long offset, int whence)
283 {
284 if (lseek(fdesc, offset, whence) < 0) {
285 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
286 fail = 1;
287 }
288 return 0;
289 }
290