175142Sbmah#!/bin/sh 275142Sbmah 375142Sbmah# 475142Sbmah# Copyright (c) 2013 Peter Holm <pho@FreeBSD.org> 575142Sbmah# All rights reserved. 675142Sbmah# 775142Sbmah# Redistribution and use in source and binary forms, with or without 875142Sbmah# modification, are permitted provided that the following conditions 975142Sbmah# are met: 1075142Sbmah# 1. Redistributions of source code must retain the above copyright 1175142Sbmah# notice, this list of conditions and the following disclaimer. 1275142Sbmah# 2. Redistributions in binary form must reproduce the above copyright 1375142Sbmah# notice, this list of conditions and the following disclaimer in the 1475142Sbmah# documentation and/or other materials provided with the distribution. 1575142Sbmah# 1675142Sbmah# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1775142Sbmah# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1875142Sbmah# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1975142Sbmah# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2075142Sbmah# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2175142Sbmah# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2275142Sbmah# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2375142Sbmah# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2475142Sbmah# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2575142Sbmah# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2675142Sbmah# SUCH DAMAGE. 2775142Sbmah# 2875142Sbmah 2975142Sbmah# Test scenario by Nate Eldredge neldredge math ucsdnedu 3075142Sbmah 3175142Sbmah# kern/127213: [tmpfs] sendfile on tmpfs data corruption 3275142Sbmah 3375142Sbmah[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 3475142Sbmah 3575142Sbmah. ../default.cfg 3698766Smarkm 3775142Sbmahset -e 3875142Sbmah 3975142Sbmahodir=`pwd` 4075142Sbmahcd /tmp 4175142Sbmahcat > server.c <<EOF 4275142Sbmah#include <stdio.h> 4375142Sbmah#include <fcntl.h> 4475142Sbmah#include <unistd.h> 4575142Sbmah#include <stdlib.h> 4675142Sbmah#include "util.h" 4775142Sbmah 4875142Sbmahint main(int argc, char *argv[]) { 4975142Sbmah int f, listener, connection; 5075142Sbmah if (argc < 3) { 5175142Sbmah fprintf(stderr, "Usage: %s filename socketname\n", argv[0]); 5275142Sbmah exit(1); 53151200Skrion } 5475142Sbmah if ((f = open(argv[1], O_RDONLY)) < 0) { 5575142Sbmah perror(argv[1]); 5675142Sbmah exit(1); 5775142Sbmah } 5875142Sbmah if ((listener = listen_unix_socket(argv[2])) < 0) { 5975142Sbmah exit(1); 6075142Sbmah } 6175142Sbmah if ((connection = accept_unix_socket(listener)) >= 0) { 6275142Sbmah real_sendfile(f, connection); 6375142Sbmah } 6475715Sbmah return 0; 6575715Sbmah} 6675715SbmahEOF 6775142Sbmahcat > client.c <<EOF 6875142Sbmah#include <stdio.h> 6975142Sbmah#include <fcntl.h> 7097411Ssobomax#include <unistd.h> 7197411Ssobomax#include <stdlib.h> 7275142Sbmah#include "util.h" 7375142Sbmah 7475142Sbmahint main(int argc, char *argv[]) { 7575142Sbmah int s; 76131274Seik if (argc < 2) { 77131274Seik fprintf(stderr, "Usage: %s socketname\n", argv[0]); 78131274Seik exit(1); 79131274Seik } 80131274Seik if ((s = connect_unix_socket(argv[1])) < 0) { 81131274Seik exit(1); 82131274Seik } 83131274Seik fake_sendfile(s, 1); 84131274Seik return 0; 85131274Seik} 86131274SeikEOF 87131274Seik 88131274Seikcat > util.c <<EOF 89131274Seik/* send data from file to unix domain socket */ 90131274Seik 91131274Seik#include <stdio.h> 92131274Seik#include <time.h> 93131274Seik#include <signal.h> 94131274Seik#include <errno.h> 95#include <sys/types.h> 96#include <sys/socket.h> 97#include <sys/un.h> 98#include <string.h> 99#include <stdlib.h> 100#include <unistd.h> 101 102int create_unix_socket(void) { 103 int fd; 104 if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { 105 perror("socket"); 106 return -1; 107 } 108 return fd; 109} 110 111int make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa) { 112 memset(sa, 0, sizeof(*sa)); 113 sa->sun_family = PF_LOCAL; 114 if (strlen(pathname) + 1 > sizeof(sa->sun_path)) { 115// fprintf(stderr, "%s: pathname too long (max %lu)\n", 116// pathname, sizeof(sa->sun_path)); 117 errno = ENAMETOOLONG; 118 return -1; 119 } 120 strcpy(sa->sun_path, pathname); 121 return 0; 122} 123 124static char *sockname; 125void delete_socket(void) { 126 unlink(sockname); 127} 128 129int listen_unix_socket(const char *path) { 130 int fd; 131 struct sockaddr_un sa; 132 if (make_unix_sockaddr(path, &sa) < 0) 133 return -1; 134 if ((fd = create_unix_socket()) < 0) 135 return -1; 136 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 137 perror("bind"); 138 close(fd); 139 return -1; 140 } 141 sockname = strdup(path); 142 atexit(delete_socket); 143 144 if (listen(fd, 5) < 0) { 145 perror("listen"); 146 close(fd); 147 return -1; 148 } 149 return fd; 150} 151 152int accept_unix_socket(int fd) { 153 int s; 154 if ((s = accept(fd, NULL, 0)) < 0) { 155 perror("accept"); 156 return -1; 157 } 158 return s; 159} 160 161int connect_unix_socket(const char *path) { 162 int fd; 163 struct sockaddr_un sa; 164 if (make_unix_sockaddr(path, &sa) < 0) 165 return -1; 166 if ((fd = create_unix_socket()) < 0) 167 return -1; 168 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 169 perror("connect"); 170 return -1; 171 } 172 return fd; 173} 174 175#define BUFSIZE 65536 176 177int fake_sendfile(int from, int to) { 178 char buf[BUFSIZE]; 179 int v; 180 int sent = 0; 181 while ((v = read(from, buf, BUFSIZE)) > 0) { 182 int d = 0; 183 while (d < v) { 184 int w = write(to, buf, v - d); 185 if (w <= 0) { 186 perror("write"); 187 return -1; 188 } 189 d += w; 190 sent += w; 191 } 192 } 193 if (v != 0) { 194 perror("read"); 195 return -1; 196 } 197 return sent; 198} 199 200int real_sendfile(int from, int to) { 201 int v; 202 v = sendfile(from, to, 0, 0, NULL, NULL, 0); 203 if (v < 0) { 204 perror("sendfile"); 205 } 206 return v; 207} 208EOF 209 210cat > util.h <<EOF 211/* send data from file to unix domain socket */ 212 213#include <stdio.h> 214#include <time.h> 215#include <signal.h> 216#include <errno.h> 217#include <sys/types.h> 218#include <sys/socket.h> 219#include <sys/un.h> 220 221int create_unix_socket(void); 222int make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa); 223int listen_unix_socket(const char *path); 224int accept_unix_socket(int fd); 225int connect_unix_socket(const char *path); 226int fake_sendfile(int from, int to); 227int real_sendfile(int from, int to); 228EOF 229 230mycc -c -Wall -Wextra -O2 util.c 231mycc -o server -Wall -Wextra -O2 server.c util.o 232mycc -o client -Wall -Wextra -O2 client.c util.o 233rm -f server.c client.c util.c util.o util.h mysocket 234 235mount | grep "$mntpoint" | grep -q tmpfs && umount $mntpoint 236mount -t tmpfs tmpfs $mntpoint 237 238dd if=/dev/random of=$mntpoint/data bs=123456 count=1 status=none 239./server $mntpoint/data mysocket & 240sleep 0.2 241./client mysocket > data.$$ 242cmp $mntpoint/data data.$$ || 243 { echo "FAIL Data mismatch"; ls -l $mntpoint/data data.$$; } 244rm -f data.$$ server client mysocket 245 246wait 247while mount | grep "$mntpoint" | grep -q tmpfs; do 248 umount $mntpoint || sleep 1 249done 250