added missing dependencies to fix failing unistr/ tests
[gnulib.git] / tests / test-pipe.c
1 /* Test of create_pipe_bidi/wait_subprocess.
2    Copyright (C) 2009, 2010 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 #include <errno.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 /* Depending on arguments, this test intentionally closes stderr or
31    starts life with stderr closed.  So, we arrange to have fd 10
32    (outside the range of interesting fd's during the test) set up to
33    duplicate the original stderr.  */
34
35 #define BACKUP_STDERR_FILENO 10
36 #define ASSERT_STREAM myerr
37 #include "macros.h"
38
39 static FILE *myerr;
40
41 /* Code executed by the child process.  argv[1] = "child".  */
42 static int
43 child_main (int argc, char *argv[])
44 {
45   char buffer[2] = { 's', 't' };
46   int fd;
47   int ret;
48
49   ASSERT (argc == 3);
50
51   /* Read one byte from fd 0, and write its value plus one to fd 1.
52      fd 2 should be closed iff the argument is 1.  Check that no other file
53      descriptors leaked.  */
54
55   ASSERT (read (STDIN_FILENO, buffer, 2) == 1);
56
57   buffer[0]++;
58   ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
59
60   errno = 0;
61   ret = dup2 (STDERR_FILENO, STDERR_FILENO);
62   switch (atoi (argv[2]))
63     {
64     case 0:
65       /* Expect fd 2 is open.  */
66       ASSERT (ret == STDERR_FILENO);
67       break;
68     case 1:
69       /* Expect fd 2 is closed.  */
70       ASSERT (ret == -1);
71       ASSERT (errno == EBADF);
72       break;
73     default:
74       ASSERT (false);
75     }
76
77   for (fd = 3; fd < 7; fd++)
78     {
79       errno = 0;
80       ASSERT (close (fd) == -1);
81       ASSERT (errno == EBADF);
82     }
83
84   return 0;
85 }
86
87 /* Create a bi-directional pipe to a test child, and validate that the
88    child program returns the expected output.  The child is the same
89    program as the parent ARGV0, but with different arguments.
90    STDERR_CLOSED is true if we have already closed fd 2.  */
91 static void
92 test_pipe (const char *argv0, bool stderr_closed)
93 {
94   int fd[2];
95   char *argv[4];
96   pid_t pid;
97   char buffer[2] = { 'a', 't' };
98
99   /* Set up child.  */
100   argv[0] = (char *) argv0;
101   argv[1] = (char *) "child";
102   argv[2] = (char *) (stderr_closed ? "1" : "0");
103   argv[3] = NULL;
104   pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
105   ASSERT (0 <= pid);
106   ASSERT (STDERR_FILENO < fd[0]);
107   ASSERT (STDERR_FILENO < fd[1]);
108
109   /* Push child's input.  */
110   ASSERT (write (fd[1], buffer, 1) == 1);
111   ASSERT (close (fd[1]) == 0);
112
113   /* Get child's output.  */
114   ASSERT (read (fd[0], buffer, 2) == 1);
115
116   /* Wait for child.  */
117   ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
118   ASSERT (close (fd[0]) == 0);
119
120   /* Check the result.  */
121   ASSERT (buffer[0] == 'b');
122   ASSERT (buffer[1] == 't');
123 }
124
125 /* Code executed by the parent process.  */
126 static int
127 parent_main (int argc, char *argv[])
128 {
129   int test;
130   int fd;
131
132   ASSERT (argc == 2);
133
134   /* Selectively close various standard fds, to verify the child process is
135      not impacted by this.  */
136   test = atoi (argv[1]);
137   switch (test)
138     {
139     case 0:
140       break;
141     case 1:
142       close (0);
143       break;
144     case 2:
145       close (1);
146       break;
147     case 3:
148       close (0);
149       close (1);
150       break;
151     case 4:
152       close (2);
153       break;
154     case 5:
155       close (0);
156       close (2);
157       break;
158     case 6:
159       close (1);
160       close (2);
161       break;
162     case 7:
163       close (0);
164       close (1);
165       close (2);
166       break;
167     default:
168       ASSERT (false);
169     }
170
171   /* Plug any file descriptor leaks inherited from outside world before
172      starting, so that child has a clean slate (at least for the fds that we
173      might be manipulating).  */
174   for (fd = 3; fd < 7; fd++)
175     close (fd);
176
177   test_pipe (argv[0], test >= 4);
178
179   return 0;
180 }
181
182 int
183 main (int argc, char *argv[])
184 {
185   if (argc < 2)
186     {
187       fprintf (stderr, "%s: need arguments\n", argv[0]);
188       return 2;
189     }
190   if (strcmp (argv[1], "child") == 0)
191     {
192       /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original
193          stderr.  */
194       myerr = fdopen (BACKUP_STDERR_FILENO, "w");
195       if (!myerr)
196         return 2;
197       return child_main (argc, argv);
198     }
199   /* We might close fd 2 later, so save it in fd 10.  */
200   if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
201       || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
202     return 2;
203   return parent_main (argc, argv);
204 }