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 56#ifndef OFF_T 57#define OFF_T off_t 58#endif /* Not def: OFF_T */ 59 60TCID_DEFINE(sendfile05); 61 62char in_file[100]; 63char out_file[100]; 64int out_fd; 65pid_t child_pid; 66static int sockfd, s; 67static struct sockaddr_in sin1; /* shared between do_child and create_server */ 68 69void cleanup(void); 70void do_child(void); 71void setup(void); 72int create_server(void); 73 74int TST_TOTAL = 1; 75 76#ifdef UCLINUX 77static char *argv0; 78#endif 79 80void do_sendfile(void) 81{ 82 OFF_T offset; 83 int in_fd; 84 struct stat sb; 85 86 out_fd = create_server(); 87 88 if ((in_fd = open(in_file, O_RDONLY)) < 0) { 89 tst_brkm(TBROK, cleanup, "open failed: %d", errno); 90 } 91 if (stat(in_file, &sb) < 0) { 92 tst_brkm(TBROK, cleanup, "stat failed: %d", errno); 93 } 94 95 offset = -1; 96 TEST(sendfile(out_fd, in_fd, &offset, sb.st_size)); 97 98 if (TEST_RETURN != -1) { 99 tst_resm(TFAIL, "call succeeded unexpectedly"); 100 } else { 101 if (TEST_ERRNO != EINVAL) { 102 tst_resm(TFAIL, "sendfile returned unexpected " 103 "errno, expected: %d, got: %d", 104 EINVAL, TEST_ERRNO); 105 } else { 106 tst_resm(TPASS, "sendfile() returned %d : %s", 107 TEST_ERRNO, strerror(TEST_ERRNO)); 108 } 109 } 110 111 shutdown(sockfd, SHUT_RDWR); 112 shutdown(s, SHUT_RDWR); 113 kill(child_pid, SIGKILL); 114 close(in_fd); 115} 116 117/* 118 * do_child 119 */ 120void do_child(void) 121{ 122 int lc; 123 socklen_t length; 124 char rbuf[4096]; 125 126 for (lc = 0; TEST_LOOPING(lc); lc++) { 127 length = sizeof(sin1); 128 recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1, 129 &length); 130 } 131 exit(0); 132} 133 134/* 135 * setup() - performs all ONE TIME setup for this test. 136 */ 137void setup(void) 138{ 139 int fd; 140 char buf[100]; 141 142 tst_sig(FORK, DEF_HANDLER, cleanup); 143 144 TEST_PAUSE; 145 146 /* make a temporary directory and cd to it */ 147 tst_tmpdir(); 148 sprintf(in_file, "in.%d", getpid()); 149 if ((fd = creat(in_file, 00700)) < 0) { 150 tst_brkm(TBROK, cleanup, "creat failed in setup, errno: %d", 151 errno); 152 } 153 sprintf(buf, "abcdefghijklmnopqrstuvwxyz"); 154 if (write(fd, buf, strlen(buf)) < 0) { 155 tst_brkm(TBROK, cleanup, "write failed, errno: %d", errno); 156 } 157 close(fd); 158 sprintf(out_file, "out.%d", getpid()); 159} 160 161/* 162 * cleanup() - performs all ONE TIME cleanup for this test at 163 * completion or premature exit. 164 */ 165void cleanup(void) 166{ 167 168 close(out_fd); 169 /* delete the test directory created in setup() */ 170 tst_rmdir(); 171 172} 173 174int create_server(void) 175{ 176 static int count = 0; 177 socklen_t slen = sizeof(sin1); 178 179 sockfd = socket(PF_INET, SOCK_DGRAM, 0); 180 if (sockfd < 0) { 181 tst_brkm(TBROK, cleanup, "call to socket() failed: %s", 182 strerror(errno)); 183 return -1; 184 } 185 sin1.sin_family = AF_INET; 186 sin1.sin_port = 0; /* pick random free port */ 187 sin1.sin_addr.s_addr = INADDR_ANY; 188 count++; 189 if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) { 190 tst_brkm(TBROK, cleanup, "call to bind() failed: %s", 191 strerror(errno)); 192 return -1; 193 } 194 if (getsockname(sockfd, (struct sockaddr *)&sin1, &slen) == -1) 195 tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed"); 196 197 child_pid = FORK_OR_VFORK(); 198 if (child_pid < 0) { 199 tst_brkm(TBROK, cleanup, "client/server fork failed: %s", 200 strerror(errno)); 201 return -1; 202 } 203 if (!child_pid) { /* child */ 204#ifdef UCLINUX 205 if (self_exec(argv0, "") < 0) { 206 tst_brkm(TBROK, cleanup, "self_exec failed"); 207 return -1; 208 209 } 210#else 211 do_child(); 212#endif 213 } 214 215 s = socket(PF_INET, SOCK_DGRAM, 0); 216 inet_aton("127.0.0.1", &sin1.sin_addr); 217 if (s < 0) { 218 tst_brkm(TBROK, cleanup, "call to socket() failed: %s", 219 strerror(errno)); 220 return -1; 221 } 222 if (connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) { 223 tst_brkm(TBROK, cleanup, "call to connect() failed: %s", 224 strerror(errno)); 225 } 226 return s; 227 228} 229 230int main(int ac, char **av) 231{ 232 int lc; 233 234 tst_parse_opts(ac, av, NULL, NULL); 235#ifdef UCLINUX 236 argv0 = av[0]; 237 maybe_run_child(&do_child, ""); 238#endif 239 240 setup(); 241 242 /* 243 * The following loop checks looping state if -c option given 244 */ 245 for (lc = 0; TEST_LOOPING(lc); lc++) { 246 tst_count = 0; 247 248 do_sendfile(); 249 } 250 cleanup(); 251 252 tst_exit(); 253} 254