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 * NAME
22 * writev05.c
23 *
24 * DESCRIPTION
25 * These testcases are written to test writev() on sparse files. This
26 * is same as writev02.c. But the initial write() with valid data is
27 * done at the beginning of the file.
28 *
29 * USAGE: <for command-line>
30 * writev05 [-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
41 * 04/2002 wjhuie sigset cleanups
42 *
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 <sys/mman.h>
55
56 #define K_1 8192
57
58 #define NBUFS 2
59 #define CHUNK K_1 /* single chunk */
60 #define MAX_IOVEC 2
61 #define DATA_FILE "writev_data_file"
62
63 char buf1[K_1];
64 char buf2[K_1];
65 char buf3[K_1];
66
67 char *bad_addr = 0;
68
69 struct iovec wr_iovec[MAX_IOVEC] = {
70 {(caddr_t) - 1, CHUNK},
71 {NULL, 0}
72 };
73
74 char name[K_1], f_name[K_1];
75 int fd[2], in_sighandler;
76 char *buf_list[NBUFS];
77
78 char *TCID = "writev05";
79 int TST_TOTAL = 1;
80
81 void sighandler(int);
82 long l_seek(int, long, int);
83 void setup(void);
84 void cleanup(void);
85
86 #if !defined(UCLINUX)
87
main(int argc,char ** argv)88 int main(int argc, char **argv)
89 {
90 int lc;
91
92 int nbytes;
93
94 tst_parse_opts(argc, argv, NULL, NULL);
95
96 setup(); /* set "tstdir", and "testfile" vars */
97
98 /* The following loop checks looping state if -i option given */
99 for (lc = 0; TEST_LOOPING(lc); lc++) {
100
101 /* reset tst_count in case we are looping */
102 tst_count = 0;
103
104 buf_list[0] = buf1;
105 buf_list[1] = buf2;
106
107 fd[1] = -1; /* Invalid file descriptor */
108
109 if (signal(SIGTERM, sighandler) == SIG_ERR) {
110 perror("signal");
111 tst_resm(TFAIL, "signal() SIGTERM FAILED");
112 cleanup();
113 }
114
115 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
116 perror("signal");
117 tst_resm(TFAIL, "signal() SIGPIPE FAILED");
118 cleanup();
119 }
120
121 /* Fill the buf_list[0] and buf_list[1] with 0 zeros */
122 memset(buf_list[0], 0, K_1);
123 memset(buf_list[1], 0, K_1);
124
125 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
126 tst_resm(TFAIL, "open(2) failed: fname = %s, "
127 "errno = %d", f_name, errno);
128 cleanup();
129 } else {
130 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) {
131 tst_resm(TFAIL, "write(2) failed: nbytes "
132 "= %d, errno = %d", nbytes, errno);
133 cleanup();
134 }
135 }
136
137 if (close(fd[0]) < 0) {
138 tst_resm(TFAIL, "close failed: errno = %d", errno);
139 cleanup();
140 }
141
142 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
143 tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
144 f_name, errno);
145 cleanup();
146 }
147
148 /*
149 * In this block we are trying to call writev() with invalid
150 * vector to be written in a sparse file. This will return
151 * EFAULT. At the same time, check should be made whether
152 * the scheduled write() with valid data is done correctly
153 * or not.
154 */
155 l_seek(fd[0], 0, 0);
156 TEST(writev(fd[0], wr_iovec, 2));
157 if (TEST_RETURN < 0) {
158 if (TEST_ERRNO == EFAULT) {
159 tst_resm(TPASS, "Received EFAULT as expected");
160 } else {
161 tst_resm(TFAIL, "Expected EFAULT, got %d",
162 TEST_ERRNO);
163 }
164 l_seek(fd[0], K_1, 0);
165 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 0) {
166 tst_resm(TFAIL, "Expected nbytes = 0, got "
167 "%d", nbytes);
168 }
169 } else {
170 tst_resm(TFAIL, "Error writev returned a positive "
171 "value");
172 }
173 }
174 close(fd[0]);
175 close(fd[1]);
176 cleanup();
177 tst_exit();
178
179 }
180
181 #else
182
main(void)183 int main(void)
184 {
185 tst_resm(TINFO, "test is not available on uClinux");
186 tst_exit();
187 }
188
189 #endif /* if !defined(UCLINUX) */
190
191 /*
192 * setup()
193 * performs all ONE TIME setup for this test
194 */
setup(void)195 void setup(void)
196 {
197
198 tst_sig(FORK, DEF_HANDLER, cleanup);
199
200 /* Pause if that option was specified.
201 * TEST_PAUSE contains the code to fork the test with the -i option.
202 * You want to make sure you do this before you create your temporary
203 * directory.
204 */
205 TEST_PAUSE;
206
207 /* Create a unique temporary directory and chdir() to it. */
208 tst_tmpdir();
209
210 strcpy(name, DATA_FILE);
211 sprintf(f_name, "%s.%d", name, getpid());
212
213 bad_addr = mmap(0, 1, PROT_NONE,
214 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
215 if (bad_addr == MAP_FAILED) {
216 printf("mmap failed\n");
217 }
218 wr_iovec[0].iov_base = bad_addr;
219
220 }
221
222 /*
223 * cleanup()
224 * performs all ONE TIME cleanup for this test at
225 * completion or premature exit
226 */
cleanup(void)227 void cleanup(void)
228 {
229
230 if (unlink(f_name) < 0) {
231 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
232 f_name, errno);
233 }
234 tst_rmdir();
235
236 }
237
238 /*
239 * sighandler()
240 * Signal handler for SIGTERM and SIGPIPE
241 */
sighandler(int sig)242 void sighandler(int sig)
243 {
244 switch (sig) {
245 case SIGTERM:
246 break;
247 case SIGPIPE:
248 ++in_sighandler;
249 return;
250 default:
251 tst_resm(TFAIL, "sighandler() received invalid signal "
252 ": %d", sig);
253 break;
254 }
255
256 if ((unlink(f_name) < 0) && (errno != ENOENT)) {
257 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
258 f_name, errno);
259 cleanup();
260 }
261 exit(sig);
262 }
263
264 /*
265 * l_seek()
266 * Wrap around for regular lseek() to give error message on failure
267 */
l_seek(int fdesc,long offset,int whence)268 long l_seek(int fdesc, long offset, int whence)
269 {
270 if (lseek(fdesc, offset, whence) < 0) {
271 tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
272 }
273 return 0;
274 }
275