Fix handling of closed stdin/stdout/stderr on mingw.
[gnulib.git] / tests / test-pipe.c
1 /* Test of create_pipe_bidi/wait_subprocess.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 #include <config.h>
19
20 #include "pipe.h"
21 #include "wait-process.h"
22
23 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
24 /* Get declarations of the Win32 API functions.  */
25 # define WIN32_LEAN_AND_MEAN
26 # include <windows.h>
27 #endif
28
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 /* Depending on arguments, this test intentionally closes stderr or
37    starts life with stderr closed.  So, the error messages might not
38    always print, but at least the exit status will be reliable.  */
39 #define ASSERT(expr) \
40   do                                                                         \
41     {                                                                        \
42       if (!(expr))                                                           \
43         {                                                                    \
44           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
45           fflush (stderr);                                                   \
46           abort ();                                                          \
47         }                                                                    \
48     }                                                                        \
49   while (0)
50
51 /* Code executed by the child process.  argv[1] = "child".  */
52 static int
53 child_main (int argc, char *argv[])
54 {
55   char buffer[1];
56   int fd;
57
58   ASSERT (argc == 3);
59
60   /* Read one byte from fd 0, and write its value plus one to fd 1.
61      fd 2 should be closed iff the argument is 1.  Check that no other file
62      descriptors leaked.  */
63
64   ASSERT (read (STDIN_FILENO, buffer, 1) == 1);
65
66   buffer[0]++;
67   ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
68
69 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
70   /* On Win32, the initial state of unassigned standard file descriptors is
71      that they are open but point to an INVALID_HANDLE_VALUE.  Thus
72      close (STDERR_FILENO) would always succeed.  */
73   switch (atoi (argv[2]))
74     {
75     case 0:
76       /* Expect fd 2 is open to a valid handle.  */
77       ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) != INVALID_HANDLE_VALUE);
78       break;
79     case 1:
80       /* Expect fd 2 is pointing to INVALID_HANDLE_VALUE.  */
81       ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) == INVALID_HANDLE_VALUE);
82       break;
83     default:
84       ASSERT (false);
85     }
86 #elif defined F_GETFL
87   /* On Unix, the initial state of unassigned standard file descriptors is
88      that they are closed.  */
89   {
90     int ret;
91     errno = 0;
92     ret = fcntl (STDERR_FILENO, F_GETFL);
93     switch (atoi (argv[2]))
94       {
95       case 0:
96         /* Expect fd 2 is open.  */
97         ASSERT (ret >= 0);
98         break;
99       case 1:
100         /* Expect fd 2 is closed.  */
101         ASSERT (ret < 0);
102         ASSERT (errno == EBADF);
103         break;
104       default:
105         ASSERT (false);
106       }
107   }
108 #endif
109
110   for (fd = 3; fd < 7; fd++)
111     {
112       errno = 0;
113       ASSERT (close (fd) == -1);
114       ASSERT (errno == EBADF);
115     }
116
117   return 0;
118 }
119
120 /* Create a bi-directional pipe to a test child, and validate that the
121    child program returns the expected output.  The child is the same
122    program as the parent ARGV0, but with different arguments.
123    STDERR_CLOSED is true if we have already closed fd 2.  */
124 static void
125 test_pipe (const char *argv0, bool stderr_closed)
126 {
127   int fd[2];
128   char *argv[4];
129   pid_t pid;
130   char buffer[2] = { 'a', 't' };
131
132   /* Set up child.  */
133   argv[0] = (char *) argv0;
134   argv[1] = (char *) "child";
135   argv[2] = (char *) (stderr_closed ? "1" : "0");
136   argv[3] = NULL;
137   pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
138   ASSERT (0 <= pid);
139   ASSERT (STDERR_FILENO < fd[0]);
140   ASSERT (STDERR_FILENO < fd[1]);
141
142   /* Push child's input.  */
143   ASSERT (write (fd[1], buffer, 1) == 1);
144
145   /* Get child's output.  */
146   ASSERT (read (fd[0], buffer, 2) == 1);
147
148   /* Wait for child.  */
149   ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
150   ASSERT (close (fd[0]) == 0);
151   ASSERT (close (fd[1]) == 0);
152
153   /* Check the result.  */
154   ASSERT (buffer[0] == 'b');
155   ASSERT (buffer[1] == 't');
156 }
157
158 /* Code executed by the parent process.  */
159 static int
160 parent_main (int argc, char *argv[])
161 {
162   int test;
163   int fd;
164
165   ASSERT (argc == 2);
166
167   /* Selectively close various standard fds, to verify the child process is
168      not impacted by this.  */
169   test = atoi (argv[1]);
170   switch (test)
171     {
172     case 0:
173       break;
174     case 1:
175       close (0);
176       break;
177     case 2:
178       close (1);
179       break;
180     case 3:
181       close (0);
182       close (1);
183       break;
184     case 4:
185       close (2);
186       break;
187     case 5:
188       close (0);
189       close (2);
190       break;
191     case 6:
192       close (1);
193       close (2);
194       break;
195     case 7:
196       close (0);
197       close (1);
198       close (2);
199       break;
200     default:
201       ASSERT (false);
202     }
203
204   /* Plug any file descriptor leaks inherited from outside world before
205      starting, so that child has a clean slate (at least for the fds that we
206      might be manipulating).  */
207   for (fd = 3; fd < 7; fd++)
208     close (fd);
209
210   test_pipe (argv[0], test >= 4);
211
212   return 0;
213 }
214
215 int
216 main (int argc, char *argv[])
217 {
218   ASSERT (argc >= 2);
219   if (strcmp (argv[1], "child") == 0)
220     return child_main (argc, argv);
221   else
222     return parent_main (argc, argv);
223 }