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 * Test Name: pread01 22 * 23 * Test Description: 24 * Verify the functionality of pread() by writing known data using pwrite() 25 * to the file at various specified offsets and later read from the file from 26 * various specified offsets, comparing the data read aganist the data 27 * written. 28 * 29 * Expected Result: 30 * pread() should succeed to read the expected no. of bytes of data and 31 * the data read should match aganist the data written to the file. 32 * 33 * Algorithm: 34 * Setup: 35 * Setup signal handling. 36 * Create temporary directory. 37 * Pause for SIGUSR1 if option specified. 38 * 39 * Test: 40 * Loop if the proper options are given. 41 * Execute system call 42 * Check return code, if system call failed (return=-1) 43 * Issue a FAIL message. 44 * Otherwise, 45 * Verify the Functionality of system call 46 * if successful, 47 * Issue Functionality-Pass message. 48 * Otherwise, 49 * Issue Functionality-Fail message. 50 * Cleanup: 51 * Print errno log and/or timing stats if options given 52 * Delete the temporary directory created. 53 * 54 * Usage: <for command-line> 55 * pread01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] 56 * where, -c n : Run n copies concurrently. 57 * -f : Turn off functionality Testing. 58 * -i n : Execute test n times. 59 * -I x : Execute test for x seconds. 60 * -P x : Pause for x seconds between iterations. 61 * -t : Turn on syscall timing. 62 * 63 * HISTORY 64 * 07/2001 Ported by Wayne Boyer 65 * 66 * RESTRICTIONS: 67 * None. 68 */ 69 70 #define _XOPEN_SOURCE 500 71 72 #include <stdlib.h> 73 #include <errno.h> 74 #include <unistd.h> 75 #include <fcntl.h> 76 #include <inttypes.h> 77 78 #include "test.h" 79 #include "safe_macros.h" 80 81 #define TEMPFILE "pread_file" 82 #define K1 1024 83 #define K2 (K1 * 2) 84 #define K3 (K1 * 3) 85 #define K4 (K1 * 4) 86 #define NBUFS 4 87 88 char *TCID = "pread01"; 89 int TST_TOTAL = 1; 90 91 int fildes; /* file descriptor for tempfile */ 92 char *write_buf[NBUFS]; /* buffer to hold data to be written */ 93 char *read_buf[NBUFS]; /* buffer to hold data read from file */ 94 95 void setup(); /* Main setup function of test */ 96 void cleanup(); /* cleanup function for the test */ 97 void l_seek(int, off_t, int, off_t); /* function to call lseek() */ 98 void init_buffers(); /* function to initialize/allocate buffers */ 99 void compare_bufers(); /* function to compare o/p of pread/pwrite */ 100 101 int main(int ac, char **av) 102 { 103 int lc; 104 int nread; /* no. of bytes read by pread() */ 105 106 tst_parse_opts(ac, av, NULL, NULL); 107 108 setup(); 109 110 for (lc = 0; TEST_LOOPING(lc); lc++) { 111 112 /* Reset tst_count in case we are looping */ 113 tst_count = 0; 114 115 /* 116 * Call pread() of K1 data (should be 2's) at offset K2. 117 */ 118 nread = pread(fildes, read_buf[2], K1, K2); 119 120 /* Check for the return value of pread() */ 121 if (nread != K1) { 122 tst_brkm(TFAIL, cleanup, "pread() at off. K2 failed: " 123 "nread=%d, error:%d", nread, errno); 124 } 125 126 /* 127 * We should still be at offset K4, 128 * which we were at the end of block 0. 129 */ 130 l_seek(fildes, 0, SEEK_CUR, K4); 131 132 /* Now lseek() to offset 0. */ 133 l_seek(fildes, 0, SEEK_SET, 0); 134 135 /* pread() K1 of data (should be 3's) at offset K3. */ 136 nread = pread(fildes, read_buf[3], K1, K3); 137 if (nread != K1) { 138 tst_brkm(TFAIL, cleanup, "pread() at off. K3 failed: " 139 "nread=%d, error:%d", nread, errno); 140 } 141 142 /* We should still be at offset 0. */ 143 l_seek(fildes, 0, SEEK_CUR, 0); 144 145 /* 146 * Do a normal read() of K1 data (should be 0's) 147 * which should take place at offset 0 and move the 148 * file pointer to an offset of K1. 149 */ 150 if ((nread = read(fildes, read_buf[0], K1)) != K1) { 151 tst_brkm(TFAIL, cleanup, "read() at off. 0 failed: " 152 "nread=%d, errno=%d", nread, errno); 153 } 154 155 /* We should now be at an offset of K1. */ 156 l_seek(fildes, 0, SEEK_CUR, K1); 157 158 /* pread() of K1 data (should be 1's) at offset K1. */ 159 nread = pread(fildes, read_buf[1], K1, K1); 160 if (nread != K1) { 161 tst_brkm(TFAIL, cleanup, "pread() at off. K1 failed: " 162 "nread=%d, error:%d", nread, errno); 163 } 164 165 /* We should still be at offset K1. */ 166 l_seek(fildes, 0, SEEK_CUR, K1); 167 168 /* 169 * Compare the read buffer data read 170 * with the data written to write buffer 171 * in the setup. 172 */ 173 compare_bufers(); 174 175 /* reset our location to offset K4 in case we are looping */ 176 l_seek(fildes, K4, SEEK_SET, K4); 177 } 178 179 cleanup(); 180 tst_exit(); 181 } 182 183 /* 184 * setup() - performs all ONE TIME setup for this test. 185 * 186 * Initialize/allocate read/write buffers. 187 * Create a temporary directory and a file under it and 188 * write know data at different offset positions. 189 */ 190 void setup(void) 191 { 192 int nwrite = 0; /* no. of bytes written by pwrite() */ 193 194 tst_sig(FORK, DEF_HANDLER, cleanup); 195 196 TEST_PAUSE; 197 198 /* Allocate/Initialize the read/write buffer with know data */ 199 init_buffers(); 200 201 tst_tmpdir(); 202 203 /* Creat a temporary file used for mapping */ 204 if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) { 205 tst_brkm(TBROK, cleanup, "open() on %s failed, errno=%d : %s", 206 TEMPFILE, errno, strerror(errno)); 207 } 208 209 /* pwrite() K1 of data (0's) at offset 0 of temporary file */ 210 if ((nwrite = pwrite(fildes, write_buf[0], K1, 0)) != K1) { 211 tst_brkm(TBROK, cleanup, "pwrite() failed to write on %s, " 212 "errno=%d : %s", TEMPFILE, errno, strerror(errno)); 213 } 214 215 /* We should still be at offset 0. */ 216 l_seek(fildes, 0, SEEK_CUR, 0); 217 218 /* Now, lseek() to a non K boundary, just to be different. */ 219 l_seek(fildes, K1 / 2, SEEK_SET, K1 / 2); 220 221 /* Again, pwrite() K1 of data (2's) at offset K2 of temporary file */ 222 if ((nwrite = pwrite(fildes, write_buf[2], K1, K2)) != K1) { 223 tst_brkm(TBROK, cleanup, "pwrite() failed to write at %d off. " 224 "on %s, errno=%d : %s", K2, TEMPFILE, errno, 225 strerror(errno)); 226 } 227 228 /* We should still be at our non K boundary. */ 229 l_seek(fildes, 0, SEEK_CUR, K1 / 2); 230 231 /* lseek() to an offset of K3. */ 232 l_seek(fildes, K3, SEEK_SET, K3); 233 234 /* 235 * Using write(), write of K1 of data (3's) which should take 236 * place at an offset of K3, moving the file pointer to K4. 237 */ 238 if ((nwrite = write(fildes, write_buf[3], K1)) != K1) { 239 tst_brkm(TBROK, cleanup, "write() failed: nwrite=%d, errno=%d " 240 ": %s", nwrite, errno, strerror(errno)); 241 } 242 243 /* We should be at offset K4. */ 244 l_seek(fildes, 0, SEEK_CUR, K4); 245 246 /* Again, pwrite() K1 of data (1's) at offset K1. */ 247 if ((nwrite = pwrite(fildes, write_buf[1], K1, K1)) != K1) { 248 tst_brkm(TBROK, cleanup, "pwrite() failed to write at %d off. " 249 "on %s, errno=%d : %s", K1, TEMPFILE, errno, 250 strerror(errno)); 251 } 252 } 253 254 /* 255 * init_buffers - allocates both write_buf and read_buf arrays. 256 * 257 * Allocate the read and write buffers. 258 * Fill the write buffer with the following data like, 259 * write_buf[0] has 0's, write_buf[1] has 1's, write_buf[2] has 2's 260 * write_buf[3] has 3's. 261 */ 262 void init_buffers(void) 263 { 264 int count; /* counter variable for loop */ 265 266 /* Allocate and Initialize read/write buffer */ 267 for (count = 0; count < NBUFS; count++) { 268 write_buf[count] = malloc(K1); 269 read_buf[count] = malloc(K1); 270 271 if ((write_buf[count] == NULL) || (read_buf[count] == NULL)) { 272 tst_brkm(TBROK, NULL, 273 "malloc() failed on read/write buffers"); 274 } 275 memset(write_buf[count], count, K1); 276 } 277 } 278 279 /* 280 * l_seek() - local front end to lseek(). 281 * 282 * "checkoff" is the offset at which we believe we should be at. 283 * Used to validate pread/pwrite don't move the offset. 284 */ 285 void l_seek(int fdesc, off_t offset, int whence, off_t checkoff) 286 { 287 off_t offloc; /* offset ret. from lseek() */ 288 289 if ((offloc = lseek(fdesc, offset, whence)) != checkoff) { 290 tst_resm(TWARN, "return = %" PRId64 ", expected %" PRId64, 291 (int64_t) offloc, (int64_t) checkoff); 292 tst_brkm(TBROK | TERRNO, cleanup, "lseek() on %s failed", 293 TEMPFILE); 294 } 295 } 296 297 /* 298 * compare_bufers() - Compare the contents of read buffer aganist the 299 * write buffer contents. 300 * 301 * The contents of the index of each buffer should be as follows: 302 * [0] has 0's, [1] has 1's, [2] has 2's, and [3] has 3's. 303 * 304 * This function does memcmp of read/write buffer and display message 305 * about the functionality of pread(). 306 */ 307 void compare_bufers(void) 308 { 309 int count; /* index for the loop */ 310 int err_flg = 0; /* flag to indicate error */ 311 312 for (count = 0; count < NBUFS; count++) { 313 if (memcmp(write_buf[count], read_buf[count], K1) != 0) { 314 tst_resm(TFAIL, "read/write buffer data mismatch"); 315 err_flg++; 316 } 317 } 318 319 /* If no erros, Test successful */ 320 if (!err_flg) { 321 tst_resm(TPASS, "Functionality of pread() is correct"); 322 } 323 } 324 325 /* 326 * cleanup() - performs all ONE TIME cleanup for this test at 327 * completion or premature exit. 328 * 329 * Deallocate the memory allocated to read/write buffers. 330 * Close the temporary file. 331 * Remove the temporary directory created. 332 */ 333 void cleanup(void) 334 { 335 int count; 336 337 /* Free the memory allocated for the read/write buffer */ 338 for (count = 0; count < NBUFS; count++) { 339 free(write_buf[count]); 340 free(read_buf[count]); 341 } 342 343 /* Close the temporary file */ 344 SAFE_CLOSE(NULL, fildes); 345 346 tst_rmdir(); 347 348 } 349