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 * readv02.c 23 * 24 * DESCRIPTION 25 * Testcase to check the error conditions of the readv(2) system call. 26 * 27 * CALLS 28 * readv() 29 * 30 * ALGORITHM 31 * Create a IO vector, and attempt to readv() various components of it. 32 * 33 * USAGE 34 * readv02 35 * 36 * HISTORY 37 * 07/2001 Ported by Wayne Boyer 38 * 39 * RESTRICTIONS 40 * None 41 */ 42 #include <sys/types.h> 43 #include <sys/uio.h> 44 #include <fcntl.h> 45 #include <sys/mman.h> 46 #include <memory.h> 47 #include <errno.h> 48 49 #include "test.h" 50 #include "safe_macros.h" 51 52 #define K_1 1024 53 #define M_1 K_1 * K_1 54 #define G_1 M_1 * K_1 55 56 #define NBUFS 4 57 #define CHUNK 64 58 #define MAX_IOVEC 16 59 #define DATA_FILE "readv_data_file" 60 61 char buf1[K_1], buf2[K_1], buf3[K_1]; 62 63 struct iovec rd_iovec[MAX_IOVEC] = { 64 /* iov_base *//* iov_len */ 65 66 /* Test case #1 */ 67 {buf2, -1}, 68 {(buf2 + CHUNK), CHUNK}, 69 {(buf2 + CHUNK * 2), CHUNK}, 70 71 /* Test case #2 */ 72 {(buf2 + CHUNK * 3), G_1}, 73 {(buf2 + CHUNK * 4), G_1}, 74 {(buf2 + CHUNK * 5), G_1}, 75 76 /* Test case #3 */ 77 {(caddr_t) - 1, CHUNK}, 78 {(buf2 + CHUNK * 6), CHUNK}, 79 {(buf2 + CHUNK * 8), CHUNK}, 80 81 /* Test case #4 */ 82 {(buf2 + CHUNK * 9), CHUNK} 83 }; 84 85 char f_name[K_1]; 86 87 int fd[4]; 88 char *buf_list[NBUFS]; 89 90 char *TCID = "readv02"; 91 int TST_TOTAL = 1; 92 93 char *bad_addr = 0; 94 95 int init_buffs(char **); 96 int fill_mem(char *, int, int); 97 long l_seek(int, long, int); 98 char *getenv(); 99 void setup(); 100 void cleanup(); 101 102 int main(int ac, char **av) 103 { 104 int lc; 105 106 tst_parse_opts(ac, av, NULL, NULL); 107 108 setup(); 109 110 /* The following loop checks looping state if -i option given */ 111 for (lc = 0; TEST_LOOPING(lc); lc++) { 112 113 /* reset tst_count in case we are looping */ 114 tst_count = 0; 115 116 //test1: 117 if (readv(fd[0], rd_iovec, 1) < 0) { 118 if (errno != EINVAL) { 119 tst_resm(TFAIL, "readv() set an illegal errno:" 120 " expected: EINVAL, got %d", errno); 121 } else { 122 tst_resm(TPASS, "got EINVAL"); 123 } 124 } else { 125 tst_resm(TFAIL, "Error: readv returned a positive " 126 "value"); 127 } 128 129 //test2: 130 l_seek(fd[0], CHUNK * 6, 0); 131 if (readv(fd[0], (rd_iovec + 6), 3) < 0) { 132 if (errno != EFAULT) { 133 tst_resm(TFAIL, "expected errno = EFAULT, " 134 "got %d", errno); 135 } else { 136 tst_resm(TPASS, "got EFAULT"); 137 } 138 if (memcmp((buf_list[0] + CHUNK * 6), 139 (buf_list[1] + CHUNK * 6), CHUNK * 3) != 0) { 140 tst_resm(TFAIL, "Error: readv() partially " 141 "overlaid buf[2]"); 142 } 143 } else { 144 tst_resm(TFAIL, "Error: readv returned a positive " 145 "value"); 146 } 147 148 //test3: 149 if (readv(fd[1], (rd_iovec + 9), 1) < 0) { 150 if (errno != EBADF) { 151 tst_resm(TFAIL, "expected errno = EBADF, " 152 "got %d", errno); 153 } else { 154 tst_resm(TPASS, "got EBADF"); 155 } 156 } else { 157 tst_resm(TFAIL, "Error: readv returned a positive " 158 "value"); 159 } 160 161 //test4: 162 l_seek(fd[0], CHUNK * 10, 0); 163 if (readv(fd[0], (rd_iovec + 10), -1) < 0) { 164 if (errno != EINVAL) { 165 tst_resm(TFAIL, "expected errno = EINVAL, " 166 "got %d", errno); 167 } else { 168 tst_resm(TPASS, "got EINVAL"); 169 } 170 } else { 171 tst_resm(TFAIL, "Error: readv returned a positive " 172 "value"); 173 } 174 175 } 176 close(fd[0]); 177 close(fd[1]); 178 cleanup(); 179 tst_exit(); 180 181 } 182 183 /* 184 * setup() - performs all ONE TIME setup for this test. 185 */ 186 void setup(void) 187 { 188 int nbytes; 189 190 tst_sig(NOFORK, DEF_HANDLER, cleanup); 191 192 TEST_PAUSE; 193 194 /* make a temporary directory and cd to it */ 195 tst_tmpdir(); 196 197 buf_list[0] = buf1; 198 buf_list[1] = buf2; 199 buf_list[2] = buf3; 200 buf_list[3] = NULL; 201 202 init_buffs(buf_list); 203 204 sprintf(f_name, "%s.%d", DATA_FILE, getpid()); 205 206 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) { 207 tst_brkm(TBROK, cleanup, "open failed: fname = %s, " 208 "errno = %d", f_name, errno); 209 } else { 210 if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) { 211 tst_brkm(TBROK, cleanup, "write failed: nbytes " 212 "= %d " "errno = %d", nbytes, errno); 213 } 214 } 215 216 SAFE_CLOSE(cleanup, fd[0]); 217 218 if ((fd[0] = open(f_name, O_RDONLY, 0666)) < 0) { 219 tst_brkm(TBROK, cleanup, "open failed: fname = %s, " 220 "errno = %d", f_name, errno); 221 } 222 223 fd[1] = -1; /* Invalid file descriptor */ 224 225 bad_addr = mmap(0, 1, PROT_NONE, 226 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 227 if (bad_addr == MAP_FAILED) { 228 tst_brkm(TBROK, cleanup, "mmap failed"); 229 } 230 rd_iovec[6].iov_base = bad_addr; 231 } 232 233 /* 234 * cleanup() - performs all ONE TIME cleanup for this test at 235 * completion or premature exit. 236 */ 237 void cleanup(void) 238 { 239 SAFE_UNLINK(NULL, f_name); 240 tst_rmdir(); 241 242 } 243 244 int init_buffs(char *pbufs[]) 245 { 246 int i; 247 248 for (i = 0; pbufs[i] != NULL; i++) { 249 switch (i) { 250 case 0: 251 /*FALLTHROUGH*/ case 1: 252 fill_mem(pbufs[i], 0, 1); 253 break; 254 255 case 2: 256 fill_mem(pbufs[i], 1, 0); 257 break; 258 259 default: 260 tst_brkm(TBROK, cleanup, "Error in init_buffs()"); 261 } 262 } 263 return 0; 264 } 265 266 int fill_mem(char *c_ptr, int c1, int c2) 267 { 268 int count; 269 270 for (count = 1; count <= K_1 / CHUNK; count++) { 271 if (count & 0x01) { /* if odd */ 272 memset(c_ptr, c1, CHUNK); 273 } else { /* if even */ 274 memset(c_ptr, c2, CHUNK); 275 } 276 } 277 return 0; 278 } 279 280 long l_seek(int fdesc, long offset, int whence) 281 { 282 SAFE_LSEEK(cleanup, fdesc, offset, whence); 283 return 0; 284 } 285