1272343Sngie/* Test case written by Bharat Joshi */
2272343Sngie#include <sys/cdefs.h>
3272343Sngie__RCSID("$NetBSD: t_fifo.c,v 1.1 2011/12/21 00:17:07 christos Exp $");
4272343Sngie
5272343Sngie#include <sys/types.h>
6272343Sngie#include <sys/wait.h>
7272343Sngie
8272343Sngie#include <stdio.h>
9272343Sngie#include <stdlib.h>
10272343Sngie#include <unistd.h>
11272343Sngie#include <fcntl.h>
12272343Sngie#include <errno.h>
13272343Sngie#include <string.h>
14272343Sngie#include <err.h>
15272343Sngie#include <signal.h>
16272343Sngie
17272343Sngie#ifndef STANDALONE
18272343Sngie#include <atf-c.h>
19272343Sngie#endif
20272343Sngie
21272343Sngie#define FIFO_FILE_PATH       "./fifo_file"
22272343Sngie#define NUM_MESSAGES         20
23272343Sngie#define MSG_SIZE             240
24272343Sngie#define MESSAGE              "I am fine"
25272343Sngie
26272343Sngiestatic int verbose = 0;
27272343Sngie
28272343Sngie/*
29272343Sngie * child_writer
30272343Sngie *
31272343Sngie * Function that runs in child context and opens and write to the FIFO.
32272343Sngie */
33272343Sngiestatic void
34272343Sngiechild_writer(void)
35272343Sngie{
36272343Sngie	ssize_t rv;
37272343Sngie	int fd;
38272343Sngie	size_t count;
39272343Sngie	char message[MSG_SIZE] = MESSAGE;
40272343Sngie	static const struct timespec ts = { 0, 10000 };
41272343Sngie
42272343Sngie	/* Open the fifo in write-mode */
43272343Sngie	for (;;) {
44272343Sngie		fd = open(FIFO_FILE_PATH, O_WRONLY, 0);
45272343Sngie		if (fd == -1) {
46272343Sngie			if (errno == EINTR)
47272343Sngie				continue;
48272343Sngie			err(1, "Child: can't open fifo in write mode");
49272343Sngie		}
50272343Sngie		break;
51272343Sngie	}
52272343Sngie
53272343Sngie	for (count = 0; count < NUM_MESSAGES; count++) {
54272343Sngie		rv = write(fd, message, MSG_SIZE);
55272343Sngie		if (rv == -1) {
56272343Sngie			warn("Child: Failed to write");
57272343Sngie			break;
58272343Sngie		}
59272343Sngie		if (rv != MSG_SIZE)
60272343Sngie			warnx("Child: wrote only %zd", rv);
61272343Sngie		nanosleep(&ts, NULL);
62272343Sngie	}
63272343Sngie
64272343Sngie	close(fd);
65272343Sngie	if (verbose) {
66272343Sngie		printf("Child: Closed the fifo file\n");
67272343Sngie		fflush(stdout);
68272343Sngie	}
69272343Sngie}
70272343Sngie
71272343Sngie/*
72272343Sngie * _sigchild_handler
73272343Sngie *
74272343Sngie * Called when a sigchild is delivered
75272343Sngie */
76272343Sngiestatic void
77272343Sngiesigchild_handler(int signo)
78272343Sngie{
79272343Sngie	if (verbose) {
80272343Sngie		if (signo == SIGCHLD) {
81272343Sngie			printf("Got sigchild\n");
82272343Sngie		} else {
83272343Sngie			printf("Got %d signal\n", signo);
84272343Sngie		}
85272343Sngie		fflush(stdout);
86272343Sngie	}
87272343Sngie
88272343Sngie}
89272343Sngie
90272343Sngiestatic int
91272343Sngierun(void)
92272343Sngie{
93272343Sngie	pid_t pid;
94272343Sngie	ssize_t rv;
95272343Sngie	int fd, status;
96272343Sngie	size_t buf_size = MSG_SIZE;
97272343Sngie	char buf[MSG_SIZE];
98272343Sngie	struct sigaction action;
99272343Sngie	static const struct timespec ts = { 0, 500000000 };
100272343Sngie
101272343Sngie	/* Catch sigchild Signal */
102272343Sngie	memset(&action, 0, sizeof(action));
103272343Sngie	action.sa_handler = sigchild_handler;
104272343Sngie	sigemptyset(&action.sa_mask);
105272343Sngie
106272343Sngie	if (sigaction(SIGCHLD, &action, NULL) == -1)
107272343Sngie		err(1, "sigaction");
108272343Sngie
109272343Sngie	(void)unlink(FIFO_FILE_PATH);
110272343Sngie	/* First create a fifo */
111272343Sngie	if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1)
112272343Sngie		err(1, "mkfifo");
113272343Sngie
114272343Sngie	switch ((pid = fork())) {
115272343Sngie	case -1:
116272343Sngie		err(1, "fork");
117272343Sngie	case 0:
118272343Sngie		/* Open the file in write mode so that subsequent read
119272343Sngie		 * from parent side does not block the parent..
120272343Sngie		 */
121272343Sngie		if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1)
122272343Sngie			err(1, "failed to open fifo");
123272343Sngie
124272343Sngie		/* In child */
125272343Sngie		child_writer();
126272343Sngie		return 0;
127272343Sngie
128272343Sngie	default:
129272343Sngie		break;
130272343Sngie	}
131272343Sngie
132272343Sngie	if (verbose) {
133272343Sngie		printf("Child pid is %d\n", pid );
134272343Sngie		fflush(stdout);
135272343Sngie	}
136272343Sngie
137272343Sngie	/* In parent */
138272343Sngie	for (;;) {
139272343Sngie		if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) {
140272343Sngie			if (errno == EINTR)
141272343Sngie				continue;
142272343Sngie			else
143272343Sngie				err(1, "Failed to open the fifo in read mode");
144272343Sngie		}
145272343Sngie		/* Read mode is opened */
146272343Sngie		break;
147272343Sngie
148272343Sngie	}
149272343Sngie
150272343Sngie	nanosleep(&ts, NULL);
151272343Sngie	if (verbose) {
152272343Sngie		printf("Was sleeping...\n");
153272343Sngie		fflush(stdout);
154272343Sngie	}
155272343Sngie
156272343Sngie	for (;;) {
157272343Sngie		rv = read(fd, buf, buf_size);
158272343Sngie
159272343Sngie		if (rv == -1) {
160272343Sngie			warn("Failed to read");
161272343Sngie			if (errno == EINTR) {
162272343Sngie				if (verbose) {
163272343Sngie					printf("Parent interrupted, "
164272343Sngie					    "continuing...\n");
165272343Sngie					fflush(stdout);
166272343Sngie				}
167272343Sngie				continue;
168272343Sngie			}
169272343Sngie
170272343Sngie			break;
171272343Sngie		}
172272343Sngie
173272343Sngie		if (rv == 0) {
174272343Sngie			if (verbose) {
175272343Sngie				printf("Writers have closed, looks like we "
176272343Sngie				    "are done\n");
177272343Sngie				fflush(stdout);
178272343Sngie			}
179272343Sngie			break;
180272343Sngie		}
181272343Sngie
182272343Sngie		if (verbose) {
183272343Sngie			printf("Received %zd bytes message '%s'\n", rv, buf);
184272343Sngie			fflush(stdout);
185272343Sngie		}
186272343Sngie	}
187272343Sngie
188272343Sngie	close(fd);
189272343Sngie
190272343Sngie	if (verbose) {
191272343Sngie		printf("We are done.. now reap the child");
192272343Sngie		fflush(stdout);
193272343Sngie	}
194272343Sngie
195272343Sngie	// Read the child...
196272343Sngie	while (waitpid(pid, &status, 0) == -1)
197272343Sngie		if (errno != EINTR) {
198272343Sngie			warn("Failed to reap the child");
199272343Sngie			return 1;
200272343Sngie		}
201272343Sngie
202272343Sngie	if (verbose) {
203272343Sngie		printf("We are done completely\n");
204272343Sngie		fflush(stdout);
205272343Sngie	}
206272343Sngie	return 0;
207272343Sngie}
208272343Sngie
209272343Sngie#ifndef STANDALONE
210272343SngieATF_TC(parent_child);
211272343Sngie
212272343SngieATF_TC_HEAD(parent_child, tc)
213272343Sngie{
214272343Sngie        atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared "
215272343Sngie	    "between a reader parent and a writer child, that read will "
216272343Sngie	    "return EOF, and not get stuck after the child exits");
217272343Sngie}
218272343Sngie
219272343SngieATF_TC_BODY(parent_child, tc)
220272343Sngie{
221272343Sngie        ATF_REQUIRE(run() == 0);
222272343Sngie}
223272343Sngie
224272343SngieATF_TP_ADD_TCS(tp)
225272343Sngie{
226272343Sngie        ATF_TP_ADD_TC(tp, parent_child);
227272343Sngie
228272343Sngie        return atf_no_error();
229272343Sngie}
230272343Sngie#else
231272343Sngieint
232272343Sngiemain(void)
233272343Sngie{
234272343Sngie	verbose = 1;
235272343Sngie	return run();
236272343Sngie}
237272343Sngie#endif
238