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 * writev05.c 23 * 24 * DESCRIPTION 25 * These testcases are written to test writev() on sparse files. This 26 * is same as writev02.c. But the initial write() with valid data is 27 * done at the beginning of the file. 28 * 29 * USAGE: <for command-line> 30 * writev05 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 31 * where, -c n : Run n copies concurrently. 32 * -e : Turn on errno logging. 33 * -i n : Execute test n times. 34 * -I x : Execute test for x seconds. 35 * -P x : Pause for x seconds between iterations. 36 * -t : Turn on syscall timing. 37 * 38 * History 39 * 07/2001 John George 40 * -Ported 41 * 04/2002 wjhuie sigset cleanups 42 * 43 * Restrictions 44 * NONE 45 */ 46 47 #include <sys/types.h> 48 #include <signal.h> 49 #include <sys/uio.h> 50 #include <fcntl.h> 51 #include <memory.h> 52 #include <errno.h> 53 #include "test.h" 54 #include <sys/mman.h> 55 56 #define K_1 8192 57 58 #define NBUFS 2 59 #define CHUNK K_1 /* single chunk */ 60 #define MAX_IOVEC 2 61 #define DATA_FILE "writev_data_file" 62 63 char buf1[K_1]; 64 char buf2[K_1]; 65 char buf3[K_1]; 66 67 char *bad_addr = 0; 68 69 struct iovec wr_iovec[MAX_IOVEC] = { 70 {(caddr_t) - 1, CHUNK}, 71 {NULL, 0} 72 }; 73 74 char name[K_1], f_name[K_1]; 75 int fd[2], in_sighandler; 76 char *buf_list[NBUFS]; 77 78 char *TCID = "writev05"; 79 int TST_TOTAL = 1; 80 81 void sighandler(int); 82 long l_seek(int, long, int); 83 void setup(void); 84 void cleanup(void); 85 int fail; 86 87 #if !defined(UCLINUX) 88 89 int main(int argc, char **argv) 90 { 91 int lc; 92 93 int nbytes; 94 95 tst_parse_opts(argc, argv, NULL, NULL); 96 97 setup(); /* set "tstdir", and "testfile" vars */ 98 99 /* The following loop checks looping state if -i option given */ 100 for (lc = 0; TEST_LOOPING(lc); lc++) { 101 102 /* reset tst_count in case we are looping */ 103 tst_count = 0; 104 105 buf_list[0] = buf1; 106 buf_list[1] = buf2; 107 108 fd[1] = -1; /* Invalid file descriptor */ 109 110 if (signal(SIGTERM, sighandler) == SIG_ERR) { 111 perror("signal"); 112 tst_resm(TFAIL, "signal() SIGTERM FAILED"); 113 cleanup(); 114 } 115 116 if (signal(SIGPIPE, sighandler) == SIG_ERR) { 117 perror("signal"); 118 tst_resm(TFAIL, "signal() SIGPIPE FAILED"); 119 cleanup(); 120 } 121 122 /* Fill the buf_list[0] and buf_list[1] with 0 zeros */ 123 memset(buf_list[0], 0, K_1); 124 memset(buf_list[1], 0, K_1); 125 126 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) { 127 tst_resm(TFAIL, "open(2) failed: fname = %s, " 128 "errno = %d", f_name, errno); 129 cleanup(); 130 } else { 131 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) { 132 tst_resm(TFAIL, "write(2) failed: nbytes " 133 "= %d, errno = %d", nbytes, errno); 134 cleanup(); 135 } 136 } 137 138 if (close(fd[0]) < 0) { 139 tst_resm(TFAIL, "close failed: errno = %d", errno); 140 cleanup(); 141 } 142 143 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) { 144 tst_resm(TFAIL, "open failed: fname = %s, errno = %d", 145 f_name, errno); 146 cleanup(); 147 } 148 149 /* 150 * In this block we are trying to call writev() with invalid 151 * vector to be written in a sparse file. This will return 152 * EFAULT. At the same time, check should be made whether 153 * the scheduled write() with valid data is done correctly 154 * or not. 155 */ 156 //block1: 157 tst_resm(TINFO, "Enter block 1"); 158 fail = 0; 159 160 l_seek(fd[0], 0, 0); 161 TEST(writev(fd[0], wr_iovec, 2)); 162 if (TEST_RETURN < 0) { 163 if (TEST_ERRNO == EFAULT) { 164 tst_resm(TINFO, "Received EFAULT as expected"); 165 } else { 166 tst_resm(TFAIL, "Expected EFAULT, got %d", 167 TEST_ERRNO); 168 fail = 1; 169 } 170 l_seek(fd[0], K_1, 0); 171 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 0) { 172 tst_resm(TFAIL, "Expected nbytes = 0, got " 173 "%d", nbytes); 174 fail = 1; 175 } 176 } else { 177 tst_resm(TFAIL, "Error writev returned a positive " 178 "value"); 179 fail = 1; 180 } 181 if (fail) { 182 tst_resm(TINFO, "block 1 FAILED"); 183 } else { 184 tst_resm(TINFO, "block 1 PASSED"); 185 } 186 tst_resm(TINFO, "Exit block 1"); 187 } 188 close(fd[0]); 189 close(fd[1]); 190 cleanup(); 191 tst_exit(); 192 193 } 194 195 #else 196 197 int main(void) 198 { 199 tst_resm(TINFO, "test is not available on uClinux"); 200 tst_exit(); 201 } 202 203 #endif /* if !defined(UCLINUX) */ 204 205 /* 206 * setup() 207 * performs all ONE TIME setup for this test 208 */ 209 void setup(void) 210 { 211 212 tst_sig(FORK, DEF_HANDLER, cleanup); 213 214 /* Pause if that option was specified. 215 * TEST_PAUSE contains the code to fork the test with the -i option. 216 * You want to make sure you do this before you create your temporary 217 * directory. 218 */ 219 TEST_PAUSE; 220 221 /* Create a unique temporary directory and chdir() to it. */ 222 tst_tmpdir(); 223 224 strcpy(name, DATA_FILE); 225 sprintf(f_name, "%s.%d", name, getpid()); 226 227 bad_addr = mmap(0, 1, PROT_NONE, 228 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 229 if (bad_addr == MAP_FAILED) { 230 printf("mmap failed\n"); 231 } 232 wr_iovec[0].iov_base = bad_addr; 233 234 } 235 236 /* 237 * cleanup() 238 * performs all ONE TIME cleanup for this test at 239 * completion or premature exit 240 */ 241 void cleanup(void) 242 { 243 244 if (unlink(f_name) < 0) { 245 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 246 f_name, errno); 247 } 248 tst_rmdir(); 249 250 } 251 252 /* 253 * sighandler() 254 * Signal handler for SIGTERM and SIGPIPE 255 */ 256 void sighandler(int sig) 257 { 258 switch (sig) { 259 case SIGTERM: 260 break; 261 case SIGPIPE: 262 ++in_sighandler; 263 return; 264 default: 265 tst_resm(TFAIL, "sighandler() received invalid signal " 266 ": %d", sig); 267 break; 268 } 269 270 if ((unlink(f_name) < 0) && (errno != ENOENT)) { 271 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 272 f_name, errno); 273 cleanup(); 274 } 275 exit(sig); 276 } 277 278 /* 279 * l_seek() 280 * Wrap around for regular lseek() to give error message on failure 281 */ 282 long l_seek(int fdesc, long offset, int whence) 283 { 284 if (lseek(fdesc, offset, whence) < 0) { 285 tst_resm(TFAIL, "lseek Failed : errno = %d", errno); 286 fail = 1; 287 } 288 return 0; 289 } 290