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