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 #include "safe_macros.h"
     82 
     83 #define _XOPEN_SOURCE 500
     84 #define TEMPFILE	"pwrite_file"
     85 #define K1              1024
     86 #define K2              (K1 * 2)
     87 #define K3              (K1 * 3)
     88 #define K4              (K1 * 4)
     89 #define NBUFS           4
     90 
     91 char *TCID = "pwrite01";
     92 int TST_TOTAL = 1;
     93 int fildes;			/* file descriptor for tempfile */
     94 char *write_buf[NBUFS];		/* buffer to hold data to be written */
     95 
     96 void setup();			/* Main setup function of test */
     97 void cleanup();			/* cleanup function for the test */
     98 void l_seek(int, off_t, int, off_t);	/* function to call lseek() */
     99 void init_buffers();		/* function to initialize/allocate buffers */
    100 void check_file_contents();	/* function to verify the contents of file */
    101 
    102 int main(int ac, char **av)
    103 {
    104 	int lc;
    105 	int nwrite;		/* no. of bytes written by pwrite() */
    106 
    107 	tst_parse_opts(ac, av, NULL, NULL);
    108 
    109 	setup();
    110 
    111 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    112 
    113 		tst_count = 0;
    114 
    115 		/*
    116 		 * Call pwrite() to write K1 bytes of data (0's) at offset 0
    117 		 * of temporary file
    118 		 */
    119 		nwrite = pwrite(fildes, write_buf[0], K1, 0);
    120 
    121 		/* Check for the return value of pwrite() */
    122 		if (nwrite != K1) {
    123 			tst_resm(TFAIL, "pwrite() at offset 0 failed, errno=%d "
    124 				 ": %s", errno, strerror(errno));
    125 			continue;
    126 		}
    127 
    128 		/* We should still be at offset 0. */
    129 		l_seek(fildes, 0, SEEK_CUR, 0);
    130 
    131 		/*
    132 		 * Now, lseek() to a non K boundary,
    133 		 * just to be different.
    134 		 */
    135 		l_seek(fildes, K1 / 2, SEEK_SET, K1 / 2);
    136 
    137 		/*
    138 		 * Again, pwrite() K1 of data (2's) at offset K2 of
    139 		 * temporary file.
    140 		 */
    141 		nwrite = pwrite(fildes, write_buf[2], K1, K2);
    142 		if (nwrite != K1) {
    143 			tst_resm(TFAIL, "pwrite() failed to "
    144 				 "write at %d off. on %s, errno=%d : %s",
    145 				 K2, TEMPFILE, errno, strerror(errno));
    146 			continue;
    147 		}
    148 
    149 		/* We should still be at our non K boundary. */
    150 		l_seek(fildes, 0, SEEK_CUR, K1 / 2);
    151 
    152 		/* lseek() to an offset of K3. */
    153 		l_seek(fildes, K3, SEEK_SET, K3);
    154 
    155 		/*
    156 		 * Using write(), write of K1 of data (3's) which
    157 		 * should take place at an offset of K3,
    158 		 * moving the file pointer to K4.
    159 		 */
    160 		nwrite = write(fildes, write_buf[3], K1);
    161 		if (nwrite != K1) {
    162 			tst_resm(TFAIL, "write() failed: nwrite=%d, errno=%d : "
    163 				 "%s", nwrite, errno, strerror(errno));
    164 			continue;
    165 		}
    166 
    167 		/* We should be at offset K4. */
    168 		l_seek(fildes, 0, SEEK_CUR, K4);
    169 
    170 		/* Again, pwrite() K1 of data (1's) at offset K1. */
    171 		nwrite = pwrite(fildes, write_buf[1], K1, K1);
    172 		if (nwrite != K1) {
    173 			tst_resm(TFAIL, "pwrite() failed to write at "
    174 				 "%d off. on %s, errno=%d : %s",
    175 				 K1, TEMPFILE, errno, strerror(errno));
    176 			continue;
    177 		}
    178 
    179 		/*
    180 		 * Check the contents of temporary file
    181 		 * to which data written using pwrite().
    182 		 * Compare the data read with the original
    183 		 * write_buf[] contents.
    184 		 */
    185 		check_file_contents();
    186 
    187 		/* reset to offset 0 in case we are looping */
    188 		l_seek(fildes, 0, SEEK_SET, 0);
    189 
    190 	}
    191 
    192 	cleanup();
    193 	tst_exit();
    194 }
    195 
    196 /*
    197  * setup() - performs all ONE TIME setup for this test.
    198  *
    199  *  Initialize/allocate read/write buffers.
    200  *  Create a temporary directory and a file under it and
    201  */
    202 void setup(void)
    203 {
    204 
    205 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    206 
    207 	TEST_PAUSE;
    208 
    209 	/* Allocate/Initialize the write buffer with known data */
    210 	init_buffers();
    211 
    212 	tst_tmpdir();
    213 
    214 	/* Creat a temporary file used for mapping */
    215 	if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) {
    216 		tst_brkm(TBROK, cleanup, "open() on %s Failed, errno=%d : %s",
    217 			 TEMPFILE, errno, strerror(errno));
    218 	}
    219 }
    220 
    221 /*
    222  * init_buffers() - allocate/Initialize write_buf array.
    223  *
    224  *  Allocate write buffer.
    225  *  Fill the write buffer with the following data like,
    226  *    write_buf[0] has 0's, write_buf[1] has 1's, write_buf[2] has 2's
    227  *    write_buf[3] has 3's.
    228  */
    229 void init_buffers(void)
    230 {
    231 	int count;		/* counter variable for loop */
    232 
    233 	/* Allocate and Initialize write buffer with known data */
    234 	for (count = 0; count < NBUFS; count++) {
    235 		write_buf[count] = malloc(K1);
    236 
    237 		if (write_buf[count] == NULL) {
    238 			tst_brkm(TBROK, NULL, "malloc() failed ");
    239 		}
    240 		memset(write_buf[count], count, K1);
    241 	}
    242 }
    243 
    244 /*
    245  * l_seek() - local front end to lseek().
    246  *
    247  *  "checkoff" is the offset at which we believe we should be at.
    248  *  Used to validate pread/pwrite don't move the offset.
    249  */
    250 void l_seek(int fdesc, off_t offset, int whence, off_t checkoff)
    251 {
    252 	off_t offloc;		/* offset ret. from lseek() */
    253 
    254 	if ((offloc = lseek(fdesc, offset, whence)) != checkoff) {
    255 		tst_resm(TWARN, "lseek returned %" PRId64 ", expected %" PRId64,
    256 			 (int64_t) offloc, (int64_t) checkoff);
    257 		tst_brkm(TBROK | TERRNO, cleanup, "lseek() on %s Failed",
    258 			 TEMPFILE);
    259 	}
    260 }
    261 
    262 /*
    263  * check_file_contents() - Check the contents of the file we wrote with
    264  *			   pwrite()'s.
    265  *  The contents of the file are verified by using a plain read() and
    266  *  Compare the data read with the original write_buf[] contents.
    267  */
    268 void check_file_contents(void)
    269 {
    270 	int count, err_flg = 0;	/* index variable and error flag */
    271 	int nread;		/* return value of read() */
    272 	off_t offloc;		/* offset. ret. by lseek() */
    273 	char *read_buf;		/* buffer to hold read data */
    274 
    275 	/* Allocate space for read buffer */
    276 	read_buf = malloc(K1);
    277 	if (read_buf == NULL) {
    278 		tst_brkm(TBROK, cleanup, "malloc() failed on read buffer");
    279 	}
    280 
    281 	/* Seek to app. location of file and read the data, compare it */
    282 	for (count = 0; count < NBUFS; count++) {
    283 		/* Seek to specified offset position from beginning */
    284 		offloc = lseek(fildes, count * K1, SEEK_SET);
    285 		if (offloc != (count * K1)) {
    286 			tst_brkm(TBROK | TERRNO, cleanup,
    287 				 "lseek() failed: offloc=%" PRId64,
    288 				 (int64_t) offloc);
    289 		}
    290 
    291 		/* Read the data from file into a buffer */
    292 		nread = read(fildes, read_buf, K1);
    293 		if (nread != K1) {
    294 			tst_brkm(TBROK | TERRNO, cleanup,
    295 				 "read() failed: nread=%d", nread);
    296 		}
    297 
    298 		/* Compare the read data with the data written using pwrite */
    299 		if (memcmp(write_buf[count], read_buf, K1) != 0) {
    300 			tst_resm(TFAIL, "read/write buffer data mismatch");
    301 			err_flg++;
    302 		}
    303 	}
    304 
    305 	/* If no erros, Test successful */
    306 	if (!err_flg) {
    307 		tst_resm(TPASS, "Functionality of pwrite() successful");
    308 	}
    309 
    310 	/* Release the memory allocated before return */
    311 	free(read_buf);
    312 }
    313 
    314 /*
    315  * cleanup() - performs all ONE TIME cleanup for this test at
    316  *             completion or premature exit.
    317  *
    318  * Deallocate the memory allocated to write buffer.
    319  * Close the temporary file.
    320  * Remove the temporary directory created.
    321  */
    322 void cleanup(void)
    323 {
    324 	int count;
    325 
    326 	/* Free the memory allocated for the write buffer */
    327 	for (count = 0; count < NBUFS; count++) {
    328 		free(write_buf[count]);
    329 	}
    330 
    331 	/* Close the temporary file */
    332 	SAFE_CLOSE(NULL, fildes);
    333 
    334 	tst_rmdir();
    335 
    336 }
    337