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
main(int argc,char ** argv)91 int main(int argc, char **argv)
92 {
93 int lc;
94
95 int nbytes;
96
97 tst_parse_opts(argc, argv, NULL, NULL);
98
99 setup();
100
101 for (lc = 0; TEST_LOOPING(lc); lc++) {
102
103 tst_count = 0;
104
105 buf_list[0] = buf1;
106 buf_list[1] = buf2;
107
108 memset(buf_list[0], 0, K_1);
109 memset(buf_list[1], 0, K_1);
110
111 fd[1] = -1; /* Invalid file descriptor */
112
113 if (signal(SIGTERM, sighandler) == SIG_ERR)
114 tst_brkm(TFAIL | TERRNO, cleanup,
115 "signal(SIGTERM, ..)");
116
117 if (signal(SIGPIPE, sighandler) == SIG_ERR)
118 tst_brkm(TFAIL | TERRNO, cleanup,
119 "signal(SIGPIPE, ..)");
120
121 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0)
122 tst_brkm(TFAIL | TERRNO, cleanup,
123 "open(.., O_WRONLY|O_CREAT, ..) failed");
124 else {
125 l_seek(fd[0], K_1, 0);
126 if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1)
127 tst_brkm(TFAIL | TERRNO, cleanup,
128 "write failed");
129 }
130
131 if (close(fd[0]) == -1)
132 tst_brkm(TFAIL | TERRNO, cleanup, "close failed");
133
134 if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0)
135 tst_brkm(TFAIL | TERRNO, cleanup,
136 "open(.., O_RDWR, ..) failed");
137 /*
138 * In this block we are trying to call writev() with invalid
139 * vector to be written in a sparse file. This will return
140 * EFAULT. At the same time, check should be made whether
141 * the scheduled write() with valid data at 8k th offset is
142 * done correctly or not.
143 */
144 l_seek(fd[0], 0, 0);
145 TEST(writev(fd[0], wr_iovec, 2));
146 if (TEST_RETURN < 0) {
147 if (TEST_ERRNO == EFAULT) {
148 tst_resm(TPASS, "Received EFAULT as expected");
149 } else if (TEST_ERRNO != EFAULT) {
150 tst_resm(TFAIL, "Expected EFAULT, got %d",
151 TEST_ERRNO);
152 }
153 l_seek(fd[0], K_1, 0);
154 if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != CHUNK) {
155 tst_resm(TFAIL, "Expected nbytes = 64, got "
156 "%d", nbytes);
157 } else {
158 if (memcmp(buf_list[0], buf_list[1], CHUNK)
159 != 0)
160 tst_resm(TFAIL, "Error: writev() "
161 "over wrote %s", f_name);
162 }
163 } else
164 tst_resm(TFAIL, "Error writev returned a positive "
165 "value");
166 }
167 cleanup();
168 tst_exit();
169 }
170
setup(void)171 void setup(void)
172 {
173 tst_sig(FORK, sighandler, cleanup);
174
175 TEST_PAUSE;
176
177 tst_tmpdir();
178
179 strcpy(name, DATA_FILE);
180 sprintf(f_name, "%s.%d", name, getpid());
181
182 bad_addr = mmap(0, 1, PROT_NONE,
183 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
184 if (bad_addr == MAP_FAILED)
185 tst_brkm(TBROK | TERRNO, cleanup, "mmap failed");
186 wr_iovec[0].iov_base = bad_addr;
187
188 }
189
cleanup(void)190 void cleanup(void)
191 {
192 close(fd[0]);
193 close(fd[1]);
194
195 if (munmap(bad_addr, 1) == -1)
196 tst_resm(TWARN | TERRNO, "unmap failed");
197 if (unlink(f_name) == -1)
198 tst_resm(TWARN | TERRNO, "unlink failed");
199
200 tst_rmdir();
201
202 }
203
sighandler(int sig)204 void sighandler(int sig)
205 {
206 switch (sig) {
207 case SIGTERM:
208 break;
209 case SIGPIPE:
210 ++in_sighandler;
211 return;
212 default:
213 tst_resm(TBROK, "sighandler received invalid signal : %d", sig);
214 break;
215 }
216
217 if (unlink(f_name) == -1 && errno != ENOENT)
218 tst_resm(TFAIL | TERRNO, "unlink failed");
219 }
220
221 /*
222 * l_seek()
223 * Wrap around for regular lseek function for giving error message
224 */
l_seek(int fdesc,off_t offset,int whence)225 void l_seek(int fdesc, off_t offset, int whence)
226 {
227 if (lseek(fdesc, offset, whence) == -1)
228 tst_resm(TBROK | TERRNO, "lseek failed");
229 }
230