Remove building with NOCRYPTO option
[minix.git] / minix / tests / test68.c
blobd9e3bab653a1a935a178ead7ffb2cfcbf9195edb
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>
11 int max_error = 5;
12 #include "common.h"
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);
24 static int seen_pipe_signal = 0;
25 static int seen_alarm_signal = 0;
27 void
28 alarm_handler(int sig)
30 if (seen_pipe_signal == 0)
31 seen_pipe_signal = -1;
32 seen_alarm_signal = 1;
35 void
36 pipe_handler(int sig)
38 seen_pipe_signal = 1;
41 void
42 copy_subtests()
44 char *subtests[] = { "t68a", "t68b" };
45 char copy_cmd[8 + PATH_MAX + 1];
46 int i, no_tests;
48 no_tests = sizeof(subtests) / sizeof(char *);
50 for (i = 0; i < no_tests; i++) {
51 snprintf(copy_cmd, 8 + PATH_MAX, "cp ../%s .", subtests[i]);
52 system(copy_cmd);
56 void
57 test_pipe_normal()
59 /* Verify pipe2 creates pipes that behave like a normal pipe */
61 int pipes[2];
62 char buf_in[1], buf_out[1];
63 pid_t pid;
65 subtest = 2;
67 if (pipe2(pipes, 0) != 0) e(1);
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);
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);
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)
91 if (seen_pipe_signal != 1) e(10);
92 if (close(pipes[1]) != 0) e(11);
94 /* Collect alarm signal */
95 while (seen_alarm_signal == 0)
98 if (pipe2(pipes, 0) != 0) e(12);
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];
107 /* Verify we can still write a byte into the pipe */
108 if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(14);
110 snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[1]);
111 execl("./t68a", "t68a", fd_buf, NULL);
113 exit(1); /* Should not be reached */
114 } else {
115 /* We're the parent */
116 int result;
118 if (waitpid(pid, &result, 0) == -1) e(15);
119 if (WEXITSTATUS(result) != 0) e(16);
122 if (close(pipes[0]) != 0) e(17);
123 if (close(pipes[1]) != 0) e(18);
126 void
127 test_pipe_cloexec()
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];
135 subtest = 3;
137 if (pipe2(pipes, O_CLOEXEC) != 0) e(1);
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);
144 pid = fork();
145 if (pid < 0) e(4);
146 if (pid == 0) {
147 /* We're the child */
148 char fd_buf[2];
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);
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);
162 snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[0]);
163 execl("./t68b", "t68b", fd_buf, NULL);
165 exit(1); /* Should not be reached */
166 } else {
167 /* We're the parent */
168 int result;
170 if (waitpid(pid, &result, 0) == -1) e(10);
171 if (WEXITSTATUS(result) != 0) e(11);
174 /* Eventhough our child's pipe should've been closed upon exec, our
175 * pipe should still be functioning.
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);
183 if (close(pipes[0]) != 0) e(15);
184 if (close(pipes[1]) != 0) e(16);
187 void
188 test_pipe_nonblock()
190 /* Open a pipe with O_NONBLOCK */
191 char *buf_in, *buf_out;
192 int pipes[2];
193 size_t pipe_size;
195 subtest = 4;
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);
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.
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);
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);
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);
230 void
231 test_pipe_nosigpipe(void)
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];
238 subtest = 5;
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);
249 /* Collect alarm signal */
250 while (seen_alarm_signal == 0)
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);
257 void
258 test_pipe_flag_setting()
260 int pipes[2];
262 subtest = 1;
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) != 0) e(6);
271 if (fcntl(pipes[1], F_GETNOSIGPIPE) != 0) e(7);
272 if (close(pipes[0]) != 0) e(8);
273 if (close(pipes[1]) != 0) e(9);
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) == 0) e(15);
282 if (fcntl(pipes[1], F_GETNOSIGPIPE) == 0) e(16);
283 if (fcntl(pipes[0], F_SETNOSIGPIPE, 0) != 0) e(17);
284 if (fcntl(pipes[0], F_GETNOSIGPIPE) != 0) e(18);
285 if (fcntl(pipes[0], F_SETNOSIGPIPE, 1) != 0) e(19);
286 if (fcntl(pipes[0], F_GETNOSIGPIPE) == 0) e(20);
287 if (close(pipes[0]) != 0) e(21);
288 if (close(pipes[1]) != 0) e(22);
292 * Test the behavior of a large pipe write that achieves partial progress
293 * before the reader end is closed. The write call is expected to return EPIPE
294 * and generate a SIGPIPE signal, and otherwise leave the system in good order.
296 static void
297 test_pipe_partial_write(void)
299 char buf[PIPE_BUF + 2];
300 int pfd[2], status;
302 signal(SIGPIPE, pipe_handler);
304 if (pipe(pfd) < 0) e(1);
306 switch (fork()) {
307 case 0:
308 close(pfd[1]);
310 sleep(1); /* let the parent block on the write(2) */
313 * This one-byte read raises the question whether the write
314 * should return partial progress or not, since consumption of
315 * part of its data is now clearly visible. NetBSD chooses
316 * *not* to return partial progress, and MINIX3 follows suit.
318 if (read(pfd[0], buf, 1) != 1) e(2);
320 sleep(1); /* let VFS retry satisfying the write(2) */
322 exit(errct); /* close the reader side of the pipe */
324 case -1:
325 e(3);
327 default:
328 break;
331 close(pfd[0]);
333 seen_pipe_signal = 0;
336 * The following large write should block until the child exits, as
337 * that is when the read end closes, thus making eventual completion of
338 * the write impossible.
340 if (write(pfd[1], buf, sizeof(buf)) != -1) e(4);
341 if (errno != EPIPE) e(5);
342 if (seen_pipe_signal != 1) e(6);
344 seen_pipe_signal = 0;
346 /* A subsequent write used to cause a system crash. */
347 if (write(pfd[1], buf, 1) != -1) e(7);
348 if (errno != EPIPE) e(8);
349 if (seen_pipe_signal != 1) e(9);
351 /* Clean up. */
352 close(pfd[1]);
354 if (wait(&status) <= 0) e(10);
355 if (!WIFEXITED(status)) e(11);
356 errct += WEXITSTATUS(status);
360 main(int argc, char *argv[])
362 start(68);
363 copy_subtests();
364 test_pipe_flag_setting();
365 test_pipe_normal();
366 test_pipe_cloexec();
367 test_pipe_nonblock();
368 test_pipe_nosigpipe();
369 test_pipe_partial_write();
370 quit();
371 return(-1); /* Unreachable */