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 63char buf1[K_1]; 64char buf2[K_1]; 65char buf3[K_1]; 66 67char *bad_addr = 0; 68 69struct iovec wr_iovec[MAX_IOVEC] = { 70 {(caddr_t) - 1, CHUNK}, 71 {NULL, 0} 72}; 73 74char name[K_1], f_name[K_1]; 75int fd[2], in_sighandler; 76char *buf_list[NBUFS]; 77 78char *TCID = "writev05"; 79int TST_TOTAL = 1; 80 81void sighandler(int); 82long l_seek(int, long, int); 83void setup(void); 84void cleanup(void); 85 86#if !defined(UCLINUX) 87 88int main(int argc, char **argv) 89{ 90 int lc; 91 92 int nbytes; 93 94 tst_parse_opts(argc, argv, NULL, NULL); 95 96 setup(); /* set "tstdir", and "testfile" vars */ 97 98 /* The following loop checks looping state if -i option given */ 99 for (lc = 0; TEST_LOOPING(lc); lc++) { 100 101 /* reset tst_count in case we are looping */ 102 tst_count = 0; 103 104 buf_list[0] = buf1; 105 buf_list[1] = buf2; 106 107 fd[1] = -1; /* Invalid file descriptor */ 108 109 if (signal(SIGTERM, sighandler) == SIG_ERR) { 110 perror("signal"); 111 tst_resm(TFAIL, "signal() SIGTERM FAILED"); 112 cleanup(); 113 } 114 115 if (signal(SIGPIPE, sighandler) == SIG_ERR) { 116 perror("signal"); 117 tst_resm(TFAIL, "signal() SIGPIPE FAILED"); 118 cleanup(); 119 } 120 121 /* Fill the buf_list[0] and buf_list[1] with 0 zeros */ 122 memset(buf_list[0], 0, K_1); 123 memset(buf_list[1], 0, K_1); 124 125 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) { 126 tst_resm(TFAIL, "open(2) failed: fname = %s, " 127 "errno = %d", f_name, errno); 128 cleanup(); 129 } else { 130 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) { 131 tst_resm(TFAIL, "write(2) failed: nbytes " 132 "= %d, errno = %d", nbytes, errno); 133 cleanup(); 134 } 135 } 136 137 if (close(fd[0]) < 0) { 138 tst_resm(TFAIL, "close failed: errno = %d", errno); 139 cleanup(); 140 } 141 142 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) { 143 tst_resm(TFAIL, "open failed: fname = %s, errno = %d", 144 f_name, errno); 145 cleanup(); 146 } 147 148 /* 149 * In this block we are trying to call writev() with invalid 150 * vector to be written in a sparse file. This will return 151 * EFAULT. At the same time, check should be made whether 152 * the scheduled write() with valid data is done correctly 153 * or not. 154 */ 155 l_seek(fd[0], 0, 0); 156 TEST(writev(fd[0], wr_iovec, 2)); 157 if (TEST_RETURN < 0) { 158 if (TEST_ERRNO == EFAULT) { 159 tst_resm(TPASS, "Received EFAULT as expected"); 160 } else { 161 tst_resm(TFAIL, "Expected EFAULT, got %d", 162 TEST_ERRNO); 163 } 164 l_seek(fd[0], K_1, 0); 165 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 0) { 166 tst_resm(TFAIL, "Expected nbytes = 0, got " 167 "%d", nbytes); 168 } 169 } else { 170 tst_resm(TFAIL, "Error writev returned a positive " 171 "value"); 172 } 173 } 174 close(fd[0]); 175 close(fd[1]); 176 cleanup(); 177 tst_exit(); 178 179} 180 181#else 182 183int main(void) 184{ 185 tst_resm(TINFO, "test is not available on uClinux"); 186 tst_exit(); 187} 188 189#endif /* if !defined(UCLINUX) */ 190 191/* 192 * setup() 193 * performs all ONE TIME setup for this test 194 */ 195void setup(void) 196{ 197 198 tst_sig(FORK, DEF_HANDLER, cleanup); 199 200 /* Pause if that option was specified. 201 * TEST_PAUSE contains the code to fork the test with the -i option. 202 * You want to make sure you do this before you create your temporary 203 * directory. 204 */ 205 TEST_PAUSE; 206 207 /* Create a unique temporary directory and chdir() to it. */ 208 tst_tmpdir(); 209 210 strcpy(name, DATA_FILE); 211 sprintf(f_name, "%s.%d", name, getpid()); 212 213 bad_addr = mmap(0, 1, PROT_NONE, 214 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 215 if (bad_addr == MAP_FAILED) { 216 printf("mmap failed\n"); 217 } 218 wr_iovec[0].iov_base = bad_addr; 219 220} 221 222/* 223 * cleanup() 224 * performs all ONE TIME cleanup for this test at 225 * completion or premature exit 226 */ 227void cleanup(void) 228{ 229 230 if (unlink(f_name) < 0) { 231 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 232 f_name, errno); 233 } 234 tst_rmdir(); 235 236} 237 238/* 239 * sighandler() 240 * Signal handler for SIGTERM and SIGPIPE 241 */ 242void sighandler(int sig) 243{ 244 switch (sig) { 245 case SIGTERM: 246 break; 247 case SIGPIPE: 248 ++in_sighandler; 249 return; 250 default: 251 tst_resm(TFAIL, "sighandler() received invalid signal " 252 ": %d", sig); 253 break; 254 } 255 256 if ((unlink(f_name) < 0) && (errno != ENOENT)) { 257 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d", 258 f_name, errno); 259 cleanup(); 260 } 261 exit(sig); 262} 263 264/* 265 * l_seek() 266 * Wrap around for regular lseek() to give error message on failure 267 */ 268long l_seek(int fdesc, long offset, int whence) 269{ 270 if (lseek(fdesc, offset, whence) < 0) { 271 tst_resm(TFAIL, "lseek Failed : errno = %d", errno); 272 } 273 return 0; 274} 275