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 * writev02.c 23 * 24 * DESCRIPTION 25 * In these testcases, writev() is called with partially valid data 26 * to be written in a sparse file. 27 * 28 * ALGORITHM 29 * The file is created and write() is called with valid buffer to write 30 * at some 8k th offset. After that writev() will be called with invalid 31 * vector. This should return EFAULT. And at the same time, try looking at 32 * the 8kth offset whether the file is intact or not. 33 * 34 * USAGE: <for command-line> 35 * writev02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 36 * where, -c n : Run n copies concurrently. 37 * -e : Turn on errno logging. 38 * -i n : Execute test n times. 39 * -I x : Execute test for x seconds. 40 * -P x : Pause for x seconds between iterations. 41 * -t : Turn on syscall timing. 42 * 43 * History 44 * 07/2001 John George 45 * -Ported 46 * 04/2002 wjhuie sigset cleanups 47 * 48 * Restrictions 49 * None 50 */ 51 52 #include <sys/types.h> 53 #include <signal.h> 54 #include <sys/uio.h> 55 #include <fcntl.h> 56 #include <memory.h> 57 #include <errno.h> 58 #include "test.h" 59 #include <sys/mman.h> 60 61 #define K_1 8192 62 63 #define NBUFS 2 64 #define CHUNK K_1 /* single chunk */ 65 #define MAX_IOVEC 2 66 #define DATA_FILE "writev_data_file" 67 68 char buf1[K_1]; 69 char buf2[K_1]; 70 71 char *bad_addr = 0; 72 73 struct iovec wr_iovec[MAX_IOVEC] = { 74 {(caddr_t) - 1, CHUNK}, 75 {NULL, 0}, 76 }; 77 78 char name[K_1], f_name[K_1]; 79 80 int fd[2], in_sighandler; 81 char *buf_list[NBUFS]; 82 83 char *TCID = "writev02"; 84 int TST_TOTAL = 1; 85 86 void sighandler(int); 87 void l_seek(int, off_t, int); 88 void setup(void); 89 void cleanup(void); 90 int fail; 91 92 int main(int argc, char **argv) 93 { 94 int lc; 95 96 int nbytes; 97 98 tst_parse_opts(argc, argv, NULL, NULL); 99 100 setup(); 101 102 for (lc = 0; TEST_LOOPING(lc); lc++) { 103 104 tst_count = 0; 105 106 buf_list[0] = buf1; 107 buf_list[1] = buf2; 108 109 memset(buf_list[0], 0, K_1); 110 memset(buf_list[1], 0, K_1); 111 112 fd[1] = -1; /* Invalid file descriptor */ 113 114 if (signal(SIGTERM, sighandler) == SIG_ERR) 115 tst_brkm(TFAIL | TERRNO, cleanup, 116 "signal(SIGTERM, ..)"); 117 118 if (signal(SIGPIPE, sighandler) == SIG_ERR) 119 tst_brkm(TFAIL | TERRNO, cleanup, 120 "signal(SIGPIPE, ..)"); 121 122 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) 123 tst_brkm(TFAIL | TERRNO, cleanup, 124 "open(.., O_WRONLY|O_CREAT, ..) failed"); 125 else { 126 l_seek(fd[0], K_1, 0); 127 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) 128 tst_brkm(TFAIL | TERRNO, cleanup, 129 "write failed"); 130 } 131 132 if (close(fd[0]) == -1) 133 tst_brkm(TFAIL | TERRNO, cleanup, "close failed"); 134 135 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) 136 tst_brkm(TFAIL | TERRNO, cleanup, 137 "open(.., O_RDWR, ..) failed"); 138 //block1: 139 /* 140 * In this block we are trying to call writev() with invalid 141 * vector to be written in a sparse file. This will return 142 * EFAULT. At the same time, check should be made whether 143 * the scheduled write() with valid data at 8k th offset is 144 * done correctly or not. 145 */ 146 tst_resm(TINFO, "Enter block 1"); 147 148 l_seek(fd[0], 0, 0); 149 TEST(writev(fd[0], wr_iovec, 2)); 150 if (TEST_RETURN < 0) { 151 if (TEST_ERRNO == EFAULT) { 152 tst_resm(TPASS, "Received EFAULT as expected"); 153 } else if (TEST_ERRNO != EFAULT) { 154 tst_resm(TFAIL, "Expected EFAULT, got %d", 155 TEST_ERRNO); 156 } 157 l_seek(fd[0], K_1, 0); 158 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != CHUNK) { 159 tst_resm(TFAIL, "Expected nbytes = 64, got " 160 "%d", nbytes); 161 } else { 162 if (memcmp(buf_list[0], buf_list[1], CHUNK) 163 != 0) 164 tst_resm(TFAIL, "Error: writev() " 165 "over wrote %s", f_name); 166 } 167 } else 168 tst_resm(TFAIL, "Error writev returned a positive " 169 "value"); 170 tst_resm(TINFO, "Exit block 1"); 171 } 172 cleanup(); 173 tst_exit(); 174 } 175 176 void setup(void) 177 { 178 tst_sig(FORK, sighandler, cleanup); 179 180 TEST_PAUSE; 181 182 tst_tmpdir(); 183 184 strcpy(name, DATA_FILE); 185 sprintf(f_name, "%s.%d", name, getpid()); 186 187 bad_addr = mmap(0, 1, PROT_NONE, 188 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 189 if (bad_addr == MAP_FAILED) 190 tst_brkm(TBROK | TERRNO, cleanup, "mmap failed"); 191 wr_iovec[0].iov_base = bad_addr; 192 193 } 194 195 void cleanup(void) 196 { 197 close(fd[0]); 198 close(fd[1]); 199 200 if (munmap(bad_addr, 1) == -1) 201 tst_resm(TWARN | TERRNO, "unmap failed"); 202 if (unlink(f_name) == -1) 203 tst_resm(TWARN | TERRNO, "unlink failed"); 204 205 tst_rmdir(); 206 207 } 208 209 void sighandler(int sig) 210 { 211 switch (sig) { 212 case SIGTERM: 213 break; 214 case SIGPIPE: 215 ++in_sighandler; 216 return; 217 default: 218 tst_resm(TBROK, "sighandler received invalid signal : %d", sig); 219 break; 220 } 221 222 if (unlink(f_name) == -1 && errno != ENOENT) 223 tst_resm(TFAIL | TERRNO, "unlink failed"); 224 } 225 226 /* 227 * l_seek() 228 * Wrap around for regular lseek function for giving error message 229 */ 230 void l_seek(int fdesc, off_t offset, int whence) 231 { 232 if (lseek(fdesc, offset, whence) == -1) 233 tst_resm(TBROK | TERRNO, "lseek failed"); 234 } 235