2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
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)
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
31 #if defined _WIN32 && ! defined __CYGWIN__
32 /* Get _isatty, _getcwd. */
36 #include "read-file.h"
39 /* The name of the "always silent" device. */
40 #if defined _WIN32 && ! defined __CYGWIN__
41 /* Native Windows API. */
42 # define DEV_NULL "NUL"
45 # define DEV_NULL "/dev/null"
48 #define BASE "test-execute"
51 main (int argc, char *argv[])
55 fprintf (stderr, "%s: need 2 arguments\n", argv[0]);
58 char *prog_path = argv[1];
59 const char *progname = "test-execute-child";
60 int test = atoi (argv[2]);
67 /* Close file descriptors that have been inherited from the parent
68 process and that would cause failures in test-execute-child.c.
69 Such file descriptors have been seen:
70 - with GNU make, when invoked as 'make -j N' with j > 1,
71 - in some versions of the KDE desktop environment,
73 - in MacPorts with the "trace mode" enabled.
76 if (close_range (3, 20 - 1, 0) < 0)
80 for (fd = 3; fd < 20; fd++)
91 /* Check an invocation without arguments. Check the exit code. */
92 const char *prog_argv[2] = { prog_path, NULL };
93 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
94 false, false, false, false, true, false, NULL);
100 /* Check an invocation of a non-existent program. */
101 const char *prog_argv[3] = { "./non-existent", NULL };
102 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
103 false, false, false, false, true, false, NULL);
109 /* Check argument passing. */
110 const char *prog_argv[13] =
126 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
127 false, false, false, false, true, false, NULL);
132 #if !(defined _WIN32 && !defined __CYGWIN__)
134 /* Check SIGPIPE handling with ignore_sigpipe = false. */
135 const char *prog_argv[3] = { prog_path, "3", NULL };
136 int termsig = 0x7DEADBEE;
137 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
138 false, false, false, false, true, false, &termsig);
140 ASSERT (termsig == SIGPIPE);
145 #if !(defined _WIN32 && !defined __CYGWIN__)
147 /* Check SIGPIPE handling with ignore_sigpipe = true. */
148 const char *prog_argv[3] = { prog_path, "4", NULL };
149 int termsig = 0x7DEADBEE;
150 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
151 true, false, false, false, true, false, &termsig);
153 ASSERT (termsig == SIGPIPE);
159 /* Check other signal. */
160 const char *prog_argv[3] = { prog_path, "5", NULL };
161 int termsig = 0x7DEADBEE;
162 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
163 false, false, false, false, true, false, &termsig);
165 #if defined _WIN32 && !defined __CYGWIN__
166 ASSERT (termsig == SIGTERM); /* dummy, from WTERMSIG in <sys/wait.h> */
168 ASSERT (termsig == SIGINT);
174 /* Check stdin is inherited. */
175 FILE *fp = fopen (BASE ".tmp", "w");
177 ASSERT (fclose (fp) == 0);
179 fp = freopen (BASE ".tmp", "r", stdin);
182 const char *prog_argv[3] = { prog_path, "6", NULL };
183 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
184 false, false, false, false, true, false, NULL);
187 ASSERT (fclose (stdin) == 0);
188 ASSERT (remove (BASE ".tmp") == 0);
193 /* Check null_stdin = true. */
194 FILE *fp = fopen (BASE ".tmp", "w");
196 ASSERT (fclose (fp) == 0);
198 fp = freopen (BASE ".tmp", "r", stdin);
201 const char *prog_argv[3] = { prog_path, "7", NULL };
202 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
203 false, true, false, false, true, false, NULL);
206 ASSERT (fclose (stdin) == 0);
207 ASSERT (remove (BASE ".tmp") == 0);
212 /* Check stdout is inherited, part 1 (regular file). */
213 FILE *fp = freopen (BASE ".tmp", "w", stdout);
216 const char *prog_argv[3] = { prog_path, "8", NULL };
217 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
218 false, false, false, false, true, false, NULL);
221 ASSERT (fclose (stdout) == 0);
224 char *contents = read_file (BASE ".tmp", 0, &length);
225 ASSERT (length == 3 && memcmp (contents, "bar", 3) == 0);
227 ASSERT (remove (BASE ".tmp") == 0);
232 /* Check stdout is inherited, part 2 (device). */
233 FILE *fp = freopen (DEV_NULL, "w", stdout);
236 const char *prog_argv[3] = { prog_path, "9", NULL };
237 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
238 false, false, false, false, true, false, NULL);
244 /* Check null_stdout = true. */
245 FILE *fp = freopen (BASE ".tmp", "w", stdout);
248 const char *prog_argv[3] = { prog_path, "10", NULL };
249 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
250 false, false, true, false, true, false, NULL);
253 ASSERT (fclose (stdout) == 0);
256 (void) read_file (BASE ".tmp", 0, &length);
257 ASSERT (length == 0);
259 ASSERT (remove (BASE ".tmp") == 0);
264 /* Check stderr is inherited, part 1 (regular file). */
265 FILE *fp = freopen (BASE ".tmp", "w", stderr);
268 const char *prog_argv[3] = { prog_path, "11", NULL };
269 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
270 false, false, false, false, true, false, NULL);
273 ASSERT (fclose (stderr) == 0);
276 char *contents = read_file (BASE ".tmp", 0, &length);
277 ASSERT (length == 3 && memcmp (contents, "bar", 3) == 0);
279 ASSERT (remove (BASE ".tmp") == 0);
284 /* Check stderr is inherited, part 2 (device). */
285 FILE *fp = freopen (DEV_NULL, "w", stderr);
288 const char *prog_argv[3] = { prog_path, "12", NULL };
289 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
290 false, false, false, false, true, false, NULL);
296 /* Check null_stderr = true. */
297 FILE *fp = freopen (BASE ".tmp", "w", stderr);
300 const char *prog_argv[3] = { prog_path, "13", NULL };
301 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
302 false, false, false, true, true, false, NULL);
305 ASSERT (fclose (stderr) == 0);
308 (void) read_file (BASE ".tmp", 0, &length);
309 ASSERT (length == 0);
311 ASSERT (remove (BASE ".tmp") == 0);
316 /* Check file descriptors >= 3 can be inherited. */
317 ASSERT (dup2 (STDOUT_FILENO, 10) >= 0);
318 const char *prog_argv[3] = { prog_path, "14", NULL };
319 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
320 true, false, false, false, true, false, NULL);
326 /* Check file descriptors >= 3 can be inherited. */
327 ASSERT (fcntl (STDOUT_FILENO, F_DUPFD, 10) >= 0);
328 const char *prog_argv[3] = { prog_path, "15", NULL };
329 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
330 true, false, false, false, true, false, NULL);
336 /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */
337 ASSERT (fcntl (STDOUT_FILENO, F_DUPFD_CLOEXEC, 10) >= 0);
338 const char *prog_argv[3] = { prog_path, "16", NULL };
339 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
340 true, false, false, false, true, false, NULL);
346 /* Check that file descriptors >= 3, open for reading, can be inherited,
347 including the file position. */
348 FILE *fp = fopen (BASE ".tmp", "w");
349 fputs ("Foobar", fp);
350 ASSERT (fclose (fp) == 0);
352 int fd = open (BASE ".tmp", O_RDONLY);
353 ASSERT (fd >= 0 && fd < 10);
355 ASSERT (dup2 (fd, 10) >= 0);
360 ASSERT (read (fd, buf, sizeof (buf)) == sizeof (buf));
361 /* The file position is now 2. */
363 const char *prog_argv[3] = { prog_path, "17", NULL };
364 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
365 false, false, false, false, true, false, NULL);
369 ASSERT (remove (BASE ".tmp") == 0);
374 /* Check that file descriptors >= 3, open for writing, can be inherited,
375 including the file position. */
376 remove (BASE ".tmp");
377 int fd = open (BASE ".tmp", O_RDWR | O_CREAT | O_TRUNC, 0600);
378 ASSERT (fd >= 0 && fd < 10);
380 ASSERT (dup2 (fd, 10) >= 0);
384 ASSERT (write (fd, "Foo", 3) == 3);
385 /* The file position is now 3. */
387 const char *prog_argv[3] = { prog_path, "18", NULL };
388 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
389 false, false, false, false, true, false, NULL);
395 char *contents = read_file (BASE ".tmp", 0, &length);
396 ASSERT (length == 6 && memcmp (contents, "Foobar", 6) == 0);
398 ASSERT (remove (BASE ".tmp") == 0);
403 /* Check that file descriptors >= 3, when inherited, preserve their
404 isatty() property, part 1 (regular file). */
405 FILE *fp = fopen (BASE ".tmp", "w");
407 ASSERT (fclose (fp) == 0);
409 int fd_in = open (BASE ".tmp", O_RDONLY);
410 ASSERT (fd_in >= 0 && fd_in < 10);
412 int fd_out = open (BASE ".tmp", O_WRONLY | O_APPEND);
413 ASSERT (fd_out >= 0 && fd_out < 10);
415 ASSERT (dup2 (fd_in, 10) >= 0);
419 ASSERT (dup2 (fd_out, 11) >= 0);
423 const char *prog_argv[3] = { prog_path, "19", NULL };
424 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
425 false, false, false, false, true, false, NULL);
426 #if defined _WIN32 && ! defined __CYGWIN__
427 ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
429 ASSERT (ret == 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
434 ASSERT (remove (BASE ".tmp") == 0);
439 /* Check that file descriptors >= 3, when inherited, preserve their
440 isatty() property, part 2 (character devices). */
441 ASSERT (dup2 (STDIN_FILENO, 10) >= 0);
444 ASSERT (dup2 (STDOUT_FILENO, 11) >= 0);
447 const char *prog_argv[3] = { prog_path, "20", NULL };
448 int ret = execute (progname, prog_argv[0], prog_argv, NULL,
449 false, false, false, false, true, false, NULL);
450 #if defined _WIN32 && ! defined __CYGWIN__
451 ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
453 ASSERT (ret == 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
462 /* Check execution in a different directory. */
464 ASSERT (mkdir (BASE ".sub", 0700) == 0);
467 #if defined _WIN32 && ! defined __CYGWIN__
468 ASSERT (_getcwd (cwd, sizeof (cwd)) != NULL);
470 ASSERT (getcwd (cwd, sizeof (cwd)) != NULL);
473 const char *prog_argv[4] = { prog_path, "21", cwd, NULL };
474 int ret = execute (progname, prog_argv[0], prog_argv, BASE ".sub",
475 false, false, false, false, true, false, NULL);
478 ASSERT (rmdir (BASE ".sub") == 0);