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