X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=tests%2Ftest-pipe.c;h=404534da2bf5d0defbd0f8757f0b685c0d115680;hb=2bc9cabc544597791089f579a5a6d025792f47dc;hp=30181863fb76a1433943f3d0e5512183688657c6;hpb=fdccb1c31b8693bcda4faea73b0d81d1c3be0719;p=gnulib.git diff --git a/tests/test-pipe.c b/tests/test-pipe.c index 30181863f..404534da2 100644 --- a/tests/test-pipe.c +++ b/tests/test-pipe.c @@ -21,27 +21,78 @@ #include "wait-process.h" #include -#include #include #include #include #include +#include /* Depending on arguments, this test intentionally closes stderr or - starts life with stderr closed. So, the error messages might not - always print, but at least the exit status will be reliable. */ + starts life with stderr closed. So, we arrange to have fd 10 + (outside the range of interesting fd's during the test) set up to + duplicate the original stderr. */ + +#define BACKUP_STDERR_FILENO 10 +static FILE *myerr; + #define ASSERT(expr) \ do \ { \ if (!(expr)) \ { \ - fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ - fflush (stderr); \ + fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (myerr); \ abort (); \ } \ } \ while (0) +/* Code executed by the child process. argv[1] = "child". */ +static int +child_main (int argc, char *argv[]) +{ + char buffer[2] = { 's', 't' }; + int fd; + int ret; + + ASSERT (argc == 3); + + /* Read one byte from fd 0, and write its value plus one to fd 1. + fd 2 should be closed iff the argument is 1. Check that no other file + descriptors leaked. */ + + ASSERT (read (STDIN_FILENO, buffer, 2) == 1); + + buffer[0]++; + ASSERT (write (STDOUT_FILENO, buffer, 1) == 1); + + errno = 0; + ret = dup2 (STDERR_FILENO, STDERR_FILENO); + switch (atoi (argv[2])) + { + case 0: + /* Expect fd 2 is open. */ + ASSERT (ret == STDERR_FILENO); + break; + case 1: + /* Expect fd 2 is closed. */ + ASSERT (ret == -1); + ASSERT (errno == EBADF); + break; + default: + ASSERT (false); + } + + for (fd = 3; fd < 7; fd++) + { + errno = 0; + ASSERT (close (fd) == -1); + ASSERT (errno == EBADF); + } + + return 0; +} + /* Create a bi-directional pipe to a test child, and validate that the child program returns the expected output. The child is the same program as the parent ARGV0, but with different arguments. @@ -50,47 +101,50 @@ static void test_pipe (const char *argv0, bool stderr_closed) { int fd[2]; - const char *argv[3]; + char *argv[4]; pid_t pid; - char buffer[2] = { 'a', 'a' }; + char buffer[2] = { 'a', 't' }; /* Set up child. */ - argv[0] = argv0; - argv[1] = stderr_closed ? "9" : "8"; - argv[2] = NULL; - pid = create_pipe_bidi(argv0, argv0, (char **) argv, - false, true, true, fd); + argv[0] = (char *) argv0; + argv[1] = (char *) "child"; + argv[2] = (char *) (stderr_closed ? "1" : "0"); + argv[3] = NULL; + pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd); ASSERT (0 <= pid); ASSERT (STDERR_FILENO < fd[0]); ASSERT (STDERR_FILENO < fd[1]); /* Push child's input. */ ASSERT (write (fd[1], buffer, 1) == 1); + ASSERT (close (fd[1]) == 0); /* Get child's output. */ ASSERT (read (fd[0], buffer, 2) == 1); /* Wait for child. */ - ASSERT (wait_subprocess (pid, argv0, true, false, false, true, NULL) == 0); + ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0); ASSERT (close (fd[0]) == 0); - ASSERT (close (fd[1]) == 0); /* Check the result. */ ASSERT (buffer[0] == 'b'); - ASSERT (buffer[1] == 'a'); + ASSERT (buffer[1] == 't'); } -int -main (int argc, const char *argv[]) +/* Code executed by the parent process. */ +static int +parent_main (int argc, char *argv[]) { - int i; int test; + int fd; + ASSERT (argc == 2); + + /* Selectively close various standard fds, to verify the child process is + not impacted by this. */ test = atoi (argv[1]); switch (test) { - /* Driver cases. Selectively close various standard fds, to - ensure the child process is not impacted by this. */ case 0: break; case 1: @@ -119,42 +173,41 @@ main (int argc, const char *argv[]) close (1); close (2); break; - - /* Slave cases. Read one byte from fd 0, and write its value - plus one to fd 1. fd 2 should be closed iff the argument is - 9. Check that no other fd's leaked. */ - case 8: - case 9: - { - char buffer[1]; - ASSERT (read (STDIN_FILENO, buffer, 1) == 1); - buffer[0]++; - ASSERT (write (STDOUT_FILENO, buffer, 1) == 1); - errno = 0; - i = fcntl (STDERR_FILENO, F_GETFL); - if (test == 8) - ASSERT (0 <= i); - else - { - ASSERT (i < 0); - ASSERT (errno == EBADF); - } - for (i = 3; i < 7; i++) - { - errno = 0; - ASSERT (close (i) == -1); - ASSERT (errno == EBADF); - } - return 0; - } default: - ASSERT (0); + ASSERT (false); } - /* All remaining code is for the driver. Plug any leaks inherited - from outside world before starting, so that child has a clean - slate (at least for the fds that we might be manipulating). */ - for (i = 3; i < 7; i++) - close (i); - test_pipe (argv[0], 3 < test); + + /* Plug any file descriptor leaks inherited from outside world before + starting, so that child has a clean slate (at least for the fds that we + might be manipulating). */ + for (fd = 3; fd < 7; fd++) + close (fd); + + test_pipe (argv[0], test >= 4); + return 0; } + +int +main (int argc, char *argv[]) +{ + if (argc < 2) + { + fprintf (stderr, "%s: need arguments\n", argv[0]); + return 2; + } + if (strcmp (argv[1], "child") == 0) + { + /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original + stderr. */ + myerr = fdopen (BACKUP_STDERR_FILENO, "w"); + if (!myerr) + return 2; + return child_main (argc, argv); + } + /* We might close fd 2 later, so save it in fd 10. */ + if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO + || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL) + return 2; + return parent_main (argc, argv); +}