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 * 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
41 * 04/2002 wjhuie sigset cleanups
42 *
43 * Restrictions
44 * NONE
45 */
46
47 #include <sys/types.h>
48 #include <sys/uio.h>
49 #include <sys/mman.h>
50 #include <unistd.h>
51 #include <signal.h>
52 #include <fcntl.h>
53 #include <memory.h>
54 #include <errno.h>
55 #include "test.h"
56
57 #define K_1 1024
58
59 #define NBUFS 4
60 #define CHUNK 64 /* single chunk */
61 #define MAX_IOVEC 4
62 #define DATA_FILE "writev_data_file"
63
64 char buf1[K_1], buf2[K_1], buf3[K_1];
65 char *bad_addr = 0;
66
67 struct iovec wr_iovec[MAX_IOVEC] = {
68 /* testcase #1 */
69 {buf1 + (CHUNK * 6), CHUNK},
70 {(caddr_t) - 1, CHUNK},
71 {buf1 + (CHUNK * 8), CHUNK},
72 {NULL, 0}
73 };
74
75 char name[K_1], f_name[K_1];
76 int fd[2], in_sighandler;
77 char *buf_list[NBUFS];
78
79 char *TCID = "writev03";
80 int TST_TOTAL = 1;
81
82 void sighandler(int);
83 void l_seek(int, off_t, int);
84 void setup(void);
85 void cleanup(void);
86
main(int argc,char ** argv)87 int main(int argc, char **argv)
88 {
89 int lc;
90
91 int nbytes;
92
93 tst_parse_opts(argc, argv, NULL, NULL);
94
95 setup();
96
97 for (lc = 0; TEST_LOOPING(lc); lc++) {
98
99 tst_count = 0;
100
101 buf_list[0] = buf1;
102 buf_list[1] = buf2;
103 buf_list[2] = buf3;
104 buf_list[3] = NULL;
105
106 fd[1] = -1; /* Invalid file descriptor */
107
108 if (signal(SIGTERM, sighandler) == SIG_ERR)
109 tst_brkm(TBROK | TERRNO, cleanup,
110 "signal(SIGTERM, ..) failed");
111
112 if (signal(SIGPIPE, sighandler) == SIG_ERR)
113 tst_brkm(TBROK | TERRNO, cleanup,
114 "signal(SIGPIPE, ..) failed");
115
116 memset(buf_list[0], 0, K_1);
117 memset(buf_list[1], 0, K_1);
118
119 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) == -1)
120 tst_brkm(TBROK | TERRNO, cleanup,
121 "open(.., O_WRONLY|O_CREAT, ..) failed");
122 else if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1)
123 tst_brkm(TFAIL | TERRNO, cleanup, "write failed");
124
125 if (close(fd[0]) < 0)
126 tst_brkm(TBROK | TERRNO, cleanup, "close failed");
127
128 if ((fd[0] = open(f_name, O_RDWR, 0666)) == -1)
129 tst_brkm(TBROK | TERRNO, cleanup,
130 "open(.., O_RDWR, ..) failed");
131 //block1:
132 tst_resm(TINFO, "Enter block 1");
133
134 /*
135 * In this block we are trying to call writev() with
136 * partially valid data. This should return the valid number
137 * of bytes written in the vector. If it returns EFAULT, it
138 * is an error. And after returning the number of valid
139 * bytes written, the check should be made to verify the
140 * contents of the first valid write() scheduled.
141 */
142
143 if (writev(fd[0], wr_iovec, 3) == -1) {
144 if (errno == EFAULT)
145 tst_resm(TFAIL, "Got EFAULT");
146 } else {
147 l_seek(fd[0], 0, 0);
148 read(fd[0], buf_list[0], CHUNK);
149 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0)
150 tst_resm(TFAIL, "writev overwrote the file");
151 }
152 tst_resm(TINFO, "Exit block 1");
153
154 //block2:
155 tst_resm(TINFO, "Enter block 2");
156
157 /*
158 * In this block we are trying to over write the contents by
159 * calling writev() with partially valid data. It should
160 * return the valid number of bytes written but not EFAULT.
161 * Also the check should be made whether the initial write()
162 * scheduled is done correctly or not.
163 */
164 l_seek(fd[0], 0, 0);
165 if (writev(fd[0], wr_iovec, 3) == -1) {
166 if (errno == EFAULT)
167 tst_resm(TFAIL, "Got EFAULT");
168 } else {
169 l_seek(fd[0], 0, 0);
170 read(fd[0], buf_list[0], CHUNK);
171 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0)
172 tst_resm(TFAIL, "writev overwrote the file");
173 }
174 tst_resm(TINFO, "Exit block 2");
175
176 //block3:
177 tst_resm(TINFO, "Enter block 3");
178
179 /*
180 * In this block, we are trying to call writev() by going to
181 * some end position of the file. Here writev() is called
182 * with partially valid data, and this will return the
183 * number of valid bytes written and not EFAULT. Also, the
184 * check should be made whether the inital write() that is
185 * scheduled with valid data is done correctly done or not.
186 */
187
188 l_seek(fd[0], 8192, 0);
189 if (writev(fd[0], wr_iovec, 3) == -1) {
190 if (errno == EFAULT)
191 tst_resm(TFAIL, "Got EFAULT");
192 } else {
193 l_seek(fd[0], 0, 0);
194 read(fd[0], buf_list[0], CHUNK);
195 if (memcmp(buf_list[0], buf_list[1], CHUNK) != 0) {
196 tst_resm(TFAIL, "writev overwrote the file");
197 }
198 }
199
200 tst_resm(TINFO, "Exit block 3");
201 }
202 cleanup();
203 tst_exit();
204 }
205
206 /*
207 * setup()
208 * performs all ONE TIME setup for this test
209 */
setup(void)210 void setup(void)
211 {
212
213 tst_sig(FORK, DEF_HANDLER, cleanup);
214
215 /* Pause if that option was specified.
216 * TEST_PAUSE contains the code to fork the test with the -i option.
217 * You want to make sure you do this before you create your temporary
218 * directory.
219 */
220 TEST_PAUSE;
221
222 strcpy(name, DATA_FILE);
223 sprintf(f_name, "%s.%d", name, getpid());
224
225 bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
226 if (bad_addr == MAP_FAILED) {
227 tst_brkm(TBROK, cleanup, "mmap failed");
228 }
229 wr_iovec[1].iov_base = bad_addr;
230 tst_tmpdir();
231 }
232
233 /*
234 * cleanup()
235 * performs all ONE TIME cleanup for this test at
236 * completion or premature exit
237 */
cleanup(void)238 void cleanup(void)
239 {
240 close(fd[0]);
241 close(fd[1]);
242
243 if (unlink(f_name) == -1)
244 tst_resm(TFAIL, "unlink failed");
245 tst_rmdir();
246
247 }
248
sighandler(int sig)249 void sighandler(int sig)
250 {
251 switch (sig) {
252 case SIGTERM:
253 break;
254 case SIGPIPE:
255 ++in_sighandler;
256 return;
257 default:
258 tst_resm(TBROK, "sighandler received invalid signal : %d", sig);
259 break;
260 }
261 }
262
263 /*
264 * l_seek()
265 * Wrap around for regular lseek function for giving error message
266 */
l_seek(int fdesc,off_t offset,int whence)267 void l_seek(int fdesc, off_t offset, int whence)
268 {
269 if (lseek(fdesc, offset, whence) == -1)
270 tst_brkm(TBROK | TERRNO, cleanup, "lseek failed");
271 }
272