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
27 static int verbose = 0;
28
29 /*
30 * child_writer
31 *
32 * Function that runs in child context and opens and write to the FIFO.
33 */
34 static void
child_writer(void)35 child_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 */
77 static void
sigchild_handler(int signo)78 sigchild_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
91 static int
run(void)92 run(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
211 ATF_TC(parent_child);
212
ATF_TC_HEAD(parent_child,tc)213 ATF_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
ATF_TC_BODY(parent_child,tc)220 ATF_TC_BODY(parent_child, tc)
221 {
222 ATF_REQUIRE(run() == 0);
223 }
224
ATF_TP_ADD_TCS(tp)225 ATF_TP_ADD_TCS(tp)
226 {
227 ATF_TP_ADD_TC(tp, parent_child);
228
229 return atf_no_error();
230 }
231 #else
232 int
main(void)233 main(void)
234 {
235 verbose = 1;
236 return run();
237 }
238 #endif
239