1
2#include <sys/poll.h>
3#include <sys/socket.h>
4#include <sys/stat.h>
5
6#include <err.h>
7#include <fcntl.h>
8#include <signal.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12
13#define	FIFONAME	"fifo.tmp"
14#define	FT_END		3
15#define	FT_FIFO		2
16#define	FT_PIPE		0
17#define	FT_SOCKETPAIR	1
18
19static int filetype;
20
21static const char *
22decode_events(int events)
23{
24	char *ncresult;
25	const char *result;
26
27	switch (events) {
28	case POLLIN:
29		result = "POLLIN";
30		break;
31	case POLLHUP:
32		result = "POLLHUP";
33		break;
34	case POLLIN | POLLHUP:
35		result = "POLLIN | POLLHUP";
36		break;
37	default:
38		asprintf(&ncresult, "%#x", events);
39		result = ncresult;
40		break;
41	}
42	return (result);
43}
44
45static void
46report_state(const char *state)
47{
48
49	printf(" %s state %s: ",
50	    filetype == FT_PIPE ? "Pipe" :
51	    filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
52	    state);
53}
54
55static void
56report(int num, const char *state, int expected, int got, int res,
57    int res_expected)
58{
59
60	if (res != res_expected) {
61		printf("not ok %-2d", num);
62		report_state(state);
63		printf("poll result %d expected %d. ",
64		    res, res_expected);
65	} else {
66		if (expected == got)
67			printf("ok %-2d    ", num);
68		else
69			printf("not ok %-2d", num);
70		report_state(state);
71	}
72	printf("expected %s; got %s\n", decode_events(expected),
73	    decode_events(got));
74	fflush(stdout);
75}
76
77static pid_t cpid;
78static pid_t ppid;
79static volatile sig_atomic_t state;
80
81static void
82catch(int sig __unused)
83{
84
85	state++;
86}
87
88static void
89child(int fd, int num)
90{
91	struct pollfd pfd;
92	int fd2, res;
93	char buf[256];
94
95	if (filetype == FT_FIFO) {
96		fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
97		if (fd < 0)
98			err(1, "open for read");
99	}
100	pfd.fd = fd;
101	pfd.events = POLLIN;
102
103	if (filetype == FT_FIFO) {
104		if ((res = poll(&pfd, 1, 0)) < 0)
105			err(1, "poll");
106		report(num++, "0", 0, pfd.revents, res, 0);
107	}
108	kill(ppid, SIGUSR1);
109
110	usleep(1);
111	while (state != 1)
112		;
113	if (filetype != FT_FIFO) {
114		/*
115		 * The connection cannot be reestablished.  Use the code that
116		 * delays the read until after the writer disconnects since
117		 * that case is more interesting.
118		 */
119		state = 4;
120		goto state4;
121	}
122	if ((res = poll(&pfd, 1, 0)) < 0)
123		err(1, "poll");
124	report(num++, "1", 0, pfd.revents, res, 0);
125	kill(ppid, SIGUSR1);
126
127	usleep(1);
128	while (state != 2)
129		;
130	if ((res = poll(&pfd, 1, 0)) < 0)
131		err(1, "poll");
132	report(num++, "2", POLLIN, pfd.revents, res, 1);
133	if (read(fd, buf, sizeof buf) != 1)
134		err(1, "read");
135	if ((res = poll(&pfd, 1, 0)) < 0)
136		err(1, "poll");
137	report(num++, "2a", 0, pfd.revents, res, 0);
138	kill(ppid, SIGUSR1);
139
140	usleep(1);
141	while (state != 3)
142		;
143	if ((res = poll(&pfd, 1, 0)) < 0)
144		err(1, "poll");
145	report(num++, "3", POLLHUP, pfd.revents, res, 1);
146	kill(ppid, SIGUSR1);
147
148	/*
149	 * Now we expect a new writer, and a new connection too since
150	 * we read all the data.  The only new point is that we didn't
151	 * start quite from scratch since the read fd is not new.  Check
152	 * startup state as above, but don't do the read as above.
153	 */
154	usleep(1);
155	while (state != 4)
156		;
157state4:
158	if ((res = poll(&pfd, 1, 0)) < 0)
159		err(1, "poll");
160	report(num++, "4", 0, pfd.revents, res, 0);
161	kill(ppid, SIGUSR1);
162
163	usleep(1);
164	while (state != 5)
165		;
166	if ((res = poll(&pfd, 1, 0)) < 0)
167		err(1, "poll");
168	report(num++, "5", POLLIN, pfd.revents, res, 1);
169	kill(ppid, SIGUSR1);
170
171	usleep(1);
172	while (state != 6)
173		;
174	/*
175	 * Now we have no writer, but should still have data from the old
176	 * writer.  Check that we have both a data-readable condition and a
177	 * hangup condition, and that the data can be read in the usual way.
178	 * Since Linux does this, programs must not quit reading when they
179	 * see POLLHUP; they must see POLLHUP without POLLIN (or another
180	 * input condition) before they decide that there is EOF.  gdb-6.1.1
181	 * is an example of a broken program that quits on POLLHUP only --
182	 * see its event-loop.c.
183	 */
184	if ((res = poll(&pfd, 1, 0)) < 0)
185		err(1, "poll");
186	report(num++, "6", POLLIN | POLLHUP, pfd.revents, res, 1);
187	if (read(fd, buf, sizeof buf) != 1)
188		err(1, "read");
189	if ((res = poll(&pfd, 1, 0)) < 0)
190		err(1, "poll");
191	report(num++, "6a", POLLHUP, pfd.revents, res, 1);
192	if (filetype == FT_FIFO) {
193		/*
194		 * Check that POLLHUP is sticky for a new reader and for
195		 * the old reader.
196		 */
197		fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
198		if (fd2 < 0)
199			err(1, "open for read");
200		pfd.fd = fd2;
201		if ((res = poll(&pfd, 1, 0)) < 0)
202			err(1, "poll");
203		report(num++, "6b", POLLHUP, pfd.revents, res, 1);
204		pfd.fd = fd;
205		if ((res = poll(&pfd, 1, 0)) < 0)
206			err(1, "poll");
207		report(num++, "6c", POLLHUP, pfd.revents, res, 1);
208		close(fd2);
209		if ((res = poll(&pfd, 1, 0)) < 0)
210			err(1, "poll");
211		report(num++, "6d", POLLHUP, pfd.revents, res, 1);
212	}
213	close(fd);
214	kill(ppid, SIGUSR1);
215
216	exit(0);
217}
218
219static void
220parent(int fd)
221{
222	usleep(1);
223	while (state != 1)
224		;
225	if (filetype == FT_FIFO) {
226		fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
227		if (fd < 0)
228			err(1, "open for write");
229	}
230	kill(cpid, SIGUSR1);
231
232	usleep(1);
233	while (state != 2)
234		;
235	if (write(fd, "", 1) != 1)
236		err(1, "write");
237	kill(cpid, SIGUSR1);
238
239	usleep(1);
240	while (state != 3)
241		;
242	if (close(fd) != 0)
243		err(1, "close for write");
244	kill(cpid, SIGUSR1);
245
246	usleep(1);
247	while (state != 4)
248		;
249	if (filetype != FT_FIFO)
250		return;
251	fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
252	if (fd < 0)
253		err(1, "open for write");
254	kill(cpid, SIGUSR1);
255
256	usleep(1);
257	while (state != 5)
258		;
259	if (write(fd, "", 1) != 1)
260		err(1, "write");
261	kill(cpid, SIGUSR1);
262
263	usleep(1);
264	while (state != 6)
265		;
266	if (close(fd) != 0)
267		err(1, "close for write");
268	kill(cpid, SIGUSR1);
269
270	usleep(1);
271	while (state != 7)
272		;
273}
274
275int
276main(void)
277{
278	int fd[2], num;
279
280	num = 1;
281	printf("1..20\n");
282	fflush(stdout);
283	signal(SIGUSR1, catch);
284	ppid = getpid();
285	for (filetype = 0; filetype < FT_END; filetype++) {
286		switch (filetype) {
287		case FT_FIFO:
288			if (mkfifo(FIFONAME, 0666) != 0)
289				err(1, "mkfifo");
290			fd[0] = -1;
291			fd[1] = -1;
292			break;
293		case FT_SOCKETPAIR:
294			if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
295			    fd) != 0)
296				err(1, "socketpair");
297			break;
298		case FT_PIPE:
299			if (pipe(fd) != 0)
300				err(1, "pipe");
301			break;
302		}
303		state = 0;
304		switch (cpid = fork()) {
305		case -1:
306			err(1, "fork");
307		case 0:
308			(void)close(fd[1]);
309			child(fd[0], num);
310			break;
311		default:
312			(void)close(fd[0]);
313			parent(fd[1]);
314			break;
315		}
316		num += filetype == FT_FIFO ? 12 : 4;
317	}
318	(void)unlink(FIFONAME);
319	return (0);
320}
321