t_fifo.c revision 313535
1/* Test case written by Bharat Joshi */
2#include <sys/cdefs.h>
3__RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $");
4
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <sys/stat.h>
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <errno.h>
14#include <string.h>
15#include <err.h>
16#include <signal.h>
17
18#ifndef STANDALONE
19#include <atf-c.h>
20#endif
21
22#define FIFO_FILE_PATH       "./fifo_file"
23#define NUM_MESSAGES         20
24#define MSG_SIZE             240
25#define MESSAGE              "I am fine"
26
27static int verbose = 0;
28
29/*
30 * child_writer
31 *
32 * Function that runs in child context and opens and write to the FIFO.
33 */
34static void
35child_writer(void)
36{
37	ssize_t rv;
38	int fd;
39	size_t count;
40	char message[MSG_SIZE] = MESSAGE;
41	static const struct timespec ts = { 0, 10000 };
42
43	/* Open the fifo in write-mode */
44	for (;;) {
45		fd = open(FIFO_FILE_PATH, O_WRONLY, 0);
46		if (fd == -1) {
47			if (errno == EINTR)
48				continue;
49			err(1, "Child: can't open fifo in write mode");
50		}
51		break;
52	}
53
54	for (count = 0; count < NUM_MESSAGES; count++) {
55		rv = write(fd, message, MSG_SIZE);
56		if (rv == -1) {
57			warn("Child: Failed to write");
58			break;
59		}
60		if (rv != MSG_SIZE)
61			warnx("Child: wrote only %zd", rv);
62		nanosleep(&ts, NULL);
63	}
64
65	close(fd);
66	if (verbose) {
67		printf("Child: Closed the fifo file\n");
68		fflush(stdout);
69	}
70}
71
72/*
73 * _sigchild_handler
74 *
75 * Called when a sigchild is delivered
76 */
77static void
78sigchild_handler(int signo)
79{
80	if (verbose) {
81		if (signo == SIGCHLD) {
82			printf("Got sigchild\n");
83		} else {
84			printf("Got %d signal\n", signo);
85		}
86		fflush(stdout);
87	}
88
89}
90
91static int
92run(void)
93{
94	pid_t pid;
95	ssize_t rv;
96	int fd, status;
97	size_t buf_size = MSG_SIZE;
98	char buf[MSG_SIZE];
99	struct sigaction action;
100	static const struct timespec ts = { 0, 500000000 };
101
102	/* Catch sigchild Signal */
103	memset(&action, 0, sizeof(action));
104	action.sa_handler = sigchild_handler;
105	sigemptyset(&action.sa_mask);
106
107	if (sigaction(SIGCHLD, &action, NULL) == -1)
108		err(1, "sigaction");
109
110	(void)unlink(FIFO_FILE_PATH);
111	/* First create a fifo */
112	if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1)
113		err(1, "mkfifo");
114
115	switch ((pid = fork())) {
116	case -1:
117		err(1, "fork");
118	case 0:
119		/* Open the file in write mode so that subsequent read
120		 * from parent side does not block the parent..
121		 */
122		if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1)
123			err(1, "failed to open fifo");
124
125		/* In child */
126		child_writer();
127		return 0;
128
129	default:
130		break;
131	}
132
133	if (verbose) {
134		printf("Child pid is %d\n", pid );
135		fflush(stdout);
136	}
137
138	/* In parent */
139	for (;;) {
140		if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) {
141			if (errno == EINTR)
142				continue;
143			else
144				err(1, "Failed to open the fifo in read mode");
145		}
146		/* Read mode is opened */
147		break;
148
149	}
150
151	nanosleep(&ts, NULL);
152	if (verbose) {
153		printf("Was sleeping...\n");
154		fflush(stdout);
155	}
156
157	for (;;) {
158		rv = read(fd, buf, buf_size);
159
160		if (rv == -1) {
161			warn("Failed to read");
162			if (errno == EINTR) {
163				if (verbose) {
164					printf("Parent interrupted, "
165					    "continuing...\n");
166					fflush(stdout);
167				}
168				continue;
169			}
170
171			break;
172		}
173
174		if (rv == 0) {
175			if (verbose) {
176				printf("Writers have closed, looks like we "
177				    "are done\n");
178				fflush(stdout);
179			}
180			break;
181		}
182
183		if (verbose) {
184			printf("Received %zd bytes message '%s'\n", rv, buf);
185			fflush(stdout);
186		}
187	}
188
189	close(fd);
190
191	if (verbose) {
192		printf("We are done.. now reap the child");
193		fflush(stdout);
194	}
195
196	// Read the child...
197	while (waitpid(pid, &status, 0) == -1)
198		if (errno != EINTR) {
199			warn("Failed to reap the child");
200			return 1;
201		}
202
203	if (verbose) {
204		printf("We are done completely\n");
205		fflush(stdout);
206	}
207	return 0;
208}
209
210#ifndef STANDALONE
211ATF_TC(parent_child);
212
213ATF_TC_HEAD(parent_child, tc)
214{
215        atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared "
216	    "between a reader parent and a writer child, that read will "
217	    "return EOF, and not get stuck after the child exits");
218}
219
220ATF_TC_BODY(parent_child, tc)
221{
222        ATF_REQUIRE(run() == 0);
223}
224
225ATF_TP_ADD_TCS(tp)
226{
227        ATF_TP_ADD_TC(tp, parent_child);
228
229        return atf_no_error();
230}
231#else
232int
233main(void)
234{
235	verbose = 1;
236	return run();
237}
238#endif
239