1132438Ssilby/*
2132438SsilbyCopyright (C) 2004 Michael J. Silbersack. All rights reserved.
3132438Ssilby
4132438SsilbyRedistribution and use in source and binary forms, with or without
5132438Ssilbymodification, are permitted provided that the following conditions
6132438Ssilbyare met:
7132438Ssilby1. Redistributions of source code must retain the above copyright
8132438Ssilby   notice, this list of conditions and the following disclaimer.
9132438Ssilby2. Redistributions in binary form must reproduce the above copyright
10132438Ssilby   notice, this list of conditions and the following disclaimer in the
11132438Ssilby   documentation and/or other materials provided with the distribution.
12132438Ssilby
13132438SsilbyTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14132438SsilbyANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15132438SsilbyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16132438SsilbyARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17132438SsilbyFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18132438SsilbyDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19132438SsilbyOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20132438SsilbyHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21132438SsilbyLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22132438SsilbyOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23132438SsilbySUCH DAMAGE.
24132438Ssilby*/
25132438Ssilby
26290914Sngie#include <sys/types.h>
27290914Sngie#include <sys/stat.h>
28290914Sngie#include <sys/wait.h>
29309662Sngie#include <sys/event.h>
30290914Sngie#include <assert.h>
31290914Sngie#include <err.h>
32290914Sngie#include <errno.h>
33290914Sngie#include <inttypes.h>
34132438Ssilby#include <stdio.h>
35290914Sngie#include <stdlib.h>
36132438Ssilby#include <unistd.h>
37132438Ssilby
38132438Ssilby/*
39132438Ssilby * $FreeBSD: stable/10/tests/sys/kern/pipe/pipe_fstat_bug_test.c 309662 2016-12-07 00:57:15Z ngie $
40132438Ssilby * The goal of this program is to see if fstat reports the correct
41132438Ssilby * data count for a pipe.  Prior to revision 1.172 of sys_pipe.c,
42132438Ssilby * 0 would be returned once the pipe entered direct write mode.
43132438Ssilby *
44132438Ssilby * Linux (2.6) always returns zero, so it's not a valuable platform
45132438Ssilby * for comparison.
46132438Ssilby */
47132438Ssilby
48290914Sngieint
49290914Sngiemain(void)
50132438Ssilby{
51290914Sngie	char buffer[32768], buffer2[32768], go[] = "go", go2[] = "go2";
52290914Sngie	int desc[2], ipc_coord[2];
53309662Sngie	struct kevent event, ke;
54290914Sngie	ssize_t error;
55290914Sngie	int successes = 0;
56290914Sngie	struct stat status;
57290914Sngie	pid_t new_pid;
58309662Sngie	int kq;
59132438Ssilby
60290914Sngie	error = pipe(desc);
61290914Sngie	if (error == -1)
62290914Sngie		err(1, "Couldn't allocate data pipe");
63132438Ssilby
64290914Sngie	error = pipe(ipc_coord);
65290914Sngie	if (error == -1)
66290914Sngie		err(1, "Couldn't allocate IPC coordination pipe");
67132438Ssilby
68290914Sngie	new_pid = fork();
69290914Sngie	assert(new_pid != -1);
70132438Ssilby
71290914Sngie	close(new_pid == 0 ? desc[0] : desc[1]);
72290914Sngie
73290914Sngie#define	SYNC_R(i, _buf) do {	\
74290914Sngie	int _error = errno; \
75290914Sngie	warnx("%d: waiting for synchronization", __LINE__); \
76290914Sngie	if (read(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
77290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "parent" : "child")); \
78290914Sngie	errno = _error; \
79290914Sngie	} while(0)
80290914Sngie
81290914Sngie#define	SYNC_W(i, _buf) do {	\
82290914Sngie	int _error = errno; \
83290914Sngie	warnx("%d: sending synchronization", __LINE__); \
84290914Sngie	if (write(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
85290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "child" : "parent")); \
86290914Sngie	errno = _error; \
87290914Sngie	} while(0)
88290914Sngie
89290914Sngie#define	WRITE(s) do { 							\
90290914Sngie	ssize_t _size; 							\
91290914Sngie	if ((_size = write(desc[1], &buffer, s)) != s)			\
92290914Sngie		warn("short write; wrote %zd, expected %d", _size, s);	\
93290914Sngie	} while(0)
94290914Sngie
95290914Sngie	if (new_pid == 0) {
96290914Sngie
97290914Sngie		SYNC_R(0, go);
98290914Sngie		WRITE(145);
99290914Sngie		SYNC_W(0, go2);
100290914Sngie
101290914Sngie		SYNC_R(0, go);
102290914Sngie		WRITE(2048);
103290914Sngie		SYNC_W(0, go2);
104290914Sngie
105290914Sngie		SYNC_R(0, go);
106290914Sngie		WRITE(4096);
107290914Sngie		SYNC_W(0, go2);
108290914Sngie
109290914Sngie		SYNC_R(0, go);
110290914Sngie		WRITE(8191);
111290914Sngie		SYNC_W(0, go2);
112290914Sngie
113290914Sngie		SYNC_R(0, go);
114290914Sngie		SYNC_W(0, go2); /* XXX: why is this required? */
115290914Sngie		WRITE(8192);
116290914Sngie		SYNC_W(0, go2);
117290914Sngie
118290914Sngie		close(ipc_coord[0]);
119290914Sngie		close(ipc_coord[1]);
120290914Sngie
121290914Sngie		_exit(0);
122290914Sngie	}
123290914Sngie
124309662Sngie	kq = kqueue();
125309662Sngie	if (kq == -1)
126309662Sngie		_exit(1);
127309662Sngie
128309662Sngie	EV_SET(&ke, desc[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
129309662Sngie
130309662Sngie	/* Attach event to the kqueue. */
131309662Sngie	if (kevent(kq, &ke, 1, NULL, 0, NULL) != 0)
132309662Sngie		_exit(2);
133309662Sngie
134132438Ssilby	while (successes < 5) {
135290914Sngie		SYNC_W(1, go);
136290914Sngie		SYNC_R(1, go2);
137309662Sngie
138309662Sngie		/* Ensure data is available to read */
139309662Sngie		if (kevent(kq, NULL, 0, &event, 1, NULL) != 1)
140309662Sngie			_exit(3);
141309662Sngie
142132438Ssilby		fstat(desc[0], &status);
143290914Sngie		error = read(desc[0], &buffer2, sizeof(buffer2));
144290914Sngie
145132438Ssilby		if (status.st_size != error)
146290914Sngie			err(1, "FAILURE: stat size %jd read size %zd",
147290914Sngie			    (intmax_t)status.st_size, error);
148132438Ssilby		if (error > 0) {
149290914Sngie			printf("SUCCESS at stat size %jd read size %zd\n",
150290914Sngie			    (intmax_t)status.st_size, error);
151132438Ssilby			successes++;
152132438Ssilby		}
153132438Ssilby	}
154132438Ssilby
155290914Sngie	exit(0);
156132438Ssilby}
157