test68: test pipe2 functionality
Change-Id: Idb15ec83983d0b052232c9533f89d637229d19df
This commit is contained in:
parent
9c99b3b3b9
commit
2e723784ff
5 changed files with 375 additions and 4 deletions
|
@ -23,11 +23,12 @@ OBJS.test57=test57loop.o
|
||||||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||||
61 62 64 65 66 67
|
61 62 64 65 66 67 68
|
||||||
PROG+= test$(t)
|
PROG+= test$(t)
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
PROG+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b t67a t67b
|
PROG+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b \
|
||||||
|
t67a t67b t68a t68b
|
||||||
|
|
||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
|
@ -53,5 +54,5 @@ clean: .PHONY .MAKE
|
||||||
$(MAKE) -C select clean
|
$(MAKE) -C select clean
|
||||||
rm -rf *.o *.s *.bak test? test?? t10a t11a t11b \
|
rm -rf *.o *.s *.bak test? test?? t10a t11a t11b \
|
||||||
t40a t40b t40c t40d t40e t40f \
|
t40a t40b t40c t40d t40e t40f \
|
||||||
t60a t60b t67a t67b \
|
t60a t60b t67a t67b t68a t68b \
|
||||||
DIR*
|
DIR*
|
||||||
|
|
2
test/run
2
test/run
|
@ -14,7 +14,7 @@ badones= # list of tests that failed
|
||||||
tests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
tests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||||
61 62 63 64 65 66 67\
|
61 62 63 64 65 66 67 68\
|
||||||
sh1.sh sh2.sh interp.sh"
|
sh1.sh sh2.sh interp.sh"
|
||||||
tests_no=`expr 0`
|
tests_no=`expr 0`
|
||||||
|
|
||||||
|
|
33
test/t68a.c
Normal file
33
test/t68a.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, fd_parent;
|
||||||
|
char buf[1];
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_parent = atoi(argv[1]);
|
||||||
|
|
||||||
|
/* If we open a new file, the fd we obtain should be fd_parent + 1 */
|
||||||
|
fd = open("open_plusplus_fd", O_CREAT|O_RDWR, 0660);
|
||||||
|
if (fd != fd_parent + 1) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also, writing to fd_parent should succeed */
|
||||||
|
if (write(fd_parent, buf, sizeof(buf)) <= 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
39
test/t68b.c
Normal file
39
test/t68b.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, fd_parent;
|
||||||
|
char buf[1];
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_parent = atoi(argv[1]);
|
||||||
|
|
||||||
|
/* Writing to fd_parent should fail as it has to be closed at this
|
||||||
|
* point */
|
||||||
|
if (write(fd_parent, buf, sizeof(buf)) != -1) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (errno != EBADF) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we open a new file, the fd we obtain should be identical to
|
||||||
|
* fd_parent */
|
||||||
|
fd = open("open_identical_fd", O_CREAT|O_RDWR, 0660);
|
||||||
|
if (fd != fd_parent) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
298
test/test68.c
Normal file
298
test/test68.c
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAX_ERROR 5
|
||||||
|
#include "common.c"
|
||||||
|
|
||||||
|
void copy_subtests(void);
|
||||||
|
void test_pipe_cloexec(void);
|
||||||
|
void test_pipe_flag_setting(void);
|
||||||
|
void test_pipe_nonblock(void);
|
||||||
|
void test_pipe_normal(void);
|
||||||
|
void test_pipe_nosigpipe(void);
|
||||||
|
void alarm_handler(int sig);
|
||||||
|
void pipe_handler(int sig);
|
||||||
|
|
||||||
|
static int seen_pipe_signal = 0;
|
||||||
|
static int seen_alarm_signal = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
alarm_handler(int sig)
|
||||||
|
{
|
||||||
|
if (seen_pipe_signal == 0)
|
||||||
|
seen_pipe_signal = -1;
|
||||||
|
seen_alarm_signal = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pipe_handler(int sig)
|
||||||
|
{
|
||||||
|
seen_pipe_signal = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_subtests()
|
||||||
|
{
|
||||||
|
char *subtests[] = { "t68a", "t68b" };
|
||||||
|
char copy_cmd[8 + PATH_MAX + 1];
|
||||||
|
int i, no_tests;
|
||||||
|
|
||||||
|
no_tests = sizeof(subtests) / sizeof(char *);
|
||||||
|
|
||||||
|
for (i = 0; i < no_tests; i++) {
|
||||||
|
snprintf(copy_cmd, 8 + PATH_MAX, "cp ../%s .", subtests[i]);
|
||||||
|
system(copy_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_pipe_normal()
|
||||||
|
{
|
||||||
|
/* Verify pipe2 creates pipes that behave like a normal pipe */
|
||||||
|
|
||||||
|
int pipes[2];
|
||||||
|
char buf_in[1], buf_out[1];
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
subtest = 2;
|
||||||
|
|
||||||
|
if (pipe2(pipes, 0) != 0) e(1);
|
||||||
|
|
||||||
|
buf_out[0] = 'T';
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(2);
|
||||||
|
if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(3);
|
||||||
|
if (buf_out[0] != buf_in[0]) e(4);
|
||||||
|
|
||||||
|
/* When we close the write end, reading should fail */
|
||||||
|
if (close(pipes[1]) != 0) e(5);
|
||||||
|
if (read(pipes[0], buf_in, sizeof(buf_in)) != 0) e(6);
|
||||||
|
|
||||||
|
/* Let's retry that experiment the other way around. Install a signal
|
||||||
|
* handler to catch SIGPIPE. Install an alarm handler to make sure
|
||||||
|
* this test finishes in finite time. */
|
||||||
|
if (pipe2(pipes, 0) != 0) e(7);
|
||||||
|
signal(SIGPIPE, pipe_handler);
|
||||||
|
signal(SIGALRM, alarm_handler);
|
||||||
|
seen_pipe_signal = 0;
|
||||||
|
seen_alarm_signal = 0;
|
||||||
|
alarm(1);
|
||||||
|
if (close(pipes[0]) != 0) e(8);
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
|
||||||
|
while (seen_pipe_signal == 0)
|
||||||
|
;
|
||||||
|
if (seen_pipe_signal != 1) e(10);
|
||||||
|
if (close(pipes[1]) != 0) e(11);
|
||||||
|
|
||||||
|
/* Collect alarm signal */
|
||||||
|
while (seen_alarm_signal == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (pipe2(pipes, 0) != 0) e(12);
|
||||||
|
|
||||||
|
/* Now fork and verify we can write to the pipe */
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) e(13);
|
||||||
|
if (pid == 0) {
|
||||||
|
/* We're the child */
|
||||||
|
char fd_buf[2];
|
||||||
|
|
||||||
|
/* Verify we can still write a byte into the pipe */
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(14);
|
||||||
|
|
||||||
|
snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[1]);
|
||||||
|
execl("./t68a", "t68a", fd_buf, NULL);
|
||||||
|
|
||||||
|
exit(1); /* Should not be reached */
|
||||||
|
} else {
|
||||||
|
/* We're the parent */
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (waitpid(pid, &result, 0) == -1) e(15);
|
||||||
|
if (WEXITSTATUS(result) != 0) e(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close(pipes[0]) != 0) e(17);
|
||||||
|
if (close(pipes[1]) != 0) e(18);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_pipe_cloexec()
|
||||||
|
{
|
||||||
|
/* Open a pipe with O_CLOEXEC */
|
||||||
|
int flags;
|
||||||
|
int pipes[2];
|
||||||
|
pid_t pid;
|
||||||
|
char buf_in[1], buf_out[1];
|
||||||
|
|
||||||
|
subtest = 3;
|
||||||
|
|
||||||
|
if (pipe2(pipes, O_CLOEXEC) != 0) e(1);
|
||||||
|
|
||||||
|
/* Verify O_CLOEXEC flag is set */
|
||||||
|
flags = fcntl(pipes[0], F_GETFD);
|
||||||
|
if (flags < 0) e(2);
|
||||||
|
if (!(flags & FD_CLOEXEC)) e(3);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) e(4);
|
||||||
|
if (pid == 0) {
|
||||||
|
/* We're the child */
|
||||||
|
char fd_buf[2];
|
||||||
|
|
||||||
|
/* Verify we can still write a byte into the pipe */
|
||||||
|
buf_in[0] = 0;
|
||||||
|
buf_out[0] = 'T';
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(5);
|
||||||
|
if (read(pipes[0], buf_in, sizeof(buf_in)) != 1) e(6);
|
||||||
|
if (buf_out[0] != buf_in[0]) e(7);
|
||||||
|
|
||||||
|
/* Verify FD_CLOEXEC flag is still set */
|
||||||
|
flags = fcntl(pipes[0], F_GETFD);
|
||||||
|
if (flags < 0) e(8);
|
||||||
|
if (!(flags & FD_CLOEXEC)) e(9);
|
||||||
|
|
||||||
|
snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[0]);
|
||||||
|
execl("./t68b", "t68b", fd_buf, NULL);
|
||||||
|
|
||||||
|
exit(1); /* Should not be reached */
|
||||||
|
} else {
|
||||||
|
/* We're the parent */
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (waitpid(pid, &result, 0) == -1) e(10);
|
||||||
|
if (WEXITSTATUS(result) != 0) e(11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eventhough our child's pipe should've been closed upon exec, our
|
||||||
|
* pipe should still be functioning.
|
||||||
|
*/
|
||||||
|
buf_in[0] = 0;
|
||||||
|
buf_out[0] = 't';
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(12);
|
||||||
|
if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(13);
|
||||||
|
if (buf_out[0] != buf_in[0]) e(14);
|
||||||
|
|
||||||
|
if (close(pipes[0]) != 0) e(15);
|
||||||
|
if (close(pipes[1]) != 0) e(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_pipe_nonblock()
|
||||||
|
{
|
||||||
|
/* Open a pipe with O_NONBLOCK */
|
||||||
|
char *buf_in, *buf_out;
|
||||||
|
int pipes[2];
|
||||||
|
size_t pipe_size;
|
||||||
|
|
||||||
|
subtest = 4;
|
||||||
|
|
||||||
|
if (pipe2(pipes, O_NONBLOCK) != 0) e(1);
|
||||||
|
if ((pipe_size = fpathconf(pipes[0], _PC_PIPE_BUF)) == -1) e(2);
|
||||||
|
buf_in = calloc(2, pipe_size); /* Allocate twice the buffer size */
|
||||||
|
if (buf_in == NULL) e(3);
|
||||||
|
buf_out = calloc(2, pipe_size); /* Idem dito for output buffer */
|
||||||
|
if (buf_out == NULL) e(4);
|
||||||
|
|
||||||
|
/* According to POSIX, a pipe with O_NONBLOCK set shall never block.
|
||||||
|
* When we attempt to write PIPE_BUF or less bytes, and there is
|
||||||
|
* sufficient space available, write returns nbytes. Else write will
|
||||||
|
* return -1 and not transfer any data.
|
||||||
|
*/
|
||||||
|
if (write(pipes[1], buf_out, 1) != 1) e(5); /* Write 1 byte */
|
||||||
|
if (write(pipes[1], buf_out, pipe_size) != -1) e(6); /* Can't fit */
|
||||||
|
if (errno != EAGAIN) e(7);
|
||||||
|
|
||||||
|
/* When writing more than PIPE_BUF bytes and when at least 1 byte can
|
||||||
|
* be tranferred, return the number of bytes written. We've written 1
|
||||||
|
* byte, so there are PIPE_BUF - 1 bytes left. */
|
||||||
|
if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size - 1) e(8);
|
||||||
|
|
||||||
|
/* Read out all data and try again. This time we should be able to
|
||||||
|
* write PIPE_BUF bytes. */
|
||||||
|
if (read(pipes[0], buf_in, pipe_size) != pipe_size) e(9);
|
||||||
|
if (read(pipes[0], buf_in, 1) != -1) e(10); /* Empty, can't read */
|
||||||
|
if (errno != EAGAIN) e(11);
|
||||||
|
if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size) e(12);
|
||||||
|
if (close(pipes[0]) != 0) e(13);
|
||||||
|
if (close(pipes[1]) != 0) e(14);
|
||||||
|
free(buf_in);
|
||||||
|
free(buf_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_pipe_nosigpipe(void)
|
||||||
|
{
|
||||||
|
/* Let's retry the writing to pipe without readers experiment. This time we set
|
||||||
|
* the O_NOSIGPIPE flag to prevent getting a signal. */
|
||||||
|
int pipes[2];
|
||||||
|
char buf_out[1];
|
||||||
|
|
||||||
|
subtest = 5;
|
||||||
|
|
||||||
|
if (pipe2(pipes, O_NOSIGPIPE) != 0) e(7);
|
||||||
|
signal(SIGPIPE, pipe_handler);
|
||||||
|
signal(SIGALRM, alarm_handler);
|
||||||
|
seen_pipe_signal = 0;
|
||||||
|
seen_alarm_signal = 0;
|
||||||
|
alarm(1);
|
||||||
|
if (close(pipes[0]) != 0) e(8);
|
||||||
|
if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
|
||||||
|
|
||||||
|
/* Collect alarm signal */
|
||||||
|
while (seen_alarm_signal == 0)
|
||||||
|
;
|
||||||
|
if (errno != EPIPE) e(10);
|
||||||
|
if (seen_pipe_signal != -1) e(11); /* Alarm sig handler set it to -1 */
|
||||||
|
if (close(pipes[1]) != 0) e(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_pipe_flag_setting()
|
||||||
|
{
|
||||||
|
int pipes[2];
|
||||||
|
|
||||||
|
subtest = 1;
|
||||||
|
|
||||||
|
/* Create standard pipe with no flags and verify they're off */
|
||||||
|
if (pipe2(pipes, 0) != 0) e(1);
|
||||||
|
if (fcntl(pipes[0], F_GETFD) != 0) e(2);
|
||||||
|
if (fcntl(pipes[1], F_GETFD) != 0) e(3);
|
||||||
|
if (fcntl(pipes[0], F_GETFL) & O_NONBLOCK) e(4);
|
||||||
|
if (fcntl(pipes[1], F_GETFL) & O_NONBLOCK) e(5);
|
||||||
|
if (fcntl(pipes[0], F_GETNOSIGPIPE) != -1) e(6);
|
||||||
|
if (fcntl(pipes[1], F_GETNOSIGPIPE) != -1) e(7);
|
||||||
|
if (close(pipes[0]) != 0) e(8);
|
||||||
|
if (close(pipes[1]) != 0) e(9);
|
||||||
|
|
||||||
|
/* Create pipe with all flags and verify they're on */
|
||||||
|
if (pipe2(pipes, O_CLOEXEC|O_NONBLOCK|O_NOSIGPIPE) != 0) e(10);
|
||||||
|
if (fcntl(pipes[0], F_GETFD) != FD_CLOEXEC) e(11);
|
||||||
|
if (fcntl(pipes[1], F_GETFD) != FD_CLOEXEC) e(12);
|
||||||
|
if (!(fcntl(pipes[0], F_GETFL) & O_NONBLOCK)) e(13);
|
||||||
|
if (!(fcntl(pipes[1], F_GETFL) & O_NONBLOCK)) e(14);
|
||||||
|
if (fcntl(pipes[0], F_GETNOSIGPIPE) == -1) e(15);
|
||||||
|
if (fcntl(pipes[1], F_GETNOSIGPIPE) == -1) e(16);
|
||||||
|
if (close(pipes[0]) != 0) e(17);
|
||||||
|
if (close(pipes[1]) != 0) e(18);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
start(68);
|
||||||
|
copy_subtests();
|
||||||
|
test_pipe_flag_setting();
|
||||||
|
test_pipe_normal();
|
||||||
|
test_pipe_cloexec();
|
||||||
|
test_pipe_nonblock();
|
||||||
|
test_pipe_nosigpipe();
|
||||||
|
quit();
|
||||||
|
return(-1); /* Unreachable */
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue