blob: d8df759c982d009886921c5e6f5866bccaa1b94c [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 * writev01.c
23 *
24 * DESCRIPTION
25 * Testcase to check the basic functionality of writev(2) system call.
26 *
27 * ALGORITHM
28 * Create a IO vector, and attempt to writev() various components of it.
29 *
30 * USAGE: <for command-line>
31 * writev01 [-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 *
43 * Restrictions
44 * None
45 */
46
47#include <stdio.h>
48#include <sys/types.h>
49#include <signal.h>
50#include <sys/uio.h>
51#include <sys/fcntl.h>
52#include <memory.h>
53#include <errno.h>
54#include <test.h>
55#include <usctest.h>
56
57#define K_1 1024
58#define M_1 K_1 * K_1
59#define G_1 M_1 * K_1
60
61#define NBUFS 4
62#define CHUNK 64 /* single chunk */
63#define MAX_IOVEC 16
64#define DATA_FILE "writev_data_file"
65
66char buf1[K_1], buf2[K_1], buf3[K_1];
67
68struct iovec wr_iovec[MAX_IOVEC] = {
69 /* iov_base */ /* iov_len */
70
71 /* testcase# 1 */
72 buf1, -1,
73 (buf1 + CHUNK), CHUNK,
74 (buf1 + CHUNK * 2), CHUNK,
75
76 /* testcase# 2 */
77 (buf1 + CHUNK * 3), G_1,
78 (buf1 + CHUNK * 4), G_1,
79 (buf1 + CHUNK * 5), G_1,
80
81 /* testcase# 3 */
82 (buf1 + CHUNK * 6), CHUNK,
83 (caddr_t)-1, CHUNK,
84 (buf1 + CHUNK * 8), CHUNK,
85
86 /* testcase# 4 */
87 (buf1 + CHUNK * 9), CHUNK,
88
89 /* testcase# 5 */
90 (buf1 + CHUNK * 10), CHUNK,
91
92 /* testcase# 6 */
93 (buf1 + CHUNK * 11), CHUNK,
94
95 /* testcase# 7 */
96 (buf1 + CHUNK * 12), CHUNK,
97
98 /* testcase# 8 */
99 (buf1 + CHUNK * 13), 0,
100
101 /* testcase# 9 */
102 (caddr_t)NULL, 0,
103
104 /* testcase# 10 */
105 (caddr_t)NULL, 0,
106};
107
108char name[K_1], f_name[K_1];
109
110/* 0 terminated list of expected errnos */
111int exp_enos[] = {14, 22, 32, 77, 0};
112
113int fd[4], in_sighandler;
114int pfd[2]; /* pipe fd's */
115char *buf_list[NBUFS];
116int fail;
117
118void sighandler(int);
119long l_seek(int, long, int);
120int fill_mem(char *, int, int);
121int init_buffs(char *[]);
122void setup(void);
123void cleanup(void);
124
125char *TCID = "writev01";
126int TST_TOTAL = 1;
127extern int Tst_count;
128
129main(int argc, char **argv)
130{
131 int nbytes, ret;
132
133 int lc; /* loop counter */
134 char *msg; /* message returned from parse_opts */
135
136 /* parse standard options */
137 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
138 (char *) NULL) {
139 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
140 /*NOTREACHED*/
141 }
142
143 /* set "tstdir", and "testfile" vars */
144 setup();
145
146 /* The following loop checks looping state if -i option given */
147 for (lc = 0; TEST_LOOPING(lc); lc++) {
148
149
150 /* reset Tst_count in case we are looping */
151 Tst_count = 0;
152
153 buf_list[0] = buf1;
154 buf_list[1] = buf2;
155 buf_list[2] = buf3;
156 buf_list[3] = (char *)NULL;
157
158 fd[1] = -1; /* Invalid file descriptor */
159
160 if (sigset(SIGTERM, sighandler) == -1) {
161 perror("sigset: SIGTERM");
162 cleanup();
163 /*NOTREACHED*/
164 }
165
166 if (sigset(SIGPIPE, sighandler) == -1) {
167 perror("sigset: SIGPIPE");
168 cleanup();
169 /*NOTREACHED*/
170 }
171
172 init_buffs(buf_list);
173
174 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
175 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
176 f_name, errno);
177 cleanup();
178 /*NOTREACHED*/
179 } else if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
180 tst_resm(TFAIL, "write failed: nbytes = %d, "
181 "errno = %d", nbytes, errno);
182 cleanup();
183 /*NOTREACHED*/
184 }
185
186 if (close(fd[0]) < 0) {
187 tst_resm(TFAIL, "close failed: errno: %d", errno);
188 cleanup();
189 /*NOTREACHED*/
190 }
191
192 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
193 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
194 f_name, errno);
195 cleanup();
196 /*NOTREACHED*/
197 }
198
199block1:
200 tst_resm(TINFO, "Enter Block 1");
201 fail = 0;
202
203 TEST(writev(fd[0], wr_iovec, 1));
204 if (TEST_RETURN < 0) {
205 TEST_ERROR_LOG(TEST_ERRNO);
206 if (TEST_ERRNO == EINVAL) {
207 tst_resm(TINFO, "Received EINVAL as expected");
208 } else {
209 tst_resm(TFAIL, "Expected errno = EINVAL, "
210 "got %d", TEST_ERRNO);
211 fail = 1;
212 }
213 } else {
214 tst_resm(TFAIL, "writev() failed to fail");
215 fail = 1;
216 }
217 if (fail) {
218 tst_resm(TINFO, "block 1 FAILED");
219 } else {
220 tst_resm(TINFO, "block 1 PASSED");
221 }
222 tst_resm(TINFO, "Exit block 1");
223
224block2:
225 tst_resm(TINFO, "Enter block 2");
226 fail = 0;
227
228 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
229 TEST_ERROR_LOG(errno);
230 tst_resm(TBROK, "block2: 1st lseek failed");
231 fail = 1;
232 }
233
234 if ((ret = writev(fd[0], (wr_iovec + 6), 3)) == CHUNK) {
235 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
236 TEST_ERROR_LOG(errno);
237 tst_resm(TFAIL, "block2: 2nd lseek failed");
238 fail = 1;
239 }
240 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) !=
241 CHUNK) {
242 perror("read error");
243 tst_resm(TFAIL, "expected nbytes = 1024, "
244 "got = %d", nbytes);
245 fail = 1;
246 } else if (memcmp((buf_list[0] + CHUNK * 6),
247 (buf_list[2] + CHUNK * 6),
248 CHUNK) != 0) {
249 tst_resm(TFAIL, "Error: writev() over "
250 "wrote %s", f_name);
251 fail = 1;
252 }
253 } else {
254 tst_resm(TFAIL, "writev() failed unexpectedly");
255 fail = 1;
256 }
257 if (fail) {
258 tst_resm(TINFO, "block 2 FAILED");
259 } else {
260 tst_resm(TINFO, "block 2 PASSED");
261 }
262 tst_resm(TINFO, "Exit block 2");
263
264block3:
265 tst_resm(TINFO, "Enter block 3");
266 fail = 0;
267
268 if (lseek(fd[0], CHUNK * 6, 0) < 0) {
269 TEST_ERROR_LOG(errno);
270 tst_resm(TFAIL, "block3: 1st lseek failed");
271 fail = 1;
272 }
273 if ((nbytes = writev(fd[0], (wr_iovec + 6), 3)) < 0) {
274 TEST_ERROR_LOG(errno);
275 if (errno == EFAULT) {
276 tst_resm(TFAIL, "Got EFAULT");
277 fail = 1;
278 }
279 }
280 if (l_seek(fd[0], 0, 0) < 0) {
281 TEST_ERROR_LOG(errno);
282 tst_resm(TFAIL, "block3: 2nd lseek failed");
283 fail = 1;
284 }
285 if ((nbytes = read(fd[0], buf_list[0], K_1)) != K_1) {
286 perror("read error");
287 tst_resm(TFAIL, "expected nbytes = 1024, got = %d",
288 nbytes);
289 fail = 1;
290 } else if (memcmp((buf_list[0]+ CHUNK * 6),
291 (buf_list[2] + CHUNK * 6),
292 CHUNK * 3) != 0) {
293 tst_resm(TFAIL, "Error: writev() over wrote %s",
294 f_name);
295 fail = 1;
296 }
297
298 if (fail) {
299 tst_resm(TINFO, "block 3 FAILED");
300 } else {
301 tst_resm(TINFO, "block 3 PASSED");
302 }
303 tst_resm(TINFO, "Exit block 3");
304
305block4:
306 tst_resm(TINFO, "Enter block 4");
307 fail = 0;
308
309 TEST(writev(fd[1], (wr_iovec + 9), 1));
310 if (TEST_RETURN < 0) {
311 TEST_ERROR_LOG(TEST_ERRNO);
312 if (TEST_ERRNO == EBADF) {
313 tst_resm(TINFO, "Received EBADF as expected");
314 } else {
315 tst_resm(TFAIL, "expected errno = EBADF, "
316 "got %d", TEST_ERRNO);
317 fail = 1;
318 }
319 } else {
320 tst_resm(TFAIL, "Error: writev() returned a "
321 "positive value");
322 fail = 1;
323 }
324
325 if (fail) {
326 tst_resm(TINFO, "block 4 FAILED");
327 } else {
328 tst_resm(TINFO, "block 4 PASSED");
329 }
330 tst_resm(TINFO, "Exit block 4");
331
332block5:
333 tst_resm(TINFO, "Enter block 5");
334 fail = 0;
335
336 TEST(writev(fd[0], (wr_iovec + 10), -1));
337 if (TEST_RETURN < 0) {
338 TEST_ERROR_LOG(TEST_ERRNO);
339 if (TEST_ERRNO == EINVAL) {
340 tst_resm(TINFO, "Received EINVAL as expected");
341 } else {
342 tst_resm(TFAIL, "expected errno = EINVAL, "
343 "got %d", TEST_ERRNO);
344 fail = 1;
345 }
346 } else {
347 tst_resm(TFAIL, "Error: writev() returned a "
348 "positive value");
349 fail = 1;
350 }
351
352 if (fail) {
353 tst_resm(TINFO, "block 5 FAILED");
354 } else {
355 tst_resm(TINFO, "block 5 PASSED");
356 }
357 tst_resm(TINFO, "Exit block 5");
358
359block6:
360 tst_resm(TINFO, "Enter block 6");
361 fail = 0;
362
363 TEST(writev(fd[0], (wr_iovec + 11), 0));
364 if (TEST_RETURN < 0) {
365 TEST_ERROR_LOG(TEST_ERRNO);
366 tst_resm(TFAIL, "writev() failed with unexpected errno "
367 "%d", TEST_ERRNO);
368 fail = 1;
369 } else {
370 tst_resm(TPASS, "writev() wrote 0 iovectors");
371 }
372
373 if (fail) {
374 tst_resm(TINFO, "block 6 FAILED");
375 } else {
376 tst_resm(TINFO, "block 6 PASSED");
377 }
378 tst_resm(TINFO, "Exit block 6");
379
380block7:
381 tst_resm(TINFO, "Enter block 7");
382 fail = 0;
383
384 l_seek(fd[0], CHUNK * 12, 0);
385 if ((ret = writev(fd[0], (wr_iovec + 12), 5)) != CHUNK) {
386 tst_resm(TFAIL, "writev() failed writing %d bytes, "
387 "followed by two NULL vectors", CHUNK);
388 fail = 1;
389 } else {
390 tst_resm(TPASS, "writev passed writing %d bytes, "
391 "followed by two NULL vectors", CHUNK);
392 }
393
394 if (fail) {
395 tst_resm(TINFO, "block 7 FAILED");
396 } else {
397 tst_resm(TINFO, "block 7 PASSED");
398 }
399 tst_resm(TINFO, "Exit block 7");
400
401block8:
402 tst_resm(TINFO, "Enter block 8");
403 fail = 0;
404
405 if (pipe(pfd) < 0) {
406 TEST_ERROR_LOG(errno);
407 perror("pipe");
408 tst_resm(TFAIL, "pipe failed: errno = %d", errno);
409 fail = 1;
410 } else {
411 if (close(pfd[0]) < 0) {
412 TEST_ERROR_LOG(errno);
413 perror("close");
414 tst_resm(TFAIL, "close failed: errno = %d",
415 errno);
416 fail = 1;
417 } else if ((writev(pfd[1], (wr_iovec + 12), 1)
418 < 0) && in_sighandler) {
419 TEST_ERROR_LOG(errno);
420 if (errno == EPIPE) {
421 tst_resm(TINFO, "Received EPIPE as "
422 "expected");
423 } else {
424 tst_resm(TFAIL, "expected errno = "
425 "EPIPE, got %d", errno);
426 fail = 1;
427 }
428 } else {
429 tst_resm(TFAIL, "Error: writev() returned a "
430 "positive value");
431 fail = 1;
432 }
433 }
434 if (fail) {
435 tst_resm(TINFO, "block 8 FAILED");
436 } else {
437 tst_resm(TINFO, "block 8 PASSED");
438 }
439 tst_resm(TINFO, "Exit block 8");
440 }
441 cleanup();
442 /*NOTREACHED*/
443}
444
445/*
446 * setup()
447 * performs all ONE TIME setup for this test
448 */
449void
450setup(void)
451{
452 /* capture signals */
453 tst_sig(FORK, DEF_HANDLER, cleanup);
454
455 /* Set up the expected error numbers for -e option */
456 TEST_EXP_ENOS(exp_enos);
457
458 /* Pause if that option was specified.
459 * TEST_PAUSE contains the code to fork the test with the -i option.
460 * You want to make sure you do this before you create your temporary
461 * directory.
462 */
463 TEST_PAUSE;
464
465 /* Create a unique temporary directory and chdir() to it. */
466 tst_tmpdir();
467
468 strcpy(name, DATA_FILE);
469 sprintf(f_name, "%s.%d", name, getpid());
470}
471
472/*
473 * cleanup()
474 * performs all ONE TIME cleanup for this test at
475 * completion or premature exit
476 */
477void
478cleanup(void)
479{
480 /*
481 * print timing stats if that option was specified.
482 * print errno log if that option was specified.
483 */
484 TEST_CLEANUP;
485
486 if (unlink(f_name) < 0) {
487 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
488 f_name, errno);
489 }
490 tst_rmdir();
491
492 tst_exit();
493}
494
495int
496init_buffs(char *pbufs[])
497{
498 int i;
499
500 for (i = 0; pbufs[i] != (char *)NULL; i++) {
501 switch (i) {
502 case 0:
503
504 case 1: fill_mem(pbufs[i], 0, 1);
505 break;
506
507 case 2: fill_mem(pbufs[i], 1, 0);
508 break;
509
510 default: tst_resm(TFAIL, "Error detected: init_buffs()");
511 cleanup();
512 /*NOTREACHED*/
513 }
514 }
515 return(0);
516}
517
518int
519fill_mem(char *c_ptr, int c1, int c2)
520{
521 int count;
522
523 for (count = 1; count <= K_1 / CHUNK; count++) {
524 if (count & 0x01) { /* if odd */
525 memset(c_ptr, c1, CHUNK);
526 } else { /* if even */
527 memset(c_ptr, c2, CHUNK);
528 }
529 }
530 return(0);
531}
532
533void
534sighandler(int sig)
535{
536 switch (sig) {
537 case SIGTERM: break;
538
539 case SIGPIPE: ++in_sighandler;
540 return;
541
542 default: tst_resm(TFAIL, "sighandler() received invalid "
543 "signal:%d", sig);
544 break;
545 }
546
547 if (unlink(f_name) < 0) {
548 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
549 f_name, errno);
550 tst_exit();
551 /*NOTREACHED*/
552 }
553 exit(sig);
554}
555
556long
557l_seek(int fdesc, long offset, int whence)
558{
559 if (lseek(fdesc, offset, whence) < 0) {
560 perror("lseek");
561 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
562 fail = 1;
563 }
564 return(0);
565}