1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) Red Hat Inc., 2007 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 Foundation, 17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * DESCRIPTION 22 * Testcase to test that sendfile(2) system call updates file 23 * position of in_fd correctly when passing NULL as offset. 24 * 25 * HISTORY 26 * 11/2007 Copyed from sendfile02.c by Masatake YAMATO 27 */ 28 29 #include <inttypes.h> 30 #include <stdio.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <sys/stat.h> 34 #include <sys/sendfile.h> 35 #include <sys/types.h> 36 #include <sys/wait.h> 37 #include <sys/socket.h> 38 #include <sys/mman.h> 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 #include <string.h> 42 #include "test.h" 43 #include "safe_macros.h" 44 45 TCID_DEFINE(sendfile06); 46 47 #define IN_FILE "infile" 48 #define OUT_FILE "outfile" 49 50 static pid_t child_pid; 51 static int sockfd; 52 static struct sockaddr_in sin1; 53 static struct stat sb; 54 55 static void cleanup(void); 56 static void do_child(void); 57 static void setup(void); 58 static int create_server(void); 59 60 int TST_TOTAL = 1; 61 62 #ifdef UCLINUX 63 static char *argv0; 64 #endif 65 66 static void do_sendfile(void) 67 { 68 int in_fd, out_fd; 69 off_t after_pos; 70 int wait_stat; 71 72 out_fd = create_server(); 73 74 in_fd = SAFE_OPEN(cleanup, IN_FILE, O_RDONLY); 75 76 TEST(sendfile(out_fd, in_fd, NULL, sb.st_size)); 77 if ((after_pos = lseek(in_fd, 0, SEEK_CUR)) < 0) { 78 tst_brkm(TBROK, cleanup, 79 "lseek after invoking sendfile failed: %d", errno); 80 } 81 82 /* Close the sockets */ 83 shutdown(sockfd, SHUT_RDWR); 84 shutdown(out_fd, SHUT_RDWR); 85 if (TEST_RETURN != sb.st_size) { 86 tst_resm(TFAIL, "sendfile(2) failed to return " 87 "expected value, expected: %" PRId64 ", " 88 "got: %ld", (int64_t) sb.st_size, TEST_RETURN); 89 SAFE_KILL(cleanup, child_pid, SIGKILL); 90 } else if (after_pos != sb.st_size) { 91 tst_resm(TFAIL, "sendfile(2) failed to update " 92 " the file position of in_fd, " 93 "expected file position: %" PRId64 ", " 94 "actual file position %" PRId64, 95 (int64_t) sb.st_size, (int64_t) after_pos); 96 SAFE_KILL(cleanup, child_pid, SIGKILL); 97 } else { 98 tst_resm(TPASS, "functionality of sendfile() is " 99 "correct"); 100 waitpid(-1, &wait_stat, 0); 101 } 102 103 SAFE_CLOSE(cleanup, in_fd); 104 SAFE_CLOSE(cleanup, out_fd); 105 SAFE_CLOSE(cleanup, sockfd); 106 } 107 108 static void do_child(void) 109 { 110 socklen_t length = sizeof(sin1); 111 char rbuf[4096]; 112 ssize_t ret, bytes_total_received = 0; 113 114 while (bytes_total_received < sb.st_size) { 115 ret = recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1, 116 &length); 117 if (ret < 0) { 118 fprintf(stderr, "child process recvfrom failed: %s\n", 119 strerror(errno)); 120 exit(1); 121 } 122 bytes_total_received += ret; 123 } 124 125 exit(0); 126 } 127 128 static void setup(void) 129 { 130 int fd; 131 132 tst_sig(FORK, DEF_HANDLER, cleanup); 133 134 TEST_PAUSE; 135 136 tst_tmpdir(); 137 138 fd = SAFE_CREAT(cleanup, IN_FILE, 0600); 139 140 SAFE_WRITE(cleanup, 1, fd, "abcdefghijklmnopqrstuvwxyz", 26); 141 142 SAFE_FSTAT(cleanup, fd, &sb); 143 144 SAFE_CLOSE(cleanup, fd); 145 } 146 147 static void cleanup(void) 148 { 149 tst_rmdir(); 150 } 151 152 static int create_server(void) 153 { 154 int s; 155 socklen_t slen = sizeof(sin1); 156 157 sockfd = socket(PF_INET, SOCK_DGRAM, 0); 158 if (sockfd < 0) { 159 tst_brkm(TBROK, cleanup, "call to socket() failed: %s", 160 strerror(errno)); 161 return -1; 162 } 163 sin1.sin_family = AF_INET; 164 sin1.sin_port = 0; /* pick random free port */ 165 sin1.sin_addr.s_addr = INADDR_ANY; 166 167 if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) { 168 tst_brkm(TBROK, cleanup, "call to bind() failed: %s", 169 strerror(errno)); 170 return -1; 171 } 172 SAFE_GETSOCKNAME(cleanup, sockfd, (struct sockaddr *)&sin1, &slen); 173 174 child_pid = FORK_OR_VFORK(); 175 if (child_pid < 0) { 176 tst_brkm(TBROK, cleanup, "client/server fork failed: %s", 177 strerror(errno)); 178 return -1; 179 } 180 181 if (!child_pid) { 182 #ifdef UCLINUX 183 if (self_exec(argv0, "") < 0) { 184 tst_brkm(TBROK, cleanup, "self_exec failed"); 185 return -1; 186 187 } 188 #else 189 do_child(); 190 #endif 191 } 192 193 s = socket(PF_INET, SOCK_DGRAM, 0); 194 inet_aton("127.0.0.1", &sin1.sin_addr); 195 196 if (s < 0) { 197 tst_brkm(TBROK, cleanup, "call to socket() failed: %s", 198 strerror(errno)); 199 return -1; 200 } 201 202 SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, sizeof(sin1)); 203 204 return s; 205 } 206 207 int main(int ac, char **av) 208 { 209 int lc; 210 211 tst_parse_opts(ac, av, NULL, NULL); 212 213 #ifdef UCLINUX 214 argv0 = av[0]; 215 maybe_run_child(&do_child, ""); 216 #endif 217 218 setup(); 219 220 for (lc = 0; TEST_LOOPING(lc); lc++) { 221 tst_count = 0; 222 223 do_sendfile(); 224 } 225 226 cleanup(); 227 tst_exit(); 228 } 229