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