-/* Test of create_pipe_bidi/wait_subprocess.
- Copyright (C) 2009 Free Software Foundation, Inc.
+/* Test of pipe.
+ Copyright (C) 2009-2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <config.h>
-#include "pipe.h"
-#include "wait-process.h"
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (pipe, int, (int[2]));
-#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* 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. */
-#define ASSERT(expr) \
- do \
- { \
- if (!(expr)) \
- { \
- fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
- fflush (stderr); \
- abort (); \
- } \
- } \
- while (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.
- STDERR_CLOSED is true if we have already closed fd 2. */
-static void
-test_pipe (const char *argv0, bool stderr_closed)
-{
- int fd[2];
- const char *argv[3];
- pid_t pid;
- char buffer[2] = { 'a', 'a' };
- /* 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);
- ASSERT (0 <= pid);
- ASSERT (STDERR_FILENO < fd[0]);
- ASSERT (STDERR_FILENO < fd[1]);
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the Win32 API functions. */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
- /* Push child's input. */
- ASSERT (write (fd[1], buffer, 1) == 1);
+#include "binary-io.h"
+#include "macros.h"
- /* Get child's output. */
- ASSERT (read (fd[0], buffer, 2) == 1);
+/* Return true if FD is open. */
+static bool
+is_open (int fd)
+{
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* On Win32, the initial state of unassigned standard file
+ descriptors is that they are open but point to an
+ INVALID_HANDLE_VALUE, and there is no fcntl. */
+ return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
+#else
+# ifndef F_GETFL
+# error Please port fcntl to your platform
+# endif
+ return 0 <= fcntl (fd, F_GETFL);
+#endif
+}
- /* Wait for child. */
- ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
- ASSERT (close (fd[0]) == 0);
- ASSERT (close (fd[1]) == 0);
+/* Return true if FD is not inherited to child processes. */
+static bool
+is_cloexec (int fd)
+{
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ DWORD flags;
+ ASSERT (GetHandleInformation (h, &flags));
+ return (flags & HANDLE_FLAG_INHERIT) == 0;
+#else
+ int flags;
+ ASSERT ((flags = fcntl (fd, F_GETFD)) >= 0);
+ return (flags & FD_CLOEXEC) != 0;
+#endif
+}
- /* Check the result. */
- ASSERT (buffer[0] == 'b');
- ASSERT (buffer[1] == 'a');
+/* Return true if FD is in non-blocking mode. */
+static bool
+is_nonblocking (int fd)
+{
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* We don't use the non-blocking mode for sockets here. */
+ return 0;
+#else
+ int flags;
+ ASSERT ((flags = fcntl (fd, F_GETFL)) >= 0);
+ return (flags & O_NONBLOCK) != 0;
+#endif
}
int
-main (int argc, const char *argv[])
+main ()
{
- int i;
- int test;
- ASSERT (argc == 2);
- 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:
- close (0);
- break;
- case 2:
- close (1);
- break;
- case 3:
- close (0);
- close (1);
- break;
- case 4:
- close (2);
- break;
- case 5:
- close (0);
- close (2);
- break;
- case 6:
- close (1);
- close (2);
- break;
- case 7:
- close (0);
- close (1);
- close (2);
- break;
+ int fd[2];
+
+ fd[0] = -1;
+ fd[1] = -1;
+ ASSERT (pipe (fd) >= 0);
+ ASSERT (fd[0] >= 0);
+ ASSERT (fd[1] >= 0);
+ ASSERT (fd[0] != fd[1]);
+ ASSERT (is_open (fd[0]));
+ ASSERT (is_open (fd[1]));
+ ASSERT (!is_cloexec (fd[0]));
+ ASSERT (!is_cloexec (fd[1]));
+ ASSERT (!is_nonblocking (fd[0]));
+ ASSERT (!is_nonblocking (fd[1]));
- /* 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;
-#ifdef F_GETFL
- /* Try to keep stderr open for better diagnostics. */
- i = fcntl (STDERR_FILENO, F_GETFL);
-#else
- /* But allow compilation on mingw. */
- i = close (STDERR_FILENO);
-#endif
- 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);
- }
- /* 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);
return 0;
}