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 * writev04.c
23 *
24 * DESCRIPTION
25 * The testcases are written calling writev() with partially valid data
26 * to overwrite the contents, to write in the beginning and to write in
27 * the end of the file. This is same as writev03.c, but the length of
28 * buffer used here is 8192 bytes.
29 *
30 * USAGE: <for command-line>
31 * writev04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
32 * where, -c n : Run n copies concurrently.
33 * -e : Turn on errno logging.
34 * -i n : Execute test n times.
35 * -I x : Execute test for x seconds.
36 * -P x : Pause for x seconds between iterations.
37 * -t : Turn on syscall timing.
38 *
39 * History
40 * 07/2001 John George
41 * -Ported
42 * 04/2002 wjhuie sigset cleanups
43 *
44 * Restrictions
45 * NONE
46 */
47 #include <sys/types.h>
48 #include <sys/uio.h>
49 #include <sys/mman.h>
50 #include <unistd.h>
51 #include <signal.h>
52 #include <fcntl.h>
53 #include <memory.h>
54 #include <errno.h>
55 #include "test.h"
56
57 #define K_1 8192
58
59 #define NBUFS 4
60 #define CHUNK 64 /* single chunk */
61 #define MAX_IOVEC 4
62 #define DATA_FILE "writev_data_file"
63
64 char buf1[K_1], buf2[K_1], buf3[K_1];
65 char *bad_addr = 0;
66
67 struct iovec wr_iovec[MAX_IOVEC] = {
68 /* testcase #1 */
69 {buf1 + (CHUNK * 6), CHUNK},
70 {(caddr_t) - 1, CHUNK},
71 {buf1 + (CHUNK * 8), CHUNK},
72 {NULL, 0}
73 };
74
75 char name[K_1], f_name[K_1];
76 int fd[2], in_sighandler;
77 char *buf_list[NBUFS];
78
79 char *TCID = "writev04";
80 int TST_TOTAL = 1;
81
82 void sighandler(int);
83 long l_seek(int, long, int);
84 void setup(void);
85 void cleanup(void);
86 int fail;
87
88 #if !defined(UCLINUX)
89
main(int argc,char ** argv)90 int main(int argc, char **argv)
91 {
92 int lc;
93
94 int nbytes;
95
96 tst_parse_opts(argc, argv, NULL, NULL);
97
98 setup(); /* set "tstdir", and "testfile" vars */
99
100 /* The following loop checks looping state if -i option given */
101 for (lc = 0; TEST_LOOPING(lc); lc++) {
102
103 /* reset tst_count in case we are looping */
104 tst_count = 0;
105
106 buf_list[0] = buf1;
107 buf_list[1] = buf2;
108 buf_list[2] = buf3;
109 buf_list[3] = NULL;
110
111 fd[1] = -1; /* Invalid file descriptor */
112
113 if (signal(SIGTERM, sighandler) == SIG_ERR) {
114 perror("signal");
115 tst_resm(TFAIL, "signal() SIGTERM FAILED");
116 cleanup();
117 }
118
119 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
120 perror("signal");
121 tst_resm(TFAIL, "signal() SIGPIPE FAILED");
122 cleanup();
123 }
124
125 memset(buf_list[0], 0, K_1);
126 memset(buf_list[1], 0, K_1);
127
128 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
129 tst_resm(TFAIL, "open(2) failed: fname = %s, "
130 "errno = %d", f_name, errno);
131 cleanup();
132 } else {
133 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) {
134 tst_resm(TFAIL, "write(2) failed: nbytes "
135 "= %d, errno = %d", nbytes, errno);
136 cleanup();
137 }
138 }
139
140 if (close(fd[0]) < 0) {
141 tst_resm(TFAIL, "close failed: errno = %d", errno);
142 cleanup();
143 }
144
145 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
146 tst_brkm(TFAIL, cleanup, "open failed: fname = %s, errno = %d",
147 f_name, errno);
148 }
149 //block1:
150 tst_resm(TINFO, "Enter block 1");
151 fail = 0;
152
153 /*
154 * In this block we are trying to call writev() with
155 * partially valid data. This should return the valid number
156 * of bytes written in the vector. If it returns EFAULT, it
157 * is an error. And after returning the number of valid
158 * bytes written, the check should be made to verify the
159 * contents of the first valid write() scheduled.
160 */
161 if (writev(fd[0], wr_iovec, 3) < 0) {
162 fail = 1;
163 if (errno == EFAULT) {
164 tst_resm(TFAIL, "Got error EFAULT");
165 } else {
166 tst_resm(TFAIL, "Received unexpected error: %d",
167 errno);
168 }
169 } else {
170 l_seek(fd[0], 0, 0);
171 read(fd[0], buf_list[0], CHUNK);
172 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
173 tst_resm(TFAIL, "writev overwrote the file");
174 fail = 1;
175 }
176 }
177
178 if (fail) {
179 tst_resm(TINFO, "block 1 FAILED");
180 } else {
181 tst_resm(TINFO, "block 1 PASSED");
182 }
183 tst_resm(TINFO, "Exit block 1");
184
185 //block2:
186 tst_resm(TINFO, "Enter block 2");
187 fail = 0;
188
189 /*
190 * In this block we are trying to over write the contents by
191 * calling writev() with partially valid data. It should
192 * return the valid number of bytes written but not EFAULT.
193 * Also the check should be made whether the initial write()
194 * scheduled is done correctly or not.
195 */
196 l_seek(fd[0], 0, 0);
197 if (writev(fd[0], wr_iovec, 3) < 0) {
198 fail = 1;
199 if (errno == EFAULT) {
200 tst_resm(TFAIL, "Got error EFAULT");
201 } else {
202 tst_resm(TFAIL, "Received unexpected error: %d",
203 errno);
204 }
205 } else {
206 l_seek(fd[0], 0, 0);
207 read(fd[0], buf_list[0], CHUNK);
208 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
209 tst_resm(TFAIL, "writev overwrote the file");
210 fail = 1;
211 }
212 }
213
214 if (fail) {
215 tst_resm(TINFO, "block 2 FAILED");
216 } else {
217 tst_resm(TINFO, "block 2 PASSED");
218 }
219 tst_resm(TINFO, "Exit block 2");
220
221 //block3:
222 tst_resm(TINFO, "Enter block 3");
223 fail = 0;
224
225 /*
226 * In this block, we are trying to call writev() by going to
227 * some end position of the file. Here writev() is called
228 * with partially valid data, and this will return the
229 * number of valid bytes written and not EFAULT. Also, the
230 * check should be made whether the inital write() that is
231 * scheduled with valid data is done correctly.
232 */
233
234 l_seek(fd[0], 8192, 0);
235 if (writev(fd[0], wr_iovec, 3) < 0) {
236 fail = 1;
237 if (errno == EFAULT) {
238 tst_resm(TFAIL, "Got error EFAULT");
239 } else {
240 tst_resm(TFAIL, "Received unexpected error: %d",
241 errno);
242 }
243 } else {
244 l_seek(fd[0], 0, 0);
245 read(fd[0], buf_list[0], CHUNK);
246 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
247 tst_resm(TFAIL, "writev overwrote the file");
248 fail = 1;
249 }
250 }
251
252 if (fail) {
253 tst_resm(TINFO, "block 3 FAILED");
254 } else {
255 tst_resm(TINFO, "block 3 PASSED");
256 }
257 tst_resm(TINFO, "Exit block 3");
258 }
259 close(fd[0]);
260 close(fd[1]);
261 cleanup();
262 tst_exit();
263 }
264
265 #else
266
main(void)267 int main(void)
268 {
269 tst_resm(TINFO, "test is not available on uClinux");
270 tst_exit();
271 }
272
273 #endif /* if !defined(UCLINUX) */
274
275 /*
276 * setup()
277 * performs all ONE TIME setup for this test
278 */
setup(void)279 void setup(void)
280 {
281
282 tst_sig(FORK, DEF_HANDLER, cleanup);
283
284 TEST_PAUSE;
285
286 /* Create a unique temporary directory and chdir() to it. */
287 tst_tmpdir();
288
289 strcpy(name, DATA_FILE);
290 sprintf(f_name, "%s.%d", name, getpid());
291
292 bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
293 if (bad_addr == MAP_FAILED) {
294 tst_brkm(TBROK, cleanup, "mmap failed");
295 }
296 wr_iovec[1].iov_base = bad_addr;
297
298 }
299
300 /*
301 * cleanup()
302 * performs all ONE TIME cleanup for this test at
303 * completion or premature exit
304 */
cleanup(void)305 void cleanup(void)
306 {
307
308 if (unlink(f_name) < 0) {
309 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
310 f_name, errno);
311 }
312 tst_rmdir();
313
314 }
315
316 /*
317 * sighandler()
318 * Signal handler function for SIGTERM and SIGPIPE
319 */
sighandler(int sig)320 void sighandler(int sig)
321 {
322 switch (sig) {
323 case SIGTERM:
324 break;
325 case SIGPIPE:
326 ++in_sighandler;
327 return;
328 default:
329 tst_resm(TFAIL, "sighandler() received invalid signal "
330 ": %d", sig);
331 break;
332 }
333
334 if ((unlink(f_name) < 0) && (errno != ENOENT)) {
335 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
336 f_name, errno);
337 cleanup();
338 }
339 exit(sig);
340 }
341
342 /*
343 * l_seek()
344 * Wrap around for regular lseek function for giving error message
345 */
l_seek(int fdesc,long offset,int whence)346 long l_seek(int fdesc, long offset, int whence)
347 {
348 if (lseek(fdesc, offset, whence) < 0) {
349 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
350 fail = 1;
351 }
352 return 0;
353 }
354