writev01.c revision ec6edca7aa42b6affd989ef91b5897f96795e40f
1/* 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 * 04/2002 wjhuie sigset cleanups 43 * 06/2002 Shaobo Li 44 * fix testcase 7, add each testcase comment. 45 * 46 * Restrictions 47 * None 48 */ 49 50#include <stdio.h> 51#include <sys/types.h> 52#include <signal.h> 53#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#include <sys/mman.h> 60 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 */ 76 {buf1, -1}, 77 {(buf1 + CHUNK), CHUNK}, 78 {(buf1 + CHUNK * 2), CHUNK}, 79 80 /* testcase# 2 */ 81 {(buf1 + CHUNK * 3), G_1}, 82 {(buf1 + CHUNK * 4), G_1}, 83 {(buf1 + CHUNK * 5), G_1}, 84 85 /* testcase# 3 */ 86 {(buf1 + CHUNK * 6), CHUNK}, 87 {(caddr_t) - 1, CHUNK}, 88 {(buf1 + CHUNK * 8), CHUNK}, 89 90 /* testcase# 4 */ 91 {(buf1 + CHUNK * 9), CHUNK}, 92 93 /* testcase# 5 */ 94 {(buf1 + CHUNK * 10), CHUNK}, 95 96 /* testcase# 6 */ 97 {(buf1 + CHUNK * 11), CHUNK}, 98 99 /* testcase# 7 */ 100 {(buf1 + CHUNK * 12), CHUNK}, 101 102 /* testcase# 8 */ 103 {(buf1 + CHUNK * 13), 0}, 104 105 /* testcase# 7 */ 106 {(caddr_t) NULL, 0}, 107 {(caddr_t) NULL, 0} 108}; 109 110char name[K_1], f_name[K_1]; 111 112char *bad_addr = 0; 113 114/* 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]; 120 121void sighandler(int); 122int fill_mem(char *, int, int); 123void init_buffs(char *[]); 124void setup(void); 125void cleanup(void); 126 127char *TCID = "writev01"; 128int TST_TOTAL = 1; 129 130int main(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 if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) 138 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 139 140 setup(); 141 142 for (lc = 0; TEST_LOOPING(lc); lc++) { 143 144 Tst_count = 0; 145 146 buf_list[0] = buf1; 147 buf_list[1] = buf2; 148 buf_list[2] = buf3; 149 buf_list[3] = NULL; 150 151 fd[1] = -1; /* Invalid file descriptor */ 152 153 if (signal(SIGTERM, sighandler) == SIG_ERR) 154 tst_brkm(TBROK|TERRNO, cleanup, 155 "signal(SIGTERM, ..) failed"); 156 157 if (signal(SIGPIPE, sighandler) == SIG_ERR) 158 tst_brkm(TBROK|TERRNO, cleanup, 159 "signal(SIGPIPE, ..) failed"); 160 161 init_buffs(buf_list); 162 163 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) == -1) 164 tst_brkm(TBROK|TERRNO, cleanup, 165 "open(.., O_WRONLY|O_CREAT, ..) failed"); 166 else 167 if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) 168 tst_brkm(TBROK|TERRNO, cleanup, "write failed"); 169 170 if (close(fd[0]) == -1) 171 tst_brkm(TBROK|TERRNO, cleanup, "close failed"); 172 173 if ((fd[0] = open(f_name, O_RDWR, 0666)) == -1) 174 tst_brkm(TBROK|TERRNO, cleanup, "open failed"); 175//block1: /* given vector length -1, writev return EINVAL. */ 176 tst_resm(TPASS, "Enter Block 1"); 177 178 TEST(writev(fd[0], wr_iovec, 1)); 179 if (TEST_RETURN == -1) { 180 if (TEST_ERRNO == EINVAL) 181 tst_resm(TPASS, "Received EINVAL as expected"); 182 else 183 tst_resm(TFAIL, "Expected errno = EINVAL, " 184 "got %d", TEST_ERRNO); 185 } else 186 tst_resm(TFAIL, "writev failed to fail"); 187 tst_resm(TINFO, "Exit block 1"); 188 189//block2: 190 /* This testcases doesn't look like what it intent to do 191 * 1. it is not using the wr_iovec initialized 192 * 2. read() and following message is not consistent 193 */ 194 tst_resm(TPASS, "Enter block 2"); 195 196 if (lseek(fd[0], CHUNK * 6, 0) == -1) 197 tst_resm(TBROK|TERRNO, "block2: 1st lseek failed"); 198 199 if ((ret = writev(fd[0], (wr_iovec + 6), 3)) == CHUNK) { 200 if (lseek(fd[0], CHUNK * 6, 0) == -1) 201 tst_brkm(TBROK|TERRNO, cleanup, 202 "block2: 2nd lseek failed"); 203 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 204 CHUNK) 205 tst_resm(TFAIL, "read failed; expected nbytes " 206 "= 1024, got = %d", nbytes); 207 else if (memcmp((buf_list[0] + CHUNK * 6), 208 (buf_list[2] + CHUNK * 6), 209 CHUNK) != 0) 210 tst_resm(TFAIL, "writev over " 211 "wrote %s", f_name); 212 } else 213 tst_resm(TFAIL|TERRNO, "writev failed unexpectedly"); 214 tst_resm(TINFO, "Exit block 2"); 215 216//block3: /* given 1 bad vector buffer with good ones, writev success */ 217 tst_resm(TPASS, "Enter block 3"); 218 219 if (lseek(fd[0], CHUNK * 6, 0) == -1) 220 tst_brkm(TBROK|TERRNO, cleanup, 221 "block3: 1st lseek failed"); 222 if ((nbytes = writev(fd[0], (wr_iovec + 6), 3)) == -1) { 223 if (errno == EFAULT) 224 tst_resm(TFAIL, "Got EFAULT"); 225 } 226 if (lseek(fd[0], 0, 0) == -1) 227 tst_brkm(TBROK, cleanup, "block3: 2nd lseek failed"); 228 if ((nbytes = read(fd[0], buf_list[0], K_1)) != K_1) { 229 tst_resm(TFAIL|TERRNO, 230 "read failed; expected nbytes = 1024, got = %d", 231 nbytes); 232 } else if (memcmp((buf_list[0] + CHUNK * 6), 233 (buf_list[2] + CHUNK * 6), CHUNK * 3) != 0) 234 tst_resm(TFAIL, "writev overwrote file"); 235 236 tst_resm(TINFO, "Exit block 3"); 237 238//block4: /* given bad file discriptor, writev return EBADF. */ 239 tst_resm(TPASS, "Enter block 4"); 240 241 TEST(writev(fd[1], (wr_iovec + 9), 1)); 242 if (TEST_RETURN == -1) { 243 if (TEST_ERRNO == EBADF) 244 tst_resm(TPASS, "Received EBADF as expected"); 245 else 246 tst_resm(TFAIL, "expected errno = EBADF, " 247 "got %d", TEST_ERRNO); 248 } else 249 tst_resm(TFAIL, "writev returned a " 250 "positive value"); 251 252 tst_resm(TINFO, "Exit block 4"); 253 254//block5: /* given invalid vector count, writev return EINVAL */ 255 tst_resm(TPASS, "Enter block 5"); 256 257 TEST(writev(fd[0], (wr_iovec + 10), -1)); 258 if (TEST_RETURN == -1) { 259 if (TEST_ERRNO == EINVAL) 260 tst_resm(TPASS, "Received EINVAL as expected"); 261 else 262 tst_resm(TFAIL, "expected errno = EINVAL, " 263 "got %d", TEST_ERRNO); 264 } else 265 tst_resm(TFAIL, "writev returned a " 266 "positive value"); 267 268 tst_resm(TINFO, "Exit block 5"); 269 270//block6: /* given no buffer vector, writev success */ 271 tst_resm(TPASS, "Enter block 6"); 272 273 TEST(writev(fd[0], (wr_iovec + 11), 0)); 274 if (TEST_RETURN == -1) 275 tst_resm(TFAIL|TTERRNO, "writev failed"); 276 else 277 tst_resm(TPASS, "writev wrote 0 iovectors"); 278 279 tst_resm(TINFO, "Exit block 6"); 280 281//block7: 282 /* given 4 vectors, 2 are NULL, 1 with 0 length and 1 with fixed length, 283 * writev success writing fixed length. 284 */ 285 tst_resm(TPASS, "Enter block 7"); 286 287 if (lseek(fd[0], CHUNK * 12, 0) == -1) 288 tst_resm(TBROK, "lseek failed"); 289 else if ((ret = writev(fd[0], (wr_iovec + 12), 4)) != CHUNK) 290 tst_resm(TFAIL, "writev failed writing %d bytes, " 291 "followed by two NULL vectors", CHUNK); 292 else 293 tst_resm(TPASS, "writev passed writing %d bytes, " 294 "followed by two NULL vectors", CHUNK); 295 296 tst_resm(TINFO, "Exit block 7"); 297 298//block8: /* try to write to a closed pipe, writev return EPIPE. */ 299 tst_resm(TPASS, "Enter block 8"); 300 301 if (pipe(pfd) == -1) 302 tst_resm(TFAIL|TERRNO, "pipe failed"); 303 else { 304 if (close(pfd[0]) == -1) 305 tst_resm(TFAIL|TERRNO, "close failed"); 306 else if (writev(pfd[1], (wr_iovec + 12), 1) == -1 && 307 in_sighandler) { 308 if (errno == EPIPE) 309 tst_resm(TPASS, "Received EPIPE as " 310 "expected"); 311 else 312 tst_resm(TFAIL|TERRNO, 313 "didn't get EPIPE"); 314 } else 315 tst_resm(TFAIL, "writev returned a positive " 316 "value"); 317 } 318 tst_resm(TINFO, "Exit block 8"); 319 } 320 cleanup(); 321 tst_exit(); 322} 323 324void setup(void) 325{ 326 327 tst_sig(FORK, sighandler, cleanup); 328 329 TEST_EXP_ENOS(exp_enos); 330 331 TEST_PAUSE; 332 333 tst_tmpdir(); 334 335 strcpy(name, DATA_FILE); 336 sprintf(f_name, "%s.%d", name, getpid()); 337 338 bad_addr = mmap(0, 1, PROT_NONE, 339 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 340 if (bad_addr == MAP_FAILED) 341 tst_brkm(TBROK|TERRNO, cleanup, "mmap failed"); 342 wr_iovec[7].iov_base = bad_addr; 343 344} 345 346void cleanup(void) 347{ 348 TEST_CLEANUP; 349 350 if (munmap(bad_addr, 1) == -1) 351 tst_resm(TBROK|TERRNO, "munmap failed"); 352 353 close(fd[0]); 354 close(fd[1]); 355 356 if (unlink(f_name) == -1) 357 tst_resm(TBROK|TERRNO, "unlink failed"); 358 359 tst_rmdir(); 360 361} 362 363void init_buffs(char *pbufs[]) 364{ 365 int i; 366 367 for (i = 0; pbufs[i] != NULL; i++) { 368 switch (i) { 369 case 0: 370 371 case 1: 372 fill_mem(pbufs[i], 0, 1); 373 break; 374 375 case 2: 376 fill_mem(pbufs[i], 1, 0); 377 break; 378 379 default: 380 tst_brkm(TBROK, cleanup, "error detected: init_buffs"); 381 } 382 } 383} 384 385int fill_mem(char *c_ptr, int c1, int c2) 386{ 387 int count; 388 389 for (count = 1; count <= K_1 / CHUNK; count++) { 390 if (count & 0x01) { /* if odd */ 391 memset(c_ptr, c1, CHUNK); 392 } else { /* if even */ 393 memset(c_ptr, c2, CHUNK); 394 } 395 } 396 return 0; 397} 398 399void sighandler(int sig) 400{ 401 switch (sig) { 402 case SIGTERM: 403 break; 404 405 case SIGPIPE: 406 in_sighandler++; 407 return; 408 409 default: 410 tst_resm(TFAIL, "sighandler received invalid signal:%d", sig); 411 break; 412 } 413} 414