blob: e4037d7cfb946a1f0d6d8e49790f9ae37732bcc7 [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 */
robbiew7d5c5172003-03-27 22:54:57 +000075 {buf1, -1},
76 {(buf1 + CHUNK), CHUNK},
77 {(buf1 + CHUNK * 2), CHUNK},
plars865695b2001-08-27 22:15:12 +000078
79 /* testcase# 2 */
robbiew7d5c5172003-03-27 22:54:57 +000080 {(buf1 + CHUNK * 3), G_1},
81 {(buf1 + CHUNK * 4), G_1},
82 {(buf1 + CHUNK * 5), G_1},
plars865695b2001-08-27 22:15:12 +000083
84 /* testcase# 3 */
robbiew7d5c5172003-03-27 22:54:57 +000085 {(buf1 + CHUNK * 6), CHUNK},
86 {(caddr_t)-1, CHUNK},
87 {(buf1 + CHUNK * 8), CHUNK},
plars865695b2001-08-27 22:15:12 +000088
89 /* testcase# 4 */
robbiew7d5c5172003-03-27 22:54:57 +000090 {(buf1 + CHUNK * 9), CHUNK},
plars865695b2001-08-27 22:15:12 +000091
92 /* testcase# 5 */
robbiew7d5c5172003-03-27 22:54:57 +000093 {(buf1 + CHUNK * 10), CHUNK},
plars865695b2001-08-27 22:15:12 +000094
95 /* testcase# 6 */
robbiew7d5c5172003-03-27 22:54:57 +000096 {(buf1 + CHUNK * 11), CHUNK},
plars865695b2001-08-27 22:15:12 +000097
98 /* testcase# 7 */
robbiew7d5c5172003-03-27 22:54:57 +000099 {(buf1 + CHUNK * 12), CHUNK},
plars865695b2001-08-27 22:15:12 +0000100
101 /* testcase# 8 */
robbiew7d5c5172003-03-27 22:54:57 +0000102 {(buf1 + CHUNK * 13), 0},
plars865695b2001-08-27 22:15:12 +0000103
robbiew51281002002-06-20 17:02:19 +0000104 /* testcase# 7 */
robbiew7d5c5172003-03-27 22:54:57 +0000105 {(caddr_t)NULL, 0},
106 {(caddr_t)NULL, 0}
plars865695b2001-08-27 22:15:12 +0000107};
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
robbiew7d5c5172003-03-27 22:54:57 +0000130int main(int argc, char **argv)
plars865695b2001-08-27 22:15:12 +0000131{
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
robbiew7d5c5172003-03-27 22:54:57 +0000200//block1: /* 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
robbiew7d5c5172003-03-27 22:54:57 +0000225//block2:
226 /* This testcases doesn't look like what it intent to do
robbiew51281002002-06-20 17:02:19 +0000227 * 1. it is not using the wr_iovec initialized
228 * 2. read() and following message is not consistent
229 */
plars865695b2001-08-27 22:15:12 +0000230 tst_resm(TINFO, "Enter block 2");
231 fail = 0;
232
233 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
234 TEST_ERROR_LOG(errno);
235 tst_resm(TBROK, "block2: 1st lseek failed");
236 fail = 1;
237 }
238
239 if ((ret = writev(fd[0], (wr_iovec + 6), 3)) == CHUNK) {
240 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
241 TEST_ERROR_LOG(errno);
242 tst_resm(TFAIL, "block2: 2nd lseek failed");
243 fail = 1;
244 }
245 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) !=
246 CHUNK) {
247 perror("read error");
248 tst_resm(TFAIL, "expected nbytes = 1024, "
249 "got = %d", nbytes);
250 fail = 1;
251 } else if (memcmp((buf_list[0] + CHUNK * 6),
252 (buf_list[2] + CHUNK * 6),
253 CHUNK) != 0) {
254 tst_resm(TFAIL, "Error: writev() over "
255 "wrote %s", f_name);
256 fail = 1;
257 }
258 } else {
259 tst_resm(TFAIL, "writev() failed unexpectedly");
260 fail = 1;
261 }
262 if (fail) {
263 tst_resm(TINFO, "block 2 FAILED");
264 } else {
265 tst_resm(TINFO, "block 2 PASSED");
266 }
267 tst_resm(TINFO, "Exit block 2");
268
robbiew7d5c5172003-03-27 22:54:57 +0000269//block3: /* given 1 bad vector buffer with good ones, writev() success */
plars865695b2001-08-27 22:15:12 +0000270 tst_resm(TINFO, "Enter block 3");
271 fail = 0;
272
273 if (lseek(fd[0], CHUNK * 6, 0) < 0) {
274 TEST_ERROR_LOG(errno);
275 tst_resm(TFAIL, "block3: 1st lseek failed");
276 fail = 1;
277 }
278 if ((nbytes = writev(fd[0], (wr_iovec + 6), 3)) < 0) {
279 TEST_ERROR_LOG(errno);
280 if (errno == EFAULT) {
281 tst_resm(TFAIL, "Got EFAULT");
282 fail = 1;
283 }
284 }
285 if (l_seek(fd[0], 0, 0) < 0) {
286 TEST_ERROR_LOG(errno);
287 tst_resm(TFAIL, "block3: 2nd lseek failed");
288 fail = 1;
289 }
290 if ((nbytes = read(fd[0], buf_list[0], K_1)) != K_1) {
291 perror("read error");
292 tst_resm(TFAIL, "expected nbytes = 1024, got = %d",
293 nbytes);
294 fail = 1;
295 } else if (memcmp((buf_list[0]+ CHUNK * 6),
296 (buf_list[2] + CHUNK * 6),
297 CHUNK * 3) != 0) {
298 tst_resm(TFAIL, "Error: writev() over wrote %s",
299 f_name);
300 fail = 1;
301 }
302
303 if (fail) {
304 tst_resm(TINFO, "block 3 FAILED");
305 } else {
306 tst_resm(TINFO, "block 3 PASSED");
307 }
308 tst_resm(TINFO, "Exit block 3");
309
robbiew7d5c5172003-03-27 22:54:57 +0000310//block4: /* given bad file discriptor, writev() return EBADF. */
plars865695b2001-08-27 22:15:12 +0000311 tst_resm(TINFO, "Enter block 4");
312 fail = 0;
313
314 TEST(writev(fd[1], (wr_iovec + 9), 1));
315 if (TEST_RETURN < 0) {
316 TEST_ERROR_LOG(TEST_ERRNO);
317 if (TEST_ERRNO == EBADF) {
318 tst_resm(TINFO, "Received EBADF as expected");
319 } else {
320 tst_resm(TFAIL, "expected errno = EBADF, "
321 "got %d", TEST_ERRNO);
322 fail = 1;
323 }
324 } else {
325 tst_resm(TFAIL, "Error: writev() returned a "
326 "positive value");
327 fail = 1;
328 }
329
330 if (fail) {
331 tst_resm(TINFO, "block 4 FAILED");
332 } else {
333 tst_resm(TINFO, "block 4 PASSED");
334 }
335 tst_resm(TINFO, "Exit block 4");
336
robbiew7d5c5172003-03-27 22:54:57 +0000337//block5: /* given invalid vector count, writev() return EINVAL */
plars865695b2001-08-27 22:15:12 +0000338 tst_resm(TINFO, "Enter block 5");
339 fail = 0;
340
341 TEST(writev(fd[0], (wr_iovec + 10), -1));
342 if (TEST_RETURN < 0) {
343 TEST_ERROR_LOG(TEST_ERRNO);
344 if (TEST_ERRNO == EINVAL) {
345 tst_resm(TINFO, "Received EINVAL as expected");
346 } else {
347 tst_resm(TFAIL, "expected errno = EINVAL, "
348 "got %d", TEST_ERRNO);
349 fail = 1;
350 }
351 } else {
352 tst_resm(TFAIL, "Error: writev() returned a "
353 "positive value");
354 fail = 1;
355 }
356
357 if (fail) {
358 tst_resm(TINFO, "block 5 FAILED");
359 } else {
360 tst_resm(TINFO, "block 5 PASSED");
361 }
362 tst_resm(TINFO, "Exit block 5");
363
robbiew7d5c5172003-03-27 22:54:57 +0000364//block6: /* given no buffer vector, writev() success */
plars865695b2001-08-27 22:15:12 +0000365 tst_resm(TINFO, "Enter block 6");
366 fail = 0;
367
368 TEST(writev(fd[0], (wr_iovec + 11), 0));
plars20bc5f22002-10-10 17:37:56 +0000369 if (TEST_RETURN < 0) {
370 TEST_ERROR_LOG(TEST_ERRNO);
371 tst_resm(TFAIL, "writev() failed with unexpected errno "
372 "%d", TEST_ERRNO);
plars29bcde82002-10-07 17:21:48 +0000373 fail = 1;
plars20bc5f22002-10-10 17:37:56 +0000374 } else {
375 tst_resm(TPASS, "writev() wrote 0 iovectors");
plars865695b2001-08-27 22:15:12 +0000376 }
377
378 if (fail) {
379 tst_resm(TINFO, "block 6 FAILED");
380 } else {
381 tst_resm(TINFO, "block 6 PASSED");
382 }
383 tst_resm(TINFO, "Exit block 6");
384
robbiew7d5c5172003-03-27 22:54:57 +0000385//block7:
386 /* given 4 vectors, 2 are NULL, 1 with 0 length and 1 with fixed length,
robbiew51281002002-06-20 17:02:19 +0000387 * writev() success writing fixed length.
388 */
plars865695b2001-08-27 22:15:12 +0000389 tst_resm(TINFO, "Enter block 7");
390 fail = 0;
391
392 l_seek(fd[0], CHUNK * 12, 0);
robbiew51281002002-06-20 17:02:19 +0000393 if ((ret = writev(fd[0], (wr_iovec + 12), 4)) != CHUNK) {
plars865695b2001-08-27 22:15:12 +0000394 tst_resm(TFAIL, "writev() failed writing %d bytes, "
395 "followed by two NULL vectors", CHUNK);
396 fail = 1;
397 } else {
398 tst_resm(TPASS, "writev passed writing %d bytes, "
399 "followed by two NULL vectors", CHUNK);
400 }
401
402 if (fail) {
403 tst_resm(TINFO, "block 7 FAILED");
404 } else {
405 tst_resm(TINFO, "block 7 PASSED");
406 }
407 tst_resm(TINFO, "Exit block 7");
408
robbiew7d5c5172003-03-27 22:54:57 +0000409//block8: /* try to write to a closed pipe, writev() return EPIPE. */
plars865695b2001-08-27 22:15:12 +0000410 tst_resm(TINFO, "Enter block 8");
411 fail = 0;
412
413 if (pipe(pfd) < 0) {
414 TEST_ERROR_LOG(errno);
415 perror("pipe");
416 tst_resm(TFAIL, "pipe failed: errno = %d", errno);
417 fail = 1;
418 } else {
419 if (close(pfd[0]) < 0) {
420 TEST_ERROR_LOG(errno);
421 perror("close");
422 tst_resm(TFAIL, "close failed: errno = %d",
423 errno);
424 fail = 1;
425 } else if ((writev(pfd[1], (wr_iovec + 12), 1)
426 < 0) && in_sighandler) {
427 TEST_ERROR_LOG(errno);
428 if (errno == EPIPE) {
429 tst_resm(TINFO, "Received EPIPE as "
430 "expected");
431 } else {
432 tst_resm(TFAIL, "expected errno = "
433 "EPIPE, got %d", errno);
434 fail = 1;
435 }
436 } else {
437 tst_resm(TFAIL, "Error: writev() returned a "
438 "positive value");
439 fail = 1;
440 }
441 }
442 if (fail) {
443 tst_resm(TINFO, "block 8 FAILED");
444 } else {
445 tst_resm(TINFO, "block 8 PASSED");
446 }
447 tst_resm(TINFO, "Exit block 8");
448 }
449 cleanup();
450 /*NOTREACHED*/
robbiew7d5c5172003-03-27 22:54:57 +0000451 return(0);
plars865695b2001-08-27 22:15:12 +0000452}
453
454/*
455 * setup()
456 * performs all ONE TIME setup for this test
457 */
458void
459setup(void)
460{
461 /* capture signals */
462 tst_sig(FORK, DEF_HANDLER, cleanup);
463
464 /* Set up the expected error numbers for -e option */
465 TEST_EXP_ENOS(exp_enos);
466
467 /* Pause if that option was specified.
468 * TEST_PAUSE contains the code to fork the test with the -i option.
469 * You want to make sure you do this before you create your temporary
470 * directory.
471 */
472 TEST_PAUSE;
473
474 /* Create a unique temporary directory and chdir() to it. */
475 tst_tmpdir();
476
477 strcpy(name, DATA_FILE);
478 sprintf(f_name, "%s.%d", name, getpid());
plars865695b2001-08-27 22:15:12 +0000479}
480
481/*
482 * cleanup()
483 * performs all ONE TIME cleanup for this test at
484 * completion or premature exit
485 */
486void
487cleanup(void)
488{
489 /*
490 * print timing stats if that option was specified.
491 * print errno log if that option was specified.
492 */
493 TEST_CLEANUP;
494
495 if (unlink(f_name) < 0) {
496 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
497 f_name, errno);
498 }
499 tst_rmdir();
500
501 tst_exit();
502}
503
504int
505init_buffs(char *pbufs[])
506{
507 int i;
508
509 for (i = 0; pbufs[i] != (char *)NULL; i++) {
510 switch (i) {
511 case 0:
512
513 case 1: fill_mem(pbufs[i], 0, 1);
514 break;
515
516 case 2: fill_mem(pbufs[i], 1, 0);
517 break;
518
519 default: tst_resm(TFAIL, "Error detected: init_buffs()");
520 cleanup();
521 /*NOTREACHED*/
522 }
523 }
524 return(0);
525}
526
527int
528fill_mem(char *c_ptr, int c1, int c2)
529{
530 int count;
531
532 for (count = 1; count <= K_1 / CHUNK; count++) {
533 if (count & 0x01) { /* if odd */
534 memset(c_ptr, c1, CHUNK);
535 } else { /* if even */
536 memset(c_ptr, c2, CHUNK);
537 }
538 }
539 return(0);
540}
541
542void
543sighandler(int sig)
544{
545 switch (sig) {
546 case SIGTERM: break;
547
548 case SIGPIPE: ++in_sighandler;
549 return;
550
551 default: tst_resm(TFAIL, "sighandler() received invalid "
552 "signal:%d", sig);
553 break;
554 }
555
556 if (unlink(f_name) < 0) {
557 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
558 f_name, errno);
559 tst_exit();
560 /*NOTREACHED*/
561 }
562 exit(sig);
563}
564
565long
566l_seek(int fdesc, long offset, int whence)
567{
568 if (lseek(fdesc, offset, whence) < 0) {
569 perror("lseek");
570 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
571 fail = 1;
572 }
573 return(0);
574}