blob: 35649dd400a7c13f06ca3720d5bcf4b6320a9bd1 [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 * writev03.c
23 *
24 * DESCRIPTION
25 * The testcases are written calling writev() with partially valid data
26 * to overwrite the contents, to write in the beginning and to write in
27 * the end of the file.
28 *
29 * USAGE: <for command-line>
30 * writev03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
31 * where, -c n : Run n copies concurrently.
32 * -e : Turn on errno logging.
33 * -i n : Execute test n times.
34 * -I x : Execute test for x seconds.
35 * -P x : Pause for x seconds between iterations.
36 * -t : Turn on syscall timing.
37 *
38 * History
39 * 07/2001 John George
40 * -Ported
robbiew4644c7e2002-04-26 14:33:32 +000041 * 04/2002 wjhuie sigset cleanups
plars865695b2001-08-27 22:15:12 +000042 *
43 * Restrictions
44 * NONE
45 */
46
47#include <sys/types.h>
48#include <signal.h>
49#include <sys/uio.h>
50#include <fcntl.h>
51#include <memory.h>
52#include <errno.h>
53#include <test.h>
54#include <usctest.h>
55
56#define K_1 1024
57
58#define NBUFS 4
59#define CHUNK 64 /* single chunk */
60#define MAX_IOVEC 4
61#define DATA_FILE "writev_data_file"
62
63char buf1[K_1], buf2[K_1], buf3[K_1];
64
65struct iovec wr_iovec[MAX_IOVEC] = {
66 /* testcase #1 */
67 buf1 + (CHUNK * 6), CHUNK,
68 (caddr_t)-1, CHUNK,
69 buf1 + (CHUNK * 8), CHUNK,
70 (caddr_t)NULL, 0,
71};
72
73/* 0 terminated list of expected errnos */
74int exp_enos[] = {0};
75
76char name[K_1], f_name[K_1];
77int fd[2], in_sighandler;
78char *buf_list[NBUFS];
79
80char *TCID = "writev03";
81int TST_TOTAL = 1;
82extern int Tst_count;
83
84void sighandler(int);
85long l_seek(int, long, int);
86void setup(void);
87void cleanup(void);
88int fail;
89
90main(int argc, char **argv)
91{
92 int lc; /* loop counter */
93 char *msg; /* message returned from parse_opts */
94
95 int nbytes;
96
97 /* parse standard options */
98 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
99 (char *) NULL) {
100 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
101 tst_exit();
102 /*NOTREACHED*/
103 }
104
105 /* set "tstdir", and "testfile" vars */
106 setup();
107
108 /* The following loop checks looping state if -i option given */
109 for (lc = 0; TEST_LOOPING(lc); lc++) {
110
111 /* reset Tst_count in case we are looping */
112 Tst_count = 0;
113
114 buf_list[0] = buf1;
115 buf_list[1] = buf2;
116 buf_list[2] = buf3;
117 buf_list[3] = (char *)NULL;
118
119 fd[1] = -1; /* Invalid file descriptor */
120
robbiew4644c7e2002-04-26 14:33:32 +0000121 if (signal(SIGTERM, sighandler) == SIG_ERR) {
122 perror("signal");
123 tst_resm(TFAIL, "signal() SIGTERM FAILED");
plars865695b2001-08-27 22:15:12 +0000124 cleanup();
125 /*NOTREACHED*/
126 }
127
robbiew4644c7e2002-04-26 14:33:32 +0000128 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
129 perror("signal");
130 tst_resm(TFAIL, "signal() SIGPIPE FAILED");
plars865695b2001-08-27 22:15:12 +0000131 cleanup();
132 /*NOTREACHED*/
133 }
134
135 memset(buf_list[0], 0, K_1);
136 memset(buf_list[1], 0, K_1);
137
138 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
139 tst_resm(TFAIL, "open(2) failed: fname = %s, "
140 "errno = %d", f_name, errno);
141 cleanup();
142 /*NOTREACHED*/
143 } else {
144 if ((nbytes = write(fd[0], buf_list[1], K_1)) !=
145 K_1) {
146 tst_resm(TFAIL, "write(2) failed: nbytes "
147 "= %d, errno = %d", nbytes, errno);
148 cleanup();
149 /*NOTREACHED*/
150 }
151 }
152
153 if (close(fd[0]) < 0) {
154 tst_resm(TFAIL, "close failed: errno = %d", errno);
155 cleanup();
156 /*NOTREACHED*/
157 }
158
159 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
160 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
161 f_name, errno);
162 cleanup();
163 /*NOTREACHED*/
164 }
165
166block1:
167 tst_resm(TINFO, "Enter block 1");
168 fail = 0;
169
170 /*
171 * In this block we are trying to call writev() with
172 * partially valid data. This should return the valid number
173 * of bytes written in the vector. If it returns EFAULT, it
174 * is an error. And after returning the number of valid
175 * bytes written, the check should be made to verify the
176 * contents of the first valid write() scheduled.
177 */
178
179 if (writev(fd[0], wr_iovec, 3) < 0) {
180 TEST_ERROR_LOG(errno);
181 if (errno == EFAULT) {
182 tst_resm(TFAIL, "Got error EFAULT");
183 fail = 1;
184 }
185 } else {
186 l_seek(fd[0], 0, 0);
187 read(fd[0], buf_list[0], CHUNK);
188 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
189 tst_resm(TFAIL, "writev overwrote the file");
190 fail = 1;
191 }
192 }
193 if (fail) {
194 tst_resm(TINFO, "block 1 FAILED");
195 } else {
196 tst_resm(TINFO, "block 1 PASSED");
197 }
198 tst_resm(TINFO, "Exit block 1");
199
200block2:
201 tst_resm(TINFO, "Enter block 2");
202 fail = 0;
203
204 /*
205 * In this block we are trying to over write the contents by
206 * calling writev() with partially valid data. It should
207 * return the valid number of bytes written but not EFAULT.
208 * Also the check should be made whether the initial write()
209 * scheduled is done correctly or not.
210 */
211 l_seek(fd[0], 0, 0);
212 if (writev(fd[0], wr_iovec, 3) < 0) {
213 TEST_ERROR_LOG(errno);
214 if (errno == EFAULT) {
215 tst_resm(TFAIL, "Got error EFAULT");
216 fail = 1;
217 }
218 } else {
219 l_seek(fd[0], 0, 0);
220 read(fd[0], buf_list[0], CHUNK);
221 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
222 tst_resm(TFAIL, "writev overwrote the file");
223 fail = 1;
224 }
225 }
226 if (fail) {
227 tst_resm(TINFO, "block 2 FAILED");
228 } else {
229 tst_resm(TINFO, "block 2 PASSED");
230 }
231 tst_resm(TINFO, "Exit block 2");
232
233block3:
234 tst_resm(TINFO, "Enter block 3");
235 fail = 0;
236
237 /*
238 * In this block, we are trying to call writev() by going to
239 * some end position of the file. Here writev() is called
240 * with partially valid data, and this will return the
241 * number of valid bytes written and not EFAULT. Also, the
242 * check should be made whether the inital write() that is
243 * scheduled with valid data is done correctly done or not.
244 */
245
246 l_seek(fd[0], 8192, 0);
247 if (writev(fd[0], wr_iovec, 3) < 0) {
248 TEST_ERROR_LOG(errno);
249 if (errno == EFAULT) {
250 tst_resm(TFAIL, "Got error EFAULT");
251 fail = 1;
252 }
253 } else {
254 l_seek(fd[0], 0, 0);
255 read(fd[0], buf_list[0], CHUNK);
256 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
257 tst_resm(TFAIL, "writev overwrote the file");
258 fail = 1;
259 }
260 }
261
262 if (fail) {
263 tst_resm(TINFO, "block 3 FAILED");
264 } else {
265 tst_resm(TINFO, "block 3 PASSED");
266 }
267 tst_resm(TINFO, "Exit block 3");
268 }
269 cleanup();
270}
271
272/*
273 * setup()
274 * performs all ONE TIME setup for this test
275 */
276void
277setup(void)
278{
279 /* capture signals */
280 tst_sig(FORK, DEF_HANDLER, cleanup);
281
282 /* Set up the expected error numbers for -e option */
283 TEST_EXP_ENOS(exp_enos);
284
285 /* Pause if that option was specified.
286 * TEST_PAUSE contains the code to fork the test with the -i option.
287 * You want to make sure you do this before you create your temporary
288 * directory.
289 */
290 TEST_PAUSE;
291
292 strcpy(name, DATA_FILE);
293 sprintf(f_name, "%s.%d", name, getpid());
294
295 tst_tmpdir();
296}
297
298/*
299 * cleanup()
300 * performs all ONE TIME cleanup for this test at
301 * completion or premature exit
302 */
303void
304cleanup(void)
305{
306 /*
307 * print timing stats if that option was specified.
308 * print errno log if that option was specified.
309 */
310 TEST_CLEANUP;
311
312 if (unlink(f_name) < 0) {
313 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
314 f_name, errno);
315 }
316 tst_rmdir();
317
318 tst_exit();
319}
320
321/*
322 * sighandler()
323 * Signal handler function for SIGTERM and SIGPIPE
324 */
325void
326sighandler(int sig)
327{
328 switch(sig) {
329 case SIGTERM: break;
330 case SIGPIPE: ++in_sighandler;
331 return;
332 default:
333 tst_resm(TFAIL, "sighandler() received invalid signal "
334 ": %d", sig);
335 break;
336 }
337
338 if ((unlink(f_name) < 0) && (errno != ENOENT)) {
339 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
340 f_name, errno);
341 cleanup();
342 /*NOTREACHED*/
343 }
344 exit(sig);
345}
346
347/*
348 * l_seek()
349 * Wrap around for regular lseek function for giving error message
350 */
351long
352l_seek(int fdesc, long offset, int whence)
353{
354 if (lseek(fdesc, offset, whence) < 0) {
355 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
356 fail = 1;
357 }
358 return(0);
359}