1132524Ssilby/*
2132524SsilbyCopyright (C) 2004 Michael J. Silbersack. All rights reserved.
3132524Ssilby
4132524SsilbyRedistribution and use in source and binary forms, with or without
5132524Ssilbymodification, are permitted provided that the following conditions
6132524Ssilbyare met:
7132524Ssilby1. Redistributions of source code must retain the above copyright
8132524Ssilby   notice, this list of conditions and the following disclaimer.
9132524Ssilby2. Redistributions in binary form must reproduce the above copyright
10132524Ssilby   notice, this list of conditions and the following disclaimer in the
11132524Ssilby   documentation and/or other materials provided with the distribution.
12132524Ssilby
13132524SsilbyTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14132524SsilbyANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15132524SsilbyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16132524SsilbyARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17132524SsilbyFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18132524SsilbyDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19132524SsilbyOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20132524SsilbyHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21132524SsilbyLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22132524SsilbyOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23132524SsilbySUCH DAMAGE.
24132524Ssilby*/
25132524Ssilby
26290914Sngie#include <sys/types.h>
27290914Sngie#include <sys/stat.h>
28290914Sngie#include <sys/wait.h>
29290914Sngie#include <assert.h>
30290914Sngie#include <err.h>
31290914Sngie#include <errno.h>
32132524Ssilby#include <stdio.h>
33290914Sngie#include <stdlib.h>
34290914Sngie#include <string.h>
35132524Ssilby#include <unistd.h>
36132524Ssilby
37132524Ssilby/*
38132524Ssilby * $FreeBSD$
39132524Ssilby * This program simply tests writing through the reverse direction of
40132524Ssilby * a pipe.  Nothing too fancy, it's only needed because most pipe-using
41132524Ssilby * programs never touch the reverse direction (it doesn't exist on
42132524Ssilby * Linux.)
43132524Ssilby */
44132524Ssilby
45290914Sngieint
46290914Sngiemain(void)
47132524Ssilby{
48290914Sngie	char buffer[65535], buffer2[65535], go[] = "go", go2[] = "go2";
49290914Sngie	int desc[2], ipc_coord[2];
50290914Sngie	size_t i;
51290914Sngie	ssize_t total;
52290914Sngie	int buggy, error;
53290914Sngie	pid_t new_pid;
54132524Ssilby
55290914Sngie	buggy = 0;
56290914Sngie	total = 0;
57132524Ssilby
58290914Sngie	error = pipe(desc);
59290914Sngie	if (error == -1)
60290914Sngie		err(1, "Couldn't allocate data pipe");
61132524Ssilby
62290914Sngie	error = pipe(ipc_coord);
63290914Sngie	if (error == -1)
64290914Sngie		err(1, "Couldn't allocate IPC coordination pipe");
65132524Ssilby
66290914Sngie	buffer[0] = 'A';
67132524Ssilby
68290914Sngie	for (i = 1; i < (int)sizeof(buffer); i++) {
69290914Sngie		buffer[i] = buffer[i - 1] + 1;
70290914Sngie		if (buffer[i] > 'Z')
71290914Sngie			buffer[i] = 'A';
72132524Ssilby	}
73132524Ssilby
74290914Sngie	new_pid = fork();
75290914Sngie	assert(new_pid != -1);
76132524Ssilby
77290914Sngie#define	SYNC_R(i, _buf) do {	\
78290914Sngie	int _error = errno; \
79290914Sngie	warnx("%d: waiting for synchronization", __LINE__); \
80290914Sngie	if (read(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
81290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "parent" : "child")); \
82290914Sngie	errno = _error; \
83290914Sngie	} while(0)
84290914Sngie
85290914Sngie#define	SYNC_W(i, _buf) do {	\
86290914Sngie	int _error = errno; \
87290914Sngie	warnx("%d: sending synchronization", __LINE__); \
88290914Sngie	if (write(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
89290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "child" : "parent")); \
90290914Sngie	errno = _error; \
91290914Sngie	} while(0)
92290914Sngie
93290914Sngie#define	WRITE(s) do { 							\
94290914Sngie	ssize_t _size; 							\
95290914Sngie	if ((_size = write(desc[1], &buffer[total], s)) != s)		\
96290914Sngie		warn("short write; wrote %zd, expected %d", _size, s);	\
97290914Sngie	total += _size;							\
98290914Sngie	} while(0)
99290914Sngie
100290914Sngie	if (new_pid == 0) {
101290914Sngie		SYNC_R(0, go);
102290914Sngie		for (i = 0; i < 8; i++)
103290914Sngie			WRITE(4096);
104290914Sngie
105290914Sngie		SYNC_W(0, go2);
106290914Sngie		SYNC_R(0, go);
107290914Sngie
108290914Sngie		for (i = 0; i < 2; i++)
109290914Sngie			WRITE(4096);
110290914Sngie
111290914Sngie		SYNC_W(0, go2);
112290914Sngie
113290914Sngie		_exit(0);
114290914Sngie	}
115290914Sngie
116290914Sngie	SYNC_W(1, go);
117290914Sngie	SYNC_R(1, go2);
118290914Sngie
119290914Sngie	error = read(desc[0], &buffer2, 8 * 4096);
120132524Ssilby	total += error;
121290914Sngie	printf("Read %d bytes\n", error);
122290914Sngie
123290914Sngie	SYNC_W(1, go);
124290914Sngie	SYNC_R(1, go2);
125290914Sngie
126290914Sngie	error = read(desc[0], &buffer2[total], 2 * 4096);
127132524Ssilby	total += error;
128132524Ssilby	printf("Read %d bytes, done\n", error);
129132524Ssilby
130290914Sngie	if (memcmp(buffer, buffer2, total) != 0) {
131290914Sngie		for (i = 0; i < (size_t)total; i++) {
132290914Sngie			if (buffer[i] != buffer2[i]) {
133290914Sngie				buggy = 1;
134290914Sngie				printf("Location %zu input: %hhx "
135290914Sngie				    "output: %hhx\n",
136290914Sngie				    i, buffer[i], buffer2[i]);
137290914Sngie			}
138132524Ssilby		}
139132524Ssilby	}
140132524Ssilby
141290914Sngie	waitpid(new_pid, NULL, 0);
142132524Ssilby
143290914Sngie	if ((buggy == 1) || (total != 10 * 4096))
144290914Sngie		errx(1, "FAILED");
145290914Sngie	else
146290914Sngie		printf("SUCCESS\n");
147132524Ssilby
148290914Sngie	exit(0);
149132524Ssilby}
150