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