xref: /minix/minix/tests/test68.c (revision 83133719)
1 #include <sys/types.h>
2 #include <sys/wait.h>
3 #include <sys/syslimits.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <signal.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 
11 int max_error = 5;
12 #include "common.h"
13 
14 
15 void copy_subtests(void);
16 void test_pipe_cloexec(void);
17 void test_pipe_flag_setting(void);
18 void test_pipe_nonblock(void);
19 void test_pipe_normal(void);
20 void test_pipe_nosigpipe(void);
21 void alarm_handler(int sig);
22 void pipe_handler(int sig);
23 
24 static int seen_pipe_signal = 0;
25 static int seen_alarm_signal = 0;
26 
27 void
28 alarm_handler(int sig)
29 {
30 	if (seen_pipe_signal == 0)
31 		seen_pipe_signal = -1;
32 	seen_alarm_signal = 1;
33 }
34 
35 void
36 pipe_handler(int sig)
37 {
38 	seen_pipe_signal = 1;
39 }
40 
41 void
42 copy_subtests()
43 {
44 	char *subtests[] = { "t68a", "t68b" };
45 	char copy_cmd[8 + PATH_MAX + 1];
46 	int i, no_tests;
47 
48 	no_tests = sizeof(subtests) / sizeof(char *);
49 
50 	for (i = 0; i < no_tests; i++) {
51 		snprintf(copy_cmd, 8 + PATH_MAX, "cp ../%s .", subtests[i]);
52 		system(copy_cmd);
53 	}
54 }
55 
56 void
57 test_pipe_normal()
58 {
59 /* Verify pipe2 creates pipes that behave like a normal pipe */
60 
61 	int pipes[2];
62 	char buf_in[1], buf_out[1];
63 	pid_t pid;
64 
65 	subtest = 2;
66 
67 	if (pipe2(pipes, 0) != 0) e(1);
68 
69 	buf_out[0] = 'T';
70 	if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(2);
71 	if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(3);
72 	if (buf_out[0] != buf_in[0]) e(4);
73 
74 	/* When we close the write end, reading should fail */
75 	if (close(pipes[1]) != 0) e(5);
76 	if (read(pipes[0], buf_in, sizeof(buf_in)) != 0) e(6);
77 
78 	/* Let's retry that experiment the other way around. Install a signal
79 	 * handler to catch SIGPIPE. Install an alarm handler to make sure
80 	 * this test finishes in finite time. */
81 	if (pipe2(pipes, 0) != 0) e(7);
82 	signal(SIGPIPE, pipe_handler);
83 	signal(SIGALRM, alarm_handler);
84 	seen_pipe_signal = 0;
85 	seen_alarm_signal = 0;
86 	alarm(1);
87 	if (close(pipes[0]) != 0) e(8);
88 	if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
89 	while (seen_pipe_signal == 0)
90 		;
91 	if (seen_pipe_signal != 1) e(10);
92 	if (close(pipes[1]) != 0) e(11);
93 
94 	/* Collect alarm signal */
95 	while (seen_alarm_signal == 0)
96 		;
97 
98 	if (pipe2(pipes, 0) != 0) e(12);
99 
100 	/* Now fork and verify we can write to the pipe */
101 	pid = fork();
102 	if (pid < 0) e(13);
103 	if (pid == 0) {
104 		/* We're the child */
105 		char fd_buf[2];
106 
107 		/* Verify we can still write a byte into the pipe */
108 		if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(14);
109 
110 		snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[1]);
111 		execl("./t68a", "t68a", fd_buf, NULL);
112 
113 		exit(1); /* Should not be reached */
114 	} else {
115 		/* We're the parent */
116 		int result;
117 
118 		if (waitpid(pid, &result, 0) == -1) e(15);
119 		if (WEXITSTATUS(result) != 0) e(16);
120 	}
121 
122 	if (close(pipes[0]) != 0) e(17);
123 	if (close(pipes[1]) != 0) e(18);
124 }
125 
126 void
127 test_pipe_cloexec()
128 {
129 /* Open a pipe with O_CLOEXEC */
130 	int flags;
131 	int pipes[2];
132 	pid_t pid;
133 	char buf_in[1], buf_out[1];
134 
135 	subtest = 3;
136 
137 	if (pipe2(pipes, O_CLOEXEC) != 0) e(1);
138 
139 	/* Verify O_CLOEXEC flag is set */
140 	flags = fcntl(pipes[0], F_GETFD);
141 	if (flags < 0) e(2);
142 	if (!(flags & FD_CLOEXEC)) e(3);
143 
144 	pid = fork();
145 	if (pid < 0) e(4);
146 	if (pid == 0) {
147 		/* We're the child */
148 		char fd_buf[2];
149 
150 		/* Verify we can still write a byte into the pipe */
151 		buf_in[0] = 0;
152 		buf_out[0] = 'T';
153 		if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(5);
154 		if (read(pipes[0], buf_in, sizeof(buf_in)) != 1) e(6);
155 		if (buf_out[0] != buf_in[0]) e(7);
156 
157 		/* Verify FD_CLOEXEC flag is still set */
158 		flags = fcntl(pipes[0], F_GETFD);
159 		if (flags < 0) e(8);
160 		if (!(flags & FD_CLOEXEC)) e(9);
161 
162 		snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[0]);
163 		execl("./t68b", "t68b", fd_buf, NULL);
164 
165 		exit(1); /* Should not be reached */
166 	} else {
167 		/* We're the parent */
168 		int result;
169 
170 		if (waitpid(pid, &result, 0) == -1) e(10);
171 		if (WEXITSTATUS(result) != 0) e(11);
172 	}
173 
174 	/* Eventhough our child's pipe should've been closed upon exec, our
175 	 * pipe should still be functioning.
176 	 */
177 	buf_in[0] = 0;
178 	buf_out[0] = 't';
179 	if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(12);
180 	if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(13);
181 	if (buf_out[0] != buf_in[0]) e(14);
182 
183 	if (close(pipes[0]) != 0) e(15);
184 	if (close(pipes[1]) != 0) e(16);
185 }
186 
187 void
188 test_pipe_nonblock()
189 {
190 /* Open a pipe with O_NONBLOCK */
191 	char *buf_in, *buf_out;
192 	int pipes[2];
193 	size_t pipe_size;
194 
195 	subtest = 4;
196 
197 	if (pipe2(pipes, O_NONBLOCK) != 0) e(1);
198 	if ((pipe_size = fpathconf(pipes[0], _PC_PIPE_BUF)) == -1) e(2);
199 	buf_in = calloc(2, pipe_size); /* Allocate twice the buffer size */
200 	if (buf_in == NULL) e(3);
201 	buf_out = calloc(2, pipe_size); /* Idem dito for output buffer */
202 	if (buf_out == NULL) e(4);
203 
204 	/* According to POSIX, a pipe with O_NONBLOCK set shall never block.
205 	 * When we attempt to write PIPE_BUF or less bytes, and there is
206 	 * sufficient space available, write returns nbytes. Else write will
207 	 * return -1 and not transfer any data.
208 	 */
209 	if (write(pipes[1], buf_out, 1) != 1) e(5);	/* Write 1 byte */
210 	if (write(pipes[1], buf_out, pipe_size) != -1) e(6);	/* Can't fit */
211 	if (errno != EAGAIN) e(7);
212 
213 	/* When writing more than PIPE_BUF bytes and when at least 1 byte can
214 	 * be tranferred, return the number of bytes written. We've written 1
215 	 * byte, so there are PIPE_BUF - 1 bytes left. */
216 	if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size - 1) e(8);
217 
218 	/* Read out all data and try again. This time we should be able to
219 	 * write PIPE_BUF bytes. */
220 	if (read(pipes[0], buf_in, pipe_size) != pipe_size) e(9);
221 	if (read(pipes[0], buf_in, 1) != -1) e(10);	/* Empty, can't read */
222 	if (errno != EAGAIN) e(11);
223 	if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size) e(12);
224 	if (close(pipes[0]) != 0) e(13);
225 	if (close(pipes[1]) != 0) e(14);
226 	free(buf_in);
227 	free(buf_out);
228 }
229 
230 void
231 test_pipe_nosigpipe(void)
232 {
233 /* Let's retry the writing to pipe without readers experiment. This time we set
234  * the O_NOSIGPIPE flag to prevent getting a signal. */
235 	int pipes[2];
236 	char buf_out[1];
237 
238 	subtest = 5;
239 
240 	if (pipe2(pipes, O_NOSIGPIPE) != 0) e(7);
241 	signal(SIGPIPE, pipe_handler);
242 	signal(SIGALRM, alarm_handler);
243 	seen_pipe_signal = 0;
244 	seen_alarm_signal = 0;
245 	alarm(1);
246 	if (close(pipes[0]) != 0) e(8);
247 	if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
248 
249 	/* Collect alarm signal */
250 	while (seen_alarm_signal == 0)
251 		;
252 	if (errno != EPIPE) e(10);
253 	if (seen_pipe_signal != -1) e(11); /* Alarm sig handler set it to -1 */
254 	if (close(pipes[1]) != 0) e(12);
255 }
256 
257 void
258 test_pipe_flag_setting()
259 {
260 	int pipes[2];
261 
262 	subtest = 1;
263 
264 	/* Create standard pipe with no flags and verify they're off */
265 	if (pipe2(pipes, 0) != 0) e(1);
266 	if (fcntl(pipes[0], F_GETFD) != 0) e(2);
267 	if (fcntl(pipes[1], F_GETFD) != 0) e(3);
268 	if (fcntl(pipes[0], F_GETFL) & O_NONBLOCK) e(4);
269 	if (fcntl(pipes[1], F_GETFL) & O_NONBLOCK) e(5);
270 	if (fcntl(pipes[0], F_GETNOSIGPIPE) != -1) e(6);
271 	if (fcntl(pipes[1], F_GETNOSIGPIPE) != -1) e(7);
272 	if (close(pipes[0]) != 0) e(8);
273 	if (close(pipes[1]) != 0) e(9);
274 
275 	/* Create pipe with all flags and verify they're on */
276 	if (pipe2(pipes, O_CLOEXEC|O_NONBLOCK|O_NOSIGPIPE) != 0) e(10);
277 	if (fcntl(pipes[0], F_GETFD) != FD_CLOEXEC) e(11);
278 	if (fcntl(pipes[1], F_GETFD) != FD_CLOEXEC) e(12);
279 	if (!(fcntl(pipes[0], F_GETFL) & O_NONBLOCK)) e(13);
280 	if (!(fcntl(pipes[1], F_GETFL) & O_NONBLOCK)) e(14);
281 	if (fcntl(pipes[0], F_GETNOSIGPIPE) == -1) e(15);
282 	if (fcntl(pipes[1], F_GETNOSIGPIPE) == -1) e(16);
283 	if (close(pipes[0]) != 0) e(17);
284 	if (close(pipes[1]) != 0) e(18);
285 }
286 
287 int
288 main(int argc, char *argv[])
289 {
290 	start(68);
291 	copy_subtests();
292 	test_pipe_flag_setting();
293 	test_pipe_normal();
294 	test_pipe_cloexec();
295 	test_pipe_nonblock();
296 	test_pipe_nosigpipe();
297 	quit();
298 	return(-1);	/* Unreachable */
299 }
300 
301