16c72f6034a8ede26df8df4647aa7f101c69f2ce
[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, we arrange to have fd 10
38    (outside the range of interesting fd's during the test) set up to
39    duplicate the original stderr.  */
40
41 #define BACKUP_STDERR_FILENO 10
42 static FILE *myerr;
43
44 #define ASSERT(expr) \
45   do                                                                         \
46     {                                                                        \
47       if (!(expr))                                                           \
48         {                                                                    \
49           fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
50           fflush (myerr);                                                    \
51           abort ();                                                          \
52         }                                                                    \
53     }                                                                        \
54   while (0)
55
56 /* Code executed by the child process.  argv[1] = "child".  */
57 static int
58 child_main (int argc, char *argv[])
59 {
60   char buffer[2] = { 's', 't' };
61   int fd;
62
63   ASSERT (argc == 3);
64
65   /* Read one byte from fd 0, and write its value plus one to fd 1.
66      fd 2 should be closed iff the argument is 1.  Check that no other file
67      descriptors leaked.  */
68
69   ASSERT (read (STDIN_FILENO, buffer, 2) == 1);
70
71   buffer[0]++;
72   ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
73
74 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
75   /* On Win32, the initial state of unassigned standard file descriptors is
76      that they are open but point to an INVALID_HANDLE_VALUE.  Thus
77      close (STDERR_FILENO) would always succeed.  */
78   switch (atoi (argv[2]))
79     {
80     case 0:
81       /* Expect fd 2 is open to a valid handle.  */
82       ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) != INVALID_HANDLE_VALUE);
83       break;
84     case 1:
85       /* Expect fd 2 is pointing to INVALID_HANDLE_VALUE.  */
86       ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) == INVALID_HANDLE_VALUE);
87       break;
88     default:
89       ASSERT (false);
90     }
91 #elif defined F_GETFL
92   /* On Unix, the initial state of unassigned standard file descriptors is
93      that they are closed.  */
94   {
95     int ret;
96     errno = 0;
97     ret = fcntl (STDERR_FILENO, F_GETFL);
98     switch (atoi (argv[2]))
99       {
100       case 0:
101         /* Expect fd 2 is open.  */
102         ASSERT (ret >= 0);
103         break;
104       case 1:
105         /* Expect fd 2 is closed.  */
106         ASSERT (ret < 0);
107         ASSERT (errno == EBADF);
108         break;
109       default:
110         ASSERT (false);
111       }
112   }
113 #endif
114
115   for (fd = 3; fd < 7; fd++)
116     {
117       errno = 0;
118       ASSERT (close (fd) == -1);
119       ASSERT (errno == EBADF);
120     }
121
122   return 0;
123 }
124
125 /* Create a bi-directional pipe to a test child, and validate that the
126    child program returns the expected output.  The child is the same
127    program as the parent ARGV0, but with different arguments.
128    STDERR_CLOSED is true if we have already closed fd 2.  */
129 static void
130 test_pipe (const char *argv0, bool stderr_closed)
131 {
132   int fd[2];
133   char *argv[4];
134   pid_t pid;
135   char buffer[2] = { 'a', 't' };
136
137   /* Set up child.  */
138   argv[0] = (char *) argv0;
139   argv[1] = (char *) "child";
140   argv[2] = (char *) (stderr_closed ? "1" : "0");
141   argv[3] = NULL;
142   pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
143   ASSERT (0 <= pid);
144   ASSERT (STDERR_FILENO < fd[0]);
145   ASSERT (STDERR_FILENO < fd[1]);
146
147   /* Push child's input.  */
148   ASSERT (write (fd[1], buffer, 1) == 1);
149   ASSERT (close (fd[1]) == 0);
150
151   /* Get child's output.  */
152   ASSERT (read (fd[0], buffer, 2) == 1);
153
154   /* Wait for child.  */
155   ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
156   ASSERT (close (fd[0]) == 0);
157
158   /* Check the result.  */
159   ASSERT (buffer[0] == 'b');
160   ASSERT (buffer[1] == 't');
161 }
162
163 /* Code executed by the parent process.  */
164 static int
165 parent_main (int argc, char *argv[])
166 {
167   int test;
168   int fd;
169
170   ASSERT (argc == 2);
171
172   /* Selectively close various standard fds, to verify the child process is
173      not impacted by this.  */
174   test = atoi (argv[1]);
175   switch (test)
176     {
177     case 0:
178       break;
179     case 1:
180       close (0);
181       break;
182     case 2:
183       close (1);
184       break;
185     case 3:
186       close (0);
187       close (1);
188       break;
189     case 4:
190       close (2);
191       break;
192     case 5:
193       close (0);
194       close (2);
195       break;
196     case 6:
197       close (1);
198       close (2);
199       break;
200     case 7:
201       close (0);
202       close (1);
203       close (2);
204       break;
205     default:
206       ASSERT (false);
207     }
208
209   /* Plug any file descriptor leaks inherited from outside world before
210      starting, so that child has a clean slate (at least for the fds that we
211      might be manipulating).  */
212   for (fd = 3; fd < 7; fd++)
213     close (fd);
214
215   test_pipe (argv[0], test >= 4);
216
217   return 0;
218 }
219
220 int
221 main (int argc, char *argv[])
222 {
223   if (argc < 2)
224     {
225       fprintf (stderr, "%s: need arguments\n", argv[0]);
226       return 2;
227     }
228   if (strcmp (argv[1], "child") == 0)
229     {
230       /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original
231          stderr.  */
232       myerr = fdopen (BACKUP_STDERR_FILENO, "w");
233       if (!myerr)
234         return 2;
235       return child_main (argc, argv);
236     }
237   /* We might close fd 2 later, so save it in fd 10.  */
238   if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
239       || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
240     return 2;
241   return parent_main (argc, argv);
242 }