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
main(int ac,char ** av)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 */
setup(void)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 */
init_buffers(void)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 */
l_seek(int fdesc,off_t offset,int whence,off_t checkoff)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 */
compare_bufers(void)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 */
cleanup(void)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