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