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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * writev04.c 23 * 24 * DESCRIPTION 25 * The testcases are written calling writev() with partially valid data 26 * to overwrite the contents, to write in the beginning and to write in 27 * the end of the file. This is same as writev03.c, but the length of 28 * buffer used here is 8192 bytes. 29 * 30 * USAGE: <for command-line> 31 * writev04 [-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 * 44 * Restrictions 45 * NONE 46 */ 47 #include <sys/types.h> 48 #include <sys/uio.h> 49 #include <sys/mman.h> 50 #include <unistd.h> 51 #include <signal.h> 52 #include <fcntl.h> 53 #include <memory.h> 54 #include <errno.h> 55 #include "test.h" 56 57 #define K_1 8192 58 59 #define NBUFS 4 60 #define CHUNK 64 /* single chunk */ 61 #define MAX_IOVEC 4 62 #define DATA_FILE "writev_data_file" 63 64 char buf1[K_1], buf2[K_1], buf3[K_1]; 65 char *bad_addr = 0; 66 67 struct iovec wr_iovec[MAX_IOVEC] = { 68 /* testcase #1 */ 69 {buf1 + (CHUNK * 6), CHUNK}, 70 {(caddr_t) - 1, CHUNK}, 71 {buf1 + (CHUNK * 8), CHUNK}, 72 {NULL, 0} 73 }; 74 75 char name[K_1], f_name[K_1]; 76 int fd[2], in_sighandler; 77 char *buf_list[NBUFS]; 78 79 char *TCID = "writev04"; 80 int TST_TOTAL = 1; 81 82 void sighandler(int); 83 long l_seek(int, long, int); 84 void setup(void); 85 void cleanup(void); 86 int fail; 87 88 #if !defined(UCLINUX) 89 90 int main(int argc, char **argv) 91 { 92 int lc; 93 94 int nbytes; 95 96 tst_parse_opts(argc, argv, NULL, NULL); 97 98 setup(); /* set "tstdir", and "testfile" vars */ 99 100 /* The following loop checks looping state if -i option given */ 101 for (lc = 0; TEST_LOOPING(lc); lc++) { 102 103 /* reset tst_count in case we are looping */ 104 tst_count = 0; 105 106 buf_list[0] = buf1; 107 buf_list[1] = buf2; 108 buf_list[2] = buf3; 109 buf_list[3] = NULL; 110 111 fd[1] = -1; /* Invalid file descriptor */ 112 113 if (signal(SIGTERM, sighandler) == SIG_ERR) { 114 perror("signal"); 115 tst_resm(TFAIL, "signal() SIGTERM FAILED"); 116 cleanup(); 117 } 118 119 if (signal(SIGPIPE, sighandler) == SIG_ERR) { 120 perror("signal"); 121 tst_resm(TFAIL, "signal() SIGPIPE FAILED"); 122 cleanup(); 123 } 124 125 memset(buf_list[0], 0, K_1); 126 memset(buf_list[1], 0, K_1); 127 128 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) { 129 tst_resm(TFAIL, "open(2) failed: fname = %s, " 130 "errno = %d", f_name, errno); 131 cleanup(); 132 } else { 133 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) { 134 tst_resm(TFAIL, "write(2) failed: nbytes " 135 "= %d, errno = %d", nbytes, errno); 136 cleanup(); 137 } 138 } 139 140 if (close(fd[0]) < 0) { 141 tst_resm(TFAIL, "close failed: errno = %d", errno); 142 cleanup(); 143 } 144 145 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) { 146 tst_brkm(TFAIL, cleanup, "open failed: fname = %s, errno = %d", 147 f_name, errno); 148 } 149 //block1: 150 tst_resm(TINFO, "Enter block 1"); 151 fail = 0; 152 153 /* 154 * In this block we are trying to call writev() with 155 * partially valid data. This should return the valid number 156 * of bytes written in the vector. If it returns EFAULT, it 157 * is an error. And after returning the number of valid 158 * bytes written, the check should be made to verify the 159 * contents of the first valid write() scheduled. 160 */ 161 if (writev(fd[0], wr_iovec, 3) < 0) { 162 fail = 1; 163 if (errno == EFAULT) { 164 tst_resm(TFAIL, "Got error EFAULT"); 165 } else { 166 tst_resm(TFAIL, "Received unexpected error: %d", 167 errno); 168 } 169 } else { 170 l_seek(fd[0], 0, 0); 171 read(fd[0], buf_list[0], CHUNK); 172 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) { 173 tst_resm(TFAIL, "writev overwrote the file"); 174 fail = 1; 175 } 176 } 177 178 if (fail) { 179 tst_resm(TINFO, "block 1 FAILED"); 180 } else { 181 tst_resm(TINFO, "block 1 PASSED"); 182 } 183 tst_resm(TINFO, "Exit block 1"); 184 185 //block2: 186 tst_resm(TINFO, "Enter block 2"); 187 fail = 0; 188 189 /* 190 * In this block we are trying to over write the contents by 191 * calling writev() with partially valid data. It should 192 * return the valid number of bytes written but not EFAULT. 193 * Also the check should be made whether the initial write() 194 * scheduled is done correctly or not. 195 */ 196 l_seek(fd[0], 0, 0); 197 if (writev(fd[0], wr_iovec, 3) < 0) { 198 fail = 1; 199 if (errno == EFAULT) { 200 tst_resm(TFAIL, "Got error EFAULT"); 201 } else { 202 tst_resm(TFAIL, "Received unexpected error: %d", 203 errno); 204 } 205 } else { 206 l_seek(fd[0], 0, 0); 207 read(fd[0], buf_list[0], CHUNK); 208 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) { 209 tst_resm(TFAIL, "writev overwrote the file"); 210 fail = 1; 211 } 212 } 213 214 if (fail) { 215 tst_resm(TINFO, "block 2 FAILED"); 216 } else { 217 tst_resm(TINFO, "block 2 PASSED"); 218 } 219 tst_resm(TINFO, "Exit block 2"); 220 221 //block3: 222 tst_resm(TINFO, "Enter block 3"); 223 fail = 0; 224 225 /* 226 * In this block, we are trying to call writev() by going to 227 * some end position of the file. Here writev() is called 228 * with partially valid data, and this will return the 229 * number of valid bytes written and not EFAULT. Also, the 230 * check should be made whether the inital write() that is 231 * scheduled with valid data is done correctly. 232 */ 233 234 l_seek(fd[0], 8192, 0); 235 if (writev(fd[0], wr_iovec, 3) < 0) { 236 fail = 1; 237 if (errno == EFAULT) { 238 tst_resm(TFAIL, "Got error EFAULT"); 239 } else { 240 tst_resm(TFAIL, "Received unexpected error: %d", 241 errno); 242 } 243 } else { 244 l_seek(fd[0], 0, 0); 245 read(fd[0], buf_list[0], CHUNK); 246 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) { 247 tst_resm(TFAIL, "writev overwrote the file"); 248 fail = 1; 249 } 250 } 251 252 if (fail) { 253 tst_resm(TINFO, "block 3 FAILED"); 254 } else { 255 tst_resm(TINFO, "block 3 PASSED"); 256 } 257 tst_resm(TINFO, "Exit block 3"); 258 } 259 close(fd[0]); 260 close(fd[1]); 261 cleanup(); 262 tst_exit(); 263 } 264 265 #else 266 267 int main(void) 268 { 269 tst_resm(TINFO, "test is not available on uClinux"); 270 tst_exit(); 271 } 272 273 #endif /* if !defined(UCLINUX) */ 274 275 /* 276 * setup() 277 * performs all ONE TIME setup for this test 278 */ 279 void setup(void) 280 { 281 282 tst_sig(FORK, DEF_HANDLER, cleanup); 283 284 TEST_PAUSE; 285 286 /* Create a unique temporary directory and chdir() to it. */ 287 tst_tmpdir(); 288 289 strcpy(name, DATA_FILE); 290 sprintf(f_name, "%s.%d", name, getpid()); 291 292 bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 293 if (bad_addr == MAP_FAILED) { 294 tst_brkm(TBROK, cleanup, "mmap failed"); 295 } 296 wr_iovec[1].iov_base = bad_addr; 297 298 } 299 300 /* 301 * cleanup() 302 * performs all ONE TIME cleanup for this test at 303 * completion or premature exit 304 */ 305 void cleanup(void) 306 { 307 308 if (unlink(f_name) < 0) { 309 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 310 f_name, errno); 311 } 312 tst_rmdir(); 313 314 } 315 316 /* 317 * sighandler() 318 * Signal handler function for SIGTERM and SIGPIPE 319 */ 320 void sighandler(int sig) 321 { 322 switch (sig) { 323 case SIGTERM: 324 break; 325 case SIGPIPE: 326 ++in_sighandler; 327 return; 328 default: 329 tst_resm(TFAIL, "sighandler() received invalid signal " 330 ": %d", sig); 331 break; 332 } 333 334 if ((unlink(f_name) < 0) && (errno != ENOENT)) { 335 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 336 f_name, errno); 337 cleanup(); 338 } 339 exit(sig); 340 } 341 342 /* 343 * l_seek() 344 * Wrap around for regular lseek function for giving error message 345 */ 346 long l_seek(int fdesc, long offset, int whence) 347 { 348 if (lseek(fdesc, offset, whence) < 0) { 349 tst_resm(TFAIL, "lseek Failed : errno = %d", errno); 350 fail = 1; 351 } 352 return 0; 353 } 354