blob: b89884a5385970f41c7d42a89b63a9cdfea1d26a [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
robbiew4644c7e2002-04-26 14:33:32 +000042 * 04/2002 wjhuie sigset cleanups
robbiew51281002002-06-20 17:02:19 +000043 * 06/2002 Shaobo Li
44 * fix testcase 7, add each testcase comment.
plars865695b2001-08-27 22:15:12 +000045 *
46 * Restrictions
47 * None
48 */
49
50#include <stdio.h>
plars29bcde82002-10-07 17:21:48 +000051#include <sys/types.h>
plars20bc5f22002-10-10 17:37:56 +000052#include <signal.h>
plars865695b2001-08-27 22:15:12 +000053#include <sys/uio.h>
54#include <sys/fcntl.h>
55#include <memory.h>
56#include <errno.h>
57#include <test.h>
58#include <usctest.h>
robbiewb73a6b72003-11-17 15:21:18 +000059#include <sys/mman.h>
plars865695b2001-08-27 22:15:12 +000060
61#define K_1 1024
62#define M_1 K_1 * K_1
63#define G_1 M_1 * K_1
64
65#define NBUFS 4
66#define CHUNK 64 /* single chunk */
67#define MAX_IOVEC 16
68#define DATA_FILE "writev_data_file"
69
70char buf1[K_1], buf2[K_1], buf3[K_1];
71
72struct iovec wr_iovec[MAX_IOVEC] = {
73 /* iov_base */ /* iov_len */
74
75 /* testcase# 1 */
robbiew7d5c5172003-03-27 22:54:57 +000076 {buf1, -1},
77 {(buf1 + CHUNK), CHUNK},
78 {(buf1 + CHUNK * 2), CHUNK},
plars865695b2001-08-27 22:15:12 +000079
80 /* testcase# 2 */
robbiew7d5c5172003-03-27 22:54:57 +000081 {(buf1 + CHUNK * 3), G_1},
82 {(buf1 + CHUNK * 4), G_1},
83 {(buf1 + CHUNK * 5), G_1},
plars865695b2001-08-27 22:15:12 +000084
85 /* testcase# 3 */
robbiew7d5c5172003-03-27 22:54:57 +000086 {(buf1 + CHUNK * 6), CHUNK},
87 {(caddr_t)-1, CHUNK},
88 {(buf1 + CHUNK * 8), CHUNK},
plars865695b2001-08-27 22:15:12 +000089
90 /* testcase# 4 */
robbiew7d5c5172003-03-27 22:54:57 +000091 {(buf1 + CHUNK * 9), CHUNK},
plars865695b2001-08-27 22:15:12 +000092
93 /* testcase# 5 */
robbiew7d5c5172003-03-27 22:54:57 +000094 {(buf1 + CHUNK * 10), CHUNK},
plars865695b2001-08-27 22:15:12 +000095
96 /* testcase# 6 */
robbiew7d5c5172003-03-27 22:54:57 +000097 {(buf1 + CHUNK * 11), CHUNK},
plars865695b2001-08-27 22:15:12 +000098
99 /* testcase# 7 */
robbiew7d5c5172003-03-27 22:54:57 +0000100 {(buf1 + CHUNK * 12), CHUNK},
plars865695b2001-08-27 22:15:12 +0000101
102 /* testcase# 8 */
robbiew7d5c5172003-03-27 22:54:57 +0000103 {(buf1 + CHUNK * 13), 0},
plars865695b2001-08-27 22:15:12 +0000104
robbiew51281002002-06-20 17:02:19 +0000105 /* testcase# 7 */
robbiew7d5c5172003-03-27 22:54:57 +0000106 {(caddr_t)NULL, 0},
107 {(caddr_t)NULL, 0}
plars865695b2001-08-27 22:15:12 +0000108};
109
110char name[K_1], f_name[K_1];
111
robbiewb73a6b72003-11-17 15:21:18 +0000112char * bad_addr = 0;
113
plars865695b2001-08-27 22:15:12 +0000114/* 0 terminated list of expected errnos */
115int exp_enos[] = {14, 22, 32, 77, 0};
116
117int fd[4], in_sighandler;
118int pfd[2]; /* pipe fd's */
119char *buf_list[NBUFS];
120int fail;
121
122void sighandler(int);
123long l_seek(int, long, int);
124int fill_mem(char *, int, int);
125int init_buffs(char *[]);
126void setup(void);
127void cleanup(void);
128
129char *TCID = "writev01";
130int TST_TOTAL = 1;
131extern int Tst_count;
132
robbiew7d5c5172003-03-27 22:54:57 +0000133int main(int argc, char **argv)
plars865695b2001-08-27 22:15:12 +0000134{
135 int nbytes, ret;
136
137 int lc; /* loop counter */
138 char *msg; /* message returned from parse_opts */
139
140 /* parse standard options */
141 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
142 (char *) NULL) {
143 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
144 /*NOTREACHED*/
145 }
146
147 /* set "tstdir", and "testfile" vars */
148 setup();
149
150 /* The following loop checks looping state if -i option given */
151 for (lc = 0; TEST_LOOPING(lc); lc++) {
152
153
154 /* reset Tst_count in case we are looping */
155 Tst_count = 0;
156
157 buf_list[0] = buf1;
158 buf_list[1] = buf2;
159 buf_list[2] = buf3;
160 buf_list[3] = (char *)NULL;
161
162 fd[1] = -1; /* Invalid file descriptor */
163
robbiew4644c7e2002-04-26 14:33:32 +0000164 if (signal(SIGTERM, sighandler) == SIG_ERR) {
165 perror("signal: SIGTERM");
plars865695b2001-08-27 22:15:12 +0000166 cleanup();
167 /*NOTREACHED*/
168 }
169
robbiew4644c7e2002-04-26 14:33:32 +0000170 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
171 perror("signal: SIGPIPE");
plars865695b2001-08-27 22:15:12 +0000172 cleanup();
173 /*NOTREACHED*/
174 }
175
176 init_buffs(buf_list);
177
178 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
179 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
180 f_name, errno);
181 cleanup();
182 /*NOTREACHED*/
183 } else if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
184 tst_resm(TFAIL, "write failed: nbytes = %d, "
185 "errno = %d", nbytes, errno);
186 cleanup();
187 /*NOTREACHED*/
188 }
189
190 if (close(fd[0]) < 0) {
191 tst_resm(TFAIL, "close failed: errno: %d", errno);
192 cleanup();
193 /*NOTREACHED*/
194 }
195
196 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
197 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
198 f_name, errno);
199 cleanup();
200 /*NOTREACHED*/
201 }
202
robbiew7d5c5172003-03-27 22:54:57 +0000203//block1: /* given vector length -1, writev() return EINVAL. */
plars865695b2001-08-27 22:15:12 +0000204 tst_resm(TINFO, "Enter Block 1");
205 fail = 0;
206
207 TEST(writev(fd[0], wr_iovec, 1));
208 if (TEST_RETURN < 0) {
209 TEST_ERROR_LOG(TEST_ERRNO);
210 if (TEST_ERRNO == EINVAL) {
211 tst_resm(TINFO, "Received EINVAL as expected");
212 } else {
213 tst_resm(TFAIL, "Expected errno = EINVAL, "
214 "got %d", TEST_ERRNO);
215 fail = 1;
216 }
217 } else {
218 tst_resm(TFAIL, "writev() failed to fail");
219 fail = 1;
220 }
221 if (fail) {
222 tst_resm(TINFO, "block 1 FAILED");
223 } else {
224 tst_resm(TINFO, "block 1 PASSED");
225 }
226 tst_resm(TINFO, "Exit block 1");
227
robbiew7d5c5172003-03-27 22:54:57 +0000228//block2:
229 /* This testcases doesn't look like what it intent to do
robbiew51281002002-06-20 17:02:19 +0000230 * 1. it is not using the wr_iovec initialized
231 * 2. read() and following message is not consistent
232 */
plars865695b2001-08-27 22:15:12 +0000233 tst_resm(TINFO, "Enter block 2");
234 fail = 0;
235
236 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
237 TEST_ERROR_LOG(errno);
238 tst_resm(TBROK, "block2: 1st lseek failed");
239 fail = 1;
240 }
241
242 if ((ret = writev(fd[0], (wr_iovec + 6), 3)) == CHUNK) {
243 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
244 TEST_ERROR_LOG(errno);
245 tst_resm(TFAIL, "block2: 2nd lseek failed");
246 fail = 1;
247 }
248 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) !=
249 CHUNK) {
250 perror("read error");
251 tst_resm(TFAIL, "expected nbytes = 1024, "
252 "got = %d", nbytes);
253 fail = 1;
254 } else if (memcmp((buf_list[0] + CHUNK * 6),
255 (buf_list[2] + CHUNK * 6),
256 CHUNK) != 0) {
257 tst_resm(TFAIL, "Error: writev() over "
258 "wrote %s", f_name);
259 fail = 1;
260 }
261 } else {
262 tst_resm(TFAIL, "writev() failed unexpectedly");
263 fail = 1;
264 }
265 if (fail) {
266 tst_resm(TINFO, "block 2 FAILED");
267 } else {
268 tst_resm(TINFO, "block 2 PASSED");
269 }
270 tst_resm(TINFO, "Exit block 2");
271
robbiew7d5c5172003-03-27 22:54:57 +0000272//block3: /* given 1 bad vector buffer with good ones, writev() success */
plars865695b2001-08-27 22:15:12 +0000273 tst_resm(TINFO, "Enter block 3");
274 fail = 0;
275
276 if (lseek(fd[0], CHUNK * 6, 0) < 0) {
277 TEST_ERROR_LOG(errno);
278 tst_resm(TFAIL, "block3: 1st lseek failed");
279 fail = 1;
280 }
281 if ((nbytes = writev(fd[0], (wr_iovec + 6), 3)) < 0) {
282 TEST_ERROR_LOG(errno);
283 if (errno == EFAULT) {
284 tst_resm(TFAIL, "Got EFAULT");
285 fail = 1;
286 }
287 }
288 if (l_seek(fd[0], 0, 0) < 0) {
289 TEST_ERROR_LOG(errno);
290 tst_resm(TFAIL, "block3: 2nd lseek failed");
291 fail = 1;
292 }
293 if ((nbytes = read(fd[0], buf_list[0], K_1)) != K_1) {
294 perror("read error");
295 tst_resm(TFAIL, "expected nbytes = 1024, got = %d",
296 nbytes);
297 fail = 1;
298 } else if (memcmp((buf_list[0]+ CHUNK * 6),
299 (buf_list[2] + CHUNK * 6),
300 CHUNK * 3) != 0) {
301 tst_resm(TFAIL, "Error: writev() over wrote %s",
302 f_name);
303 fail = 1;
304 }
305
306 if (fail) {
307 tst_resm(TINFO, "block 3 FAILED");
308 } else {
309 tst_resm(TINFO, "block 3 PASSED");
310 }
311 tst_resm(TINFO, "Exit block 3");
312
robbiew7d5c5172003-03-27 22:54:57 +0000313//block4: /* given bad file discriptor, writev() return EBADF. */
plars865695b2001-08-27 22:15:12 +0000314 tst_resm(TINFO, "Enter block 4");
315 fail = 0;
316
317 TEST(writev(fd[1], (wr_iovec + 9), 1));
318 if (TEST_RETURN < 0) {
319 TEST_ERROR_LOG(TEST_ERRNO);
320 if (TEST_ERRNO == EBADF) {
321 tst_resm(TINFO, "Received EBADF as expected");
322 } else {
323 tst_resm(TFAIL, "expected errno = EBADF, "
324 "got %d", TEST_ERRNO);
325 fail = 1;
326 }
327 } else {
328 tst_resm(TFAIL, "Error: writev() returned a "
329 "positive value");
330 fail = 1;
331 }
332
333 if (fail) {
334 tst_resm(TINFO, "block 4 FAILED");
335 } else {
336 tst_resm(TINFO, "block 4 PASSED");
337 }
338 tst_resm(TINFO, "Exit block 4");
339
robbiew7d5c5172003-03-27 22:54:57 +0000340//block5: /* given invalid vector count, writev() return EINVAL */
plars865695b2001-08-27 22:15:12 +0000341 tst_resm(TINFO, "Enter block 5");
342 fail = 0;
343
344 TEST(writev(fd[0], (wr_iovec + 10), -1));
345 if (TEST_RETURN < 0) {
346 TEST_ERROR_LOG(TEST_ERRNO);
347 if (TEST_ERRNO == EINVAL) {
348 tst_resm(TINFO, "Received EINVAL as expected");
349 } else {
350 tst_resm(TFAIL, "expected errno = EINVAL, "
351 "got %d", TEST_ERRNO);
352 fail = 1;
353 }
354 } else {
355 tst_resm(TFAIL, "Error: writev() returned a "
356 "positive value");
357 fail = 1;
358 }
359
360 if (fail) {
361 tst_resm(TINFO, "block 5 FAILED");
362 } else {
363 tst_resm(TINFO, "block 5 PASSED");
364 }
365 tst_resm(TINFO, "Exit block 5");
366
robbiew7d5c5172003-03-27 22:54:57 +0000367//block6: /* given no buffer vector, writev() success */
plars865695b2001-08-27 22:15:12 +0000368 tst_resm(TINFO, "Enter block 6");
369 fail = 0;
370
371 TEST(writev(fd[0], (wr_iovec + 11), 0));
plars20bc5f22002-10-10 17:37:56 +0000372 if (TEST_RETURN < 0) {
373 TEST_ERROR_LOG(TEST_ERRNO);
374 tst_resm(TFAIL, "writev() failed with unexpected errno "
375 "%d", TEST_ERRNO);
plars29bcde82002-10-07 17:21:48 +0000376 fail = 1;
plars20bc5f22002-10-10 17:37:56 +0000377 } else {
378 tst_resm(TPASS, "writev() wrote 0 iovectors");
plars865695b2001-08-27 22:15:12 +0000379 }
380
381 if (fail) {
382 tst_resm(TINFO, "block 6 FAILED");
383 } else {
384 tst_resm(TINFO, "block 6 PASSED");
385 }
386 tst_resm(TINFO, "Exit block 6");
387
robbiew7d5c5172003-03-27 22:54:57 +0000388//block7:
389 /* given 4 vectors, 2 are NULL, 1 with 0 length and 1 with fixed length,
robbiew51281002002-06-20 17:02:19 +0000390 * writev() success writing fixed length.
391 */
plars865695b2001-08-27 22:15:12 +0000392 tst_resm(TINFO, "Enter block 7");
393 fail = 0;
394
395 l_seek(fd[0], CHUNK * 12, 0);
robbiew51281002002-06-20 17:02:19 +0000396 if ((ret = writev(fd[0], (wr_iovec + 12), 4)) != CHUNK) {
plars865695b2001-08-27 22:15:12 +0000397 tst_resm(TFAIL, "writev() failed writing %d bytes, "
398 "followed by two NULL vectors", CHUNK);
399 fail = 1;
400 } else {
401 tst_resm(TPASS, "writev passed writing %d bytes, "
402 "followed by two NULL vectors", CHUNK);
403 }
404
405 if (fail) {
406 tst_resm(TINFO, "block 7 FAILED");
407 } else {
408 tst_resm(TINFO, "block 7 PASSED");
409 }
410 tst_resm(TINFO, "Exit block 7");
411
robbiew7d5c5172003-03-27 22:54:57 +0000412//block8: /* try to write to a closed pipe, writev() return EPIPE. */
plars865695b2001-08-27 22:15:12 +0000413 tst_resm(TINFO, "Enter block 8");
414 fail = 0;
415
416 if (pipe(pfd) < 0) {
417 TEST_ERROR_LOG(errno);
418 perror("pipe");
419 tst_resm(TFAIL, "pipe failed: errno = %d", errno);
420 fail = 1;
421 } else {
422 if (close(pfd[0]) < 0) {
423 TEST_ERROR_LOG(errno);
424 perror("close");
425 tst_resm(TFAIL, "close failed: errno = %d",
426 errno);
427 fail = 1;
428 } else if ((writev(pfd[1], (wr_iovec + 12), 1)
429 < 0) && in_sighandler) {
430 TEST_ERROR_LOG(errno);
431 if (errno == EPIPE) {
432 tst_resm(TINFO, "Received EPIPE as "
433 "expected");
434 } else {
435 tst_resm(TFAIL, "expected errno = "
436 "EPIPE, got %d", errno);
437 fail = 1;
438 }
439 } else {
440 tst_resm(TFAIL, "Error: writev() returned a "
441 "positive value");
442 fail = 1;
443 }
444 }
445 if (fail) {
446 tst_resm(TINFO, "block 8 FAILED");
447 } else {
448 tst_resm(TINFO, "block 8 PASSED");
449 }
450 tst_resm(TINFO, "Exit block 8");
451 }
452 cleanup();
453 /*NOTREACHED*/
robbiew7d5c5172003-03-27 22:54:57 +0000454 return(0);
plars865695b2001-08-27 22:15:12 +0000455}
456
457/*
458 * setup()
459 * performs all ONE TIME setup for this test
460 */
461void
462setup(void)
463{
464 /* capture signals */
465 tst_sig(FORK, DEF_HANDLER, cleanup);
466
467 /* Set up the expected error numbers for -e option */
468 TEST_EXP_ENOS(exp_enos);
469
470 /* Pause if that option was specified.
471 * TEST_PAUSE contains the code to fork the test with the -i option.
472 * You want to make sure you do this before you create your temporary
473 * directory.
474 */
475 TEST_PAUSE;
476
477 /* Create a unique temporary directory and chdir() to it. */
478 tst_tmpdir();
479
480 strcpy(name, DATA_FILE);
481 sprintf(f_name, "%s.%d", name, getpid());
robbiewb73a6b72003-11-17 15:21:18 +0000482
483 bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
484 if (bad_addr <= 0) {
485 printf("mmap failed\n");
486 }
487 wr_iovec[7].iov_base = bad_addr;
488
plars865695b2001-08-27 22:15:12 +0000489}
490
491/*
492 * cleanup()
493 * performs all ONE TIME cleanup for this test at
494 * completion or premature exit
495 */
496void
497cleanup(void)
498{
499 /*
500 * print timing stats if that option was specified.
501 * print errno log if that option was specified.
502 */
503 TEST_CLEANUP;
504
505 if (unlink(f_name) < 0) {
506 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
507 f_name, errno);
508 }
509 tst_rmdir();
510
511 tst_exit();
512}
513
514int
515init_buffs(char *pbufs[])
516{
517 int i;
518
519 for (i = 0; pbufs[i] != (char *)NULL; i++) {
520 switch (i) {
521 case 0:
522
523 case 1: fill_mem(pbufs[i], 0, 1);
524 break;
525
526 case 2: fill_mem(pbufs[i], 1, 0);
527 break;
528
529 default: tst_resm(TFAIL, "Error detected: init_buffs()");
530 cleanup();
531 /*NOTREACHED*/
532 }
533 }
534 return(0);
535}
536
537int
538fill_mem(char *c_ptr, int c1, int c2)
539{
540 int count;
541
542 for (count = 1; count <= K_1 / CHUNK; count++) {
543 if (count & 0x01) { /* if odd */
544 memset(c_ptr, c1, CHUNK);
545 } else { /* if even */
546 memset(c_ptr, c2, CHUNK);
547 }
548 }
549 return(0);
550}
551
552void
553sighandler(int sig)
554{
555 switch (sig) {
556 case SIGTERM: break;
557
558 case SIGPIPE: ++in_sighandler;
559 return;
560
561 default: tst_resm(TFAIL, "sighandler() received invalid "
562 "signal:%d", sig);
563 break;
564 }
565
566 if (unlink(f_name) < 0) {
567 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
568 f_name, errno);
569 tst_exit();
570 /*NOTREACHED*/
571 }
572 exit(sig);
573}
574
575long
576l_seek(int fdesc, long offset, int whence)
577{
578 if (lseek(fdesc, offset, whence) < 0) {
579 perror("lseek");
580 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
581 fail = 1;
582 }
583 return(0);
584}