• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *   Copyright (c) Red Hat Inc., 2007
5  *
6  *   This program is free software;  you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14  *   the GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program;  if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * NAME
23  *	sendfile05.c
24  *
25  * DESCRIPTION
26  *	Testcase to test that sendfile(2) system call returns EINVAL
27  *	when passing negative offset.
28  *
29  * USAGE:  <for command-line>
30  *  sendfile05 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
31  *     where,
32  *             -f   : Turn off functionality Testing.
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  *	11/2007 Copyed from sendfile02.c by Masatake YAMATO
40  *
41  * RESTRICTIONS
42  *	NONE
43  */
44 #include <stdio.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <sys/stat.h>
48 #include <sys/sendfile.h>
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <sys/mman.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include "test.h"
55 #include "safe_macros.h"
56 
57 #ifndef OFF_T
58 #define OFF_T off_t
59 #endif /* Not def: OFF_T */
60 
61 TCID_DEFINE(sendfile05);
62 
63 char in_file[100];
64 char out_file[100];
65 int out_fd;
66 pid_t child_pid;
67 static int sockfd, s;
68 static struct sockaddr_in sin1;	/* shared between do_child and create_server */
69 
70 void cleanup(void);
71 void do_child(void);
72 void setup(void);
73 int create_server(void);
74 
75 int TST_TOTAL = 1;
76 
77 #ifdef UCLINUX
78 static char *argv0;
79 #endif
80 
do_sendfile(void)81 void do_sendfile(void)
82 {
83 	OFF_T offset;
84 	int in_fd;
85 	struct stat sb;
86 
87 	out_fd = create_server();
88 
89 	if ((in_fd = open(in_file, O_RDONLY)) < 0) {
90 		tst_brkm(TBROK, cleanup, "open failed: %d", errno);
91 	}
92 	SAFE_STAT(cleanup, in_file, &sb);
93 
94 	offset = -1;
95 	TEST(sendfile(out_fd, in_fd, &offset, sb.st_size));
96 
97 	if (TEST_RETURN != -1) {
98 		tst_resm(TFAIL, "call succeeded unexpectedly");
99 	} else {
100 		if (TEST_ERRNO != EINVAL) {
101 			tst_resm(TFAIL, "sendfile returned unexpected "
102 				 "errno, expected: %d, got: %d",
103 				 EINVAL, TEST_ERRNO);
104 		} else {
105 			tst_resm(TPASS, "sendfile() returned %d : %s",
106 				 TEST_ERRNO, strerror(TEST_ERRNO));
107 		}
108 	}
109 
110 	shutdown(sockfd, SHUT_RDWR);
111 	shutdown(s, SHUT_RDWR);
112 	kill(child_pid, SIGKILL);
113 	close(in_fd);
114 }
115 
116 /*
117  * do_child
118  */
do_child(void)119 void do_child(void)
120 {
121 	int lc;
122 	socklen_t length;
123 	char rbuf[4096];
124 
125 	for (lc = 0; TEST_LOOPING(lc); lc++) {
126 		length = sizeof(sin1);
127 		recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1,
128 			 &length);
129 	}
130 	exit(0);
131 }
132 
133 /*
134  * setup() - performs all ONE TIME setup for this test.
135  */
setup(void)136 void setup(void)
137 {
138 	int fd;
139 	char buf[100];
140 
141 	tst_sig(FORK, DEF_HANDLER, cleanup);
142 
143 	TEST_PAUSE;
144 
145 	/* make a temporary directory and cd to it */
146 	tst_tmpdir();
147 	sprintf(in_file, "in.%d", getpid());
148 	if ((fd = creat(in_file, 00700)) < 0) {
149 		tst_brkm(TBROK, cleanup, "creat failed in setup, errno: %d",
150 			 errno);
151 	}
152 	sprintf(buf, "abcdefghijklmnopqrstuvwxyz");
153 	if (write(fd, buf, strlen(buf)) < 0) {
154 		tst_brkm(TBROK, cleanup, "write failed, errno: %d", errno);
155 	}
156 	close(fd);
157 	sprintf(out_file, "out.%d", getpid());
158 }
159 
160 /*
161  * cleanup() - performs all ONE TIME cleanup for this test at
162  *	       completion or premature exit.
163  */
cleanup(void)164 void cleanup(void)
165 {
166 
167 	close(out_fd);
168 	/* delete the test directory created in setup() */
169 	tst_rmdir();
170 
171 }
172 
create_server(void)173 int create_server(void)
174 {
175 	static int count = 0;
176 	socklen_t slen = sizeof(sin1);
177 
178 	sockfd = socket(PF_INET, SOCK_DGRAM, 0);
179 	if (sockfd < 0) {
180 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
181 			 strerror(errno));
182 		return -1;
183 	}
184 	sin1.sin_family = AF_INET;
185 	sin1.sin_port = 0; /* pick random free port */
186 	sin1.sin_addr.s_addr = INADDR_ANY;
187 	count++;
188 	if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
189 		tst_brkm(TBROK, cleanup, "call to bind() failed: %s",
190 			 strerror(errno));
191 		return -1;
192 	}
193 	SAFE_GETSOCKNAME(cleanup, sockfd, (struct sockaddr *)&sin1, &slen);
194 
195 	child_pid = FORK_OR_VFORK();
196 	if (child_pid < 0) {
197 		tst_brkm(TBROK, cleanup, "client/server fork failed: %s",
198 			 strerror(errno));
199 		return -1;
200 	}
201 	if (!child_pid) {	/* child */
202 #ifdef UCLINUX
203 		if (self_exec(argv0, "") < 0) {
204 			tst_brkm(TBROK, cleanup, "self_exec failed");
205 			return -1;
206 
207 		}
208 #else
209 		do_child();
210 #endif
211 	}
212 
213 	s = socket(PF_INET, SOCK_DGRAM, 0);
214 	inet_aton("127.0.0.1", &sin1.sin_addr);
215 	if (s < 0) {
216 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
217 			 strerror(errno));
218 		return -1;
219 	}
220 	SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, sizeof(sin1));
221 	return s;
222 
223 }
224 
main(int ac,char ** av)225 int main(int ac, char **av)
226 {
227 	int lc;
228 
229 	tst_parse_opts(ac, av, NULL, NULL);
230 #ifdef UCLINUX
231 	argv0 = av[0];
232 	maybe_run_child(&do_child, "");
233 #endif
234 
235 	setup();
236 
237 	/*
238 	 * The following loop checks looping state if -c option given
239 	 */
240 	for (lc = 0; TEST_LOOPING(lc); lc++) {
241 		tst_count = 0;
242 
243 		do_sendfile();
244 	}
245 	cleanup();
246 
247 	tst_exit();
248 }
249