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