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 * writev02.c
23 *
24 * DESCRIPTION
25 * In these testcases, writev() is called with partially valid data
26 * to be written in a sparse file.
27 *
28 * ALGORITHM
29 * The file is created and write() is called with valid buffer to write
30 * at some 8k th offset. After that writev() will be called with invalid
31 * vector. This should return EFAULT. And at the same time, try looking at
32 * the 8kth offset whether the file is intact or not.
33 *
34 * USAGE: <for command-line>
35 * writev02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
36 * where, -c n : Run n copies concurrently.
37 * -e : Turn on errno logging.
38 * -i n : Execute test n times.
39 * -I x : Execute test for x seconds.
40 * -P x : Pause for x seconds between iterations.
41 * -t : Turn on syscall timing.
42 *
43 * History
44 * 07/2001 John George
45 * -Ported
46 * 04/2002 wjhuie sigset cleanups
47 *
48 * Restrictions
49 * None
50 */
51
52 #include <sys/types.h>
53 #include <signal.h>
54 #include <sys/uio.h>
55 #include <fcntl.h>
56 #include <memory.h>
57 #include <errno.h>
58 #include "test.h"
59 #include <sys/mman.h>
60
61 #define K_1 8192
62
63 #define NBUFS 2
64 #define CHUNK K_1 /* single chunk */
65 #define MAX_IOVEC 2
66 #define DATA_FILE "writev_data_file"
67
68 char buf1[K_1];
69 char buf2[K_1];
70
71 char *bad_addr = 0;
72
73 struct iovec wr_iovec[MAX_IOVEC] = {
74 {(caddr_t) - 1, CHUNK},
75 {NULL, 0},
76 };
77
78 char name[K_1], f_name[K_1];
79
80 int fd[2], in_sighandler;
81 char *buf_list[NBUFS];
82
83 char *TCID = "writev02";
84 int TST_TOTAL = 1;
85
86 void sighandler(int);
87 void l_seek(int, off_t, int);
88 void setup(void);
89 void cleanup(void);
90 int fail;
91
main(int argc,char ** argv)92 int main(int argc, char **argv)
93 {
94 int lc;
95
96 int nbytes;
97
98 tst_parse_opts(argc, argv, NULL, NULL);
99
100 setup();
101
102 for (lc = 0; TEST_LOOPING(lc); lc++) {
103
104 tst_count = 0;
105
106 buf_list[0] = buf1;
107 buf_list[1] = buf2;
108
109 memset(buf_list[0], 0, K_1);
110 memset(buf_list[1], 0, K_1);
111
112 fd[1] = -1; /* Invalid file descriptor */
113
114 if (signal(SIGTERM, sighandler) == SIG_ERR)
115 tst_brkm(TFAIL | TERRNO, cleanup,
116 "signal(SIGTERM, ..)");
117
118 if (signal(SIGPIPE, sighandler) == SIG_ERR)
119 tst_brkm(TFAIL | TERRNO, cleanup,
120 "signal(SIGPIPE, ..)");
121
122 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0)
123 tst_brkm(TFAIL | TERRNO, cleanup,
124 "open(.., O_WRONLY|O_CREAT, ..) failed");
125 else {
126 l_seek(fd[0], K_1, 0);
127 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1)
128 tst_brkm(TFAIL | TERRNO, cleanup,
129 "write failed");
130 }
131
132 if (close(fd[0]) == -1)
133 tst_brkm(TFAIL | TERRNO, cleanup, "close failed");
134
135 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0)
136 tst_brkm(TFAIL | TERRNO, cleanup,
137 "open(.., O_RDWR, ..) failed");
138 //block1:
139 /*
140 * In this block we are trying to call writev() with invalid
141 * vector to be written in a sparse file. This will return
142 * EFAULT. At the same time, check should be made whether
143 * the scheduled write() with valid data at 8k th offset is
144 * done correctly or not.
145 */
146 tst_resm(TINFO, "Enter block 1");
147
148 l_seek(fd[0], 0, 0);
149 TEST(writev(fd[0], wr_iovec, 2));
150 if (TEST_RETURN < 0) {
151 if (TEST_ERRNO == EFAULT) {
152 tst_resm(TPASS, "Received EFAULT as expected");
153 } else if (TEST_ERRNO != EFAULT) {
154 tst_resm(TFAIL, "Expected EFAULT, got %d",
155 TEST_ERRNO);
156 }
157 l_seek(fd[0], K_1, 0);
158 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != CHUNK) {
159 tst_resm(TFAIL, "Expected nbytes = 64, got "
160 "%d", nbytes);
161 } else {
162 if (memcmp(buf_list[0], buf_list[1], CHUNK)
163 != 0)
164 tst_resm(TFAIL, "Error: writev() "
165 "over wrote %s", f_name);
166 }
167 } else
168 tst_resm(TFAIL, "Error writev returned a positive "
169 "value");
170 tst_resm(TINFO, "Exit block 1");
171 }
172 cleanup();
173 tst_exit();
174 }
175
setup(void)176 void setup(void)
177 {
178 tst_sig(FORK, sighandler, cleanup);
179
180 TEST_PAUSE;
181
182 tst_tmpdir();
183
184 strcpy(name, DATA_FILE);
185 sprintf(f_name, "%s.%d", name, getpid());
186
187 bad_addr = mmap(0, 1, PROT_NONE,
188 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
189 if (bad_addr == MAP_FAILED)
190 tst_brkm(TBROK | TERRNO, cleanup, "mmap failed");
191 wr_iovec[0].iov_base = bad_addr;
192
193 }
194
cleanup(void)195 void cleanup(void)
196 {
197 close(fd[0]);
198 close(fd[1]);
199
200 if (munmap(bad_addr, 1) == -1)
201 tst_resm(TWARN | TERRNO, "unmap failed");
202 if (unlink(f_name) == -1)
203 tst_resm(TWARN | TERRNO, "unlink failed");
204
205 tst_rmdir();
206
207 }
208
sighandler(int sig)209 void sighandler(int sig)
210 {
211 switch (sig) {
212 case SIGTERM:
213 break;
214 case SIGPIPE:
215 ++in_sighandler;
216 return;
217 default:
218 tst_resm(TBROK, "sighandler received invalid signal : %d", sig);
219 break;
220 }
221
222 if (unlink(f_name) == -1 && errno != ENOENT)
223 tst_resm(TFAIL | TERRNO, "unlink failed");
224 }
225
226 /*
227 * l_seek()
228 * Wrap around for regular lseek function for giving error message
229 */
l_seek(int fdesc,off_t offset,int whence)230 void l_seek(int fdesc, off_t offset, int whence)
231 {
232 if (lseek(fdesc, offset, whence) == -1)
233 tst_resm(TBROK | TERRNO, "lseek failed");
234 }
235