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 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 */ 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 */ 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 */ 164 void cleanup(void) 165 { 166 167 close(out_fd); 168 /* delete the test directory created in setup() */ 169 tst_rmdir(); 170 171 } 172 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 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