blob: 2fa434de743fa3bbad3c76ed4f4f6043f0e08c9f [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
plars865695b2001-08-27 22:15:12 +000043 *
44 * Restrictions
45 * None
46 */
47
48#include <stdio.h>
49#include <sys/types.h>
50#include <signal.h>
51#include <sys/uio.h>
52#include <sys/fcntl.h>
53#include <memory.h>
54#include <errno.h>
55#include <test.h>
56#include <usctest.h>
57
58#define K_1 1024
59#define M_1 K_1 * K_1
60#define G_1 M_1 * K_1
61
62#define NBUFS 4
63#define CHUNK 64 /* single chunk */
64#define MAX_IOVEC 16
65#define DATA_FILE "writev_data_file"
66
67char buf1[K_1], buf2[K_1], buf3[K_1];
68
69struct iovec wr_iovec[MAX_IOVEC] = {
70 /* iov_base */ /* iov_len */
71
72 /* testcase# 1 */
73 buf1, -1,
74 (buf1 + CHUNK), CHUNK,
75 (buf1 + CHUNK * 2), CHUNK,
76
77 /* testcase# 2 */
78 (buf1 + CHUNK * 3), G_1,
79 (buf1 + CHUNK * 4), G_1,
80 (buf1 + CHUNK * 5), G_1,
81
82 /* testcase# 3 */
83 (buf1 + CHUNK * 6), CHUNK,
84 (caddr_t)-1, CHUNK,
85 (buf1 + CHUNK * 8), CHUNK,
86
87 /* testcase# 4 */
88 (buf1 + CHUNK * 9), CHUNK,
89
90 /* testcase# 5 */
91 (buf1 + CHUNK * 10), CHUNK,
92
93 /* testcase# 6 */
94 (buf1 + CHUNK * 11), CHUNK,
95
96 /* testcase# 7 */
97 (buf1 + CHUNK * 12), CHUNK,
98
99 /* testcase# 8 */
100 (buf1 + CHUNK * 13), 0,
101
102 /* testcase# 9 */
103 (caddr_t)NULL, 0,
104
105 /* testcase# 10 */
106 (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
200block1:
201 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
225block2:
226 tst_resm(TINFO, "Enter block 2");
227 fail = 0;
228
229 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
230 TEST_ERROR_LOG(errno);
231 tst_resm(TBROK, "block2: 1st lseek failed");
232 fail = 1;
233 }
234
235 if ((ret = writev(fd[0], (wr_iovec + 6), 3)) == CHUNK) {
236 if (l_seek(fd[0], CHUNK * 6, 0) < 0) {
237 TEST_ERROR_LOG(errno);
238 tst_resm(TFAIL, "block2: 2nd lseek failed");
239 fail = 1;
240 }
241 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) !=
242 CHUNK) {
243 perror("read error");
244 tst_resm(TFAIL, "expected nbytes = 1024, "
245 "got = %d", nbytes);
246 fail = 1;
247 } else if (memcmp((buf_list[0] + CHUNK * 6),
248 (buf_list[2] + CHUNK * 6),
249 CHUNK) != 0) {
250 tst_resm(TFAIL, "Error: writev() over "
251 "wrote %s", f_name);
252 fail = 1;
253 }
254 } else {
255 tst_resm(TFAIL, "writev() failed unexpectedly");
256 fail = 1;
257 }
258 if (fail) {
259 tst_resm(TINFO, "block 2 FAILED");
260 } else {
261 tst_resm(TINFO, "block 2 PASSED");
262 }
263 tst_resm(TINFO, "Exit block 2");
264
265block3:
266 tst_resm(TINFO, "Enter block 3");
267 fail = 0;
268
269 if (lseek(fd[0], CHUNK * 6, 0) < 0) {
270 TEST_ERROR_LOG(errno);
271 tst_resm(TFAIL, "block3: 1st lseek failed");
272 fail = 1;
273 }
274 if ((nbytes = writev(fd[0], (wr_iovec + 6), 3)) < 0) {
275 TEST_ERROR_LOG(errno);
276 if (errno == EFAULT) {
277 tst_resm(TFAIL, "Got EFAULT");
278 fail = 1;
279 }
280 }
281 if (l_seek(fd[0], 0, 0) < 0) {
282 TEST_ERROR_LOG(errno);
283 tst_resm(TFAIL, "block3: 2nd lseek failed");
284 fail = 1;
285 }
286 if ((nbytes = read(fd[0], buf_list[0], K_1)) != K_1) {
287 perror("read error");
288 tst_resm(TFAIL, "expected nbytes = 1024, got = %d",
289 nbytes);
290 fail = 1;
291 } else if (memcmp((buf_list[0]+ CHUNK * 6),
292 (buf_list[2] + CHUNK * 6),
293 CHUNK * 3) != 0) {
294 tst_resm(TFAIL, "Error: writev() over wrote %s",
295 f_name);
296 fail = 1;
297 }
298
299 if (fail) {
300 tst_resm(TINFO, "block 3 FAILED");
301 } else {
302 tst_resm(TINFO, "block 3 PASSED");
303 }
304 tst_resm(TINFO, "Exit block 3");
305
306block4:
307 tst_resm(TINFO, "Enter block 4");
308 fail = 0;
309
310 TEST(writev(fd[1], (wr_iovec + 9), 1));
311 if (TEST_RETURN < 0) {
312 TEST_ERROR_LOG(TEST_ERRNO);
313 if (TEST_ERRNO == EBADF) {
314 tst_resm(TINFO, "Received EBADF as expected");
315 } else {
316 tst_resm(TFAIL, "expected errno = EBADF, "
317 "got %d", TEST_ERRNO);
318 fail = 1;
319 }
320 } else {
321 tst_resm(TFAIL, "Error: writev() returned a "
322 "positive value");
323 fail = 1;
324 }
325
326 if (fail) {
327 tst_resm(TINFO, "block 4 FAILED");
328 } else {
329 tst_resm(TINFO, "block 4 PASSED");
330 }
331 tst_resm(TINFO, "Exit block 4");
332
333block5:
334 tst_resm(TINFO, "Enter block 5");
335 fail = 0;
336
337 TEST(writev(fd[0], (wr_iovec + 10), -1));
338 if (TEST_RETURN < 0) {
339 TEST_ERROR_LOG(TEST_ERRNO);
340 if (TEST_ERRNO == EINVAL) {
341 tst_resm(TINFO, "Received EINVAL as expected");
342 } else {
343 tst_resm(TFAIL, "expected errno = EINVAL, "
344 "got %d", TEST_ERRNO);
345 fail = 1;
346 }
347 } else {
348 tst_resm(TFAIL, "Error: writev() returned a "
349 "positive value");
350 fail = 1;
351 }
352
353 if (fail) {
354 tst_resm(TINFO, "block 5 FAILED");
355 } else {
356 tst_resm(TINFO, "block 5 PASSED");
357 }
358 tst_resm(TINFO, "Exit block 5");
359
360block6:
361 tst_resm(TINFO, "Enter block 6");
362 fail = 0;
363
364 TEST(writev(fd[0], (wr_iovec + 11), 0));
365 if (TEST_RETURN < 0) {
366 TEST_ERROR_LOG(TEST_ERRNO);
367 tst_resm(TFAIL, "writev() failed with unexpected errno "
368 "%d", TEST_ERRNO);
369 fail = 1;
370 } else {
371 tst_resm(TPASS, "writev() wrote 0 iovectors");
372 }
373
374 if (fail) {
375 tst_resm(TINFO, "block 6 FAILED");
376 } else {
377 tst_resm(TINFO, "block 6 PASSED");
378 }
379 tst_resm(TINFO, "Exit block 6");
380
381block7:
382 tst_resm(TINFO, "Enter block 7");
383 fail = 0;
384
385 l_seek(fd[0], CHUNK * 12, 0);
386 if ((ret = writev(fd[0], (wr_iovec + 12), 5)) != CHUNK) {
387 tst_resm(TFAIL, "writev() failed writing %d bytes, "
388 "followed by two NULL vectors", CHUNK);
389 fail = 1;
390 } else {
391 tst_resm(TPASS, "writev passed writing %d bytes, "
392 "followed by two NULL vectors", CHUNK);
393 }
394
395 if (fail) {
396 tst_resm(TINFO, "block 7 FAILED");
397 } else {
398 tst_resm(TINFO, "block 7 PASSED");
399 }
400 tst_resm(TINFO, "Exit block 7");
401
402block8:
403 tst_resm(TINFO, "Enter block 8");
404 fail = 0;
405
406 if (pipe(pfd) < 0) {
407 TEST_ERROR_LOG(errno);
408 perror("pipe");
409 tst_resm(TFAIL, "pipe failed: errno = %d", errno);
410 fail = 1;
411 } else {
412 if (close(pfd[0]) < 0) {
413 TEST_ERROR_LOG(errno);
414 perror("close");
415 tst_resm(TFAIL, "close failed: errno = %d",
416 errno);
417 fail = 1;
418 } else if ((writev(pfd[1], (wr_iovec + 12), 1)
419 < 0) && in_sighandler) {
420 TEST_ERROR_LOG(errno);
421 if (errno == EPIPE) {
422 tst_resm(TINFO, "Received EPIPE as "
423 "expected");
424 } else {
425 tst_resm(TFAIL, "expected errno = "
426 "EPIPE, got %d", errno);
427 fail = 1;
428 }
429 } else {
430 tst_resm(TFAIL, "Error: writev() returned a "
431 "positive value");
432 fail = 1;
433 }
434 }
435 if (fail) {
436 tst_resm(TINFO, "block 8 FAILED");
437 } else {
438 tst_resm(TINFO, "block 8 PASSED");
439 }
440 tst_resm(TINFO, "Exit block 8");
441 }
442 cleanup();
443 /*NOTREACHED*/
444}
445
446/*
447 * setup()
448 * performs all ONE TIME setup for this test
449 */
450void
451setup(void)
452{
453 /* capture signals */
454 tst_sig(FORK, DEF_HANDLER, cleanup);
455
456 /* Set up the expected error numbers for -e option */
457 TEST_EXP_ENOS(exp_enos);
458
459 /* Pause if that option was specified.
460 * TEST_PAUSE contains the code to fork the test with the -i option.
461 * You want to make sure you do this before you create your temporary
462 * directory.
463 */
464 TEST_PAUSE;
465
466 /* Create a unique temporary directory and chdir() to it. */
467 tst_tmpdir();
468
469 strcpy(name, DATA_FILE);
470 sprintf(f_name, "%s.%d", name, getpid());
471}
472
473/*
474 * cleanup()
475 * performs all ONE TIME cleanup for this test at
476 * completion or premature exit
477 */
478void
479cleanup(void)
480{
481 /*
482 * print timing stats if that option was specified.
483 * print errno log if that option was specified.
484 */
485 TEST_CLEANUP;
486
487 if (unlink(f_name) < 0) {
488 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
489 f_name, errno);
490 }
491 tst_rmdir();
492
493 tst_exit();
494}
495
496int
497init_buffs(char *pbufs[])
498{
499 int i;
500
501 for (i = 0; pbufs[i] != (char *)NULL; i++) {
502 switch (i) {
503 case 0:
504
505 case 1: fill_mem(pbufs[i], 0, 1);
506 break;
507
508 case 2: fill_mem(pbufs[i], 1, 0);
509 break;
510
511 default: tst_resm(TFAIL, "Error detected: init_buffs()");
512 cleanup();
513 /*NOTREACHED*/
514 }
515 }
516 return(0);
517}
518
519int
520fill_mem(char *c_ptr, int c1, int c2)
521{
522 int count;
523
524 for (count = 1; count <= K_1 / CHUNK; count++) {
525 if (count & 0x01) { /* if odd */
526 memset(c_ptr, c1, CHUNK);
527 } else { /* if even */
528 memset(c_ptr, c2, CHUNK);
529 }
530 }
531 return(0);
532}
533
534void
535sighandler(int sig)
536{
537 switch (sig) {
538 case SIGTERM: break;
539
540 case SIGPIPE: ++in_sighandler;
541 return;
542
543 default: tst_resm(TFAIL, "sighandler() received invalid "
544 "signal:%d", sig);
545 break;
546 }
547
548 if (unlink(f_name) < 0) {
549 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
550 f_name, errno);
551 tst_exit();
552 /*NOTREACHED*/
553 }
554 exit(sig);
555}
556
557long
558l_seek(int fdesc, long offset, int whence)
559{
560 if (lseek(fdesc, offset, whence) < 0) {
561 perror("lseek");
562 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
563 fail = 1;
564 }
565 return(0);
566}