2 Copyright (C) 2020 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]);
65 /* Check an invocation without arguments. Check the exit code. */
66 const char *prog_argv
[2] = { prog_path
, NULL
};
67 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
68 false, false, false, false, true, false, NULL
);
74 /* Check an invocation of a non-existent program. */
75 const char *prog_argv
[3] = { "./non-existent", NULL
};
76 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
77 false, false, false, false, true, false, NULL
);
83 /* Check argument passing. */
84 const char *prog_argv
[13] =
100 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
101 false, false, false, false, true, false, NULL
);
106 #if !(defined _WIN32 && !defined __CYGWIN__)
108 /* Check SIGPIPE handling with ignore_sigpipe = false. */
109 const char *prog_argv
[3] = { prog_path
, "3", NULL
};
110 int termsig
= 0xDEADBEEF;
111 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
112 false, false, false, false, true, false, &termsig
);
114 ASSERT (termsig
== SIGPIPE
);
119 #if !(defined _WIN32 && !defined __CYGWIN__)
121 /* Check SIGPIPE handling with ignore_sigpipe = true. */
122 const char *prog_argv
[3] = { prog_path
, "4", NULL
};
123 int termsig
= 0xDEADBEEF;
124 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
125 true, false, false, false, true, false, &termsig
);
127 ASSERT (termsig
== SIGPIPE
);
133 /* Check other signal. */
134 const char *prog_argv
[3] = { prog_path
, "5", NULL
};
135 int termsig
= 0xDEADBEEF;
136 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
137 false, false, false, false, true, false, &termsig
);
138 #if defined _WIN32 && !defined __CYGWIN__
140 ASSERT (termsig
== 0);
143 ASSERT (termsig
== SIGINT
);
149 /* Check stdin is inherited. */
150 FILE *fp
= fopen (BASE
".tmp", "w");
152 ASSERT (fclose (fp
) == 0);
154 fp
= freopen (BASE
".tmp", "r", stdin
);
157 const char *prog_argv
[3] = { prog_path
, "6", NULL
};
158 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
159 false, false, false, false, true, false, NULL
);
162 ASSERT (fclose (stdin
) == 0);
163 ASSERT (remove (BASE
".tmp") == 0);
168 /* Check null_stdin = true. */
169 FILE *fp
= fopen (BASE
".tmp", "w");
171 ASSERT (fclose (fp
) == 0);
173 fp
= freopen (BASE
".tmp", "r", stdin
);
176 const char *prog_argv
[3] = { prog_path
, "7", NULL
};
177 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
178 false, true, false, false, true, false, NULL
);
181 ASSERT (fclose (stdin
) == 0);
182 ASSERT (remove (BASE
".tmp") == 0);
187 /* Check stdout is inherited, part 1 (regular file). */
188 FILE *fp
= freopen (BASE
".tmp", "w", stdout
);
191 const char *prog_argv
[3] = { prog_path
, "8", NULL
};
192 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
193 false, false, false, false, true, false, NULL
);
196 ASSERT (fclose (stdout
) == 0);
199 char *contents
= read_file (BASE
".tmp", 0, &length
);
200 ASSERT (length
== 3 && memcmp (contents
, "bar", 3) == 0);
202 ASSERT (remove (BASE
".tmp") == 0);
207 /* Check stdout is inherited, part 2 (device). */
208 FILE *fp
= freopen (DEV_NULL
, "w", stdout
);
211 const char *prog_argv
[3] = { prog_path
, "9", NULL
};
212 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
213 false, false, false, false, true, false, NULL
);
219 /* Check null_stdout = true. */
220 FILE *fp
= freopen (BASE
".tmp", "w", stdout
);
223 const char *prog_argv
[3] = { prog_path
, "10", NULL
};
224 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
225 false, false, true, false, true, false, NULL
);
228 ASSERT (fclose (stdout
) == 0);
231 (void) read_file (BASE
".tmp", 0, &length
);
232 ASSERT (length
== 0);
234 ASSERT (remove (BASE
".tmp") == 0);
239 /* Check stderr is inherited, part 1 (regular file). */
240 FILE *fp
= freopen (BASE
".tmp", "w", stderr
);
243 const char *prog_argv
[3] = { prog_path
, "11", NULL
};
244 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
245 false, false, false, false, true, false, NULL
);
248 ASSERT (fclose (stderr
) == 0);
251 char *contents
= read_file (BASE
".tmp", 0, &length
);
252 ASSERT (length
== 3 && memcmp (contents
, "bar", 3) == 0);
254 ASSERT (remove (BASE
".tmp") == 0);
259 /* Check stderr is inherited, part 2 (device). */
260 FILE *fp
= freopen (DEV_NULL
, "w", stderr
);
263 const char *prog_argv
[3] = { prog_path
, "12", NULL
};
264 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
265 false, false, false, false, true, false, NULL
);
271 /* Check null_stderr = true. */
272 FILE *fp
= freopen (BASE
".tmp", "w", stderr
);
275 const char *prog_argv
[3] = { prog_path
, "13", NULL
};
276 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
277 false, false, false, true, true, false, NULL
);
280 ASSERT (fclose (stderr
) == 0);
283 (void) read_file (BASE
".tmp", 0, &length
);
284 ASSERT (length
== 0);
286 ASSERT (remove (BASE
".tmp") == 0);
291 /* Check file descriptors >= 3 can be inherited. */
292 ASSERT (dup2 (STDOUT_FILENO
, 10) >= 0);
293 const char *prog_argv
[3] = { prog_path
, "14", NULL
};
294 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
295 true, false, false, false, true, false, NULL
);
301 /* Check file descriptors >= 3 can be inherited. */
302 ASSERT (fcntl (STDOUT_FILENO
, F_DUPFD
, 10) >= 0);
303 const char *prog_argv
[3] = { prog_path
, "15", NULL
};
304 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
305 true, false, false, false, true, false, NULL
);
311 /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */
312 ASSERT (fcntl (STDOUT_FILENO
, F_DUPFD_CLOEXEC
, 10) >= 0);
313 const char *prog_argv
[3] = { prog_path
, "16", NULL
};
314 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
315 true, false, false, false, true, false, NULL
);
321 /* Check that file descriptors >= 3, open for reading, can be inherited,
322 including the file position. */
323 FILE *fp
= fopen (BASE
".tmp", "w");
324 fputs ("Foobar", fp
);
325 ASSERT (fclose (fp
) == 0);
327 int fd
= open (BASE
".tmp", O_RDONLY
);
328 ASSERT (fd
>= 0 && fd
< 10);
330 ASSERT (dup2 (fd
, 10) >= 0);
335 ASSERT (read (fd
, buf
, sizeof (buf
)) == sizeof (buf
));
336 /* The file position is now 2. */
338 const char *prog_argv
[3] = { prog_path
, "17", NULL
};
339 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
340 false, false, false, false, true, false, NULL
);
344 ASSERT (remove (BASE
".tmp") == 0);
349 /* Check that file descriptors >= 3, open for writing, can be inherited,
350 including the file position. */
351 remove (BASE
".tmp");
352 int fd
= open (BASE
".tmp", O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
353 ASSERT (fd
>= 0 && fd
< 10);
355 ASSERT (dup2 (fd
, 10) >= 0);
359 ASSERT (write (fd
, "Foo", 3) == 3);
360 /* The file position is now 3. */
362 const char *prog_argv
[3] = { prog_path
, "18", NULL
};
363 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
364 false, false, false, false, true, false, NULL
);
370 char *contents
= read_file (BASE
".tmp", 0, &length
);
371 ASSERT (length
== 6 && memcmp (contents
, "Foobar", 6) == 0);
373 ASSERT (remove (BASE
".tmp") == 0);
378 /* Check that file descriptors >= 3, when inherited, preserve their
379 isatty() property, part 1 (regular file). */
380 FILE *fp
= fopen (BASE
".tmp", "w");
382 ASSERT (fclose (fp
) == 0);
384 int fd_in
= open (BASE
".tmp", O_RDONLY
);
385 ASSERT (fd_in
>= 0 && fd_in
< 10);
387 int fd_out
= open (BASE
".tmp", O_WRONLY
| O_APPEND
);
388 ASSERT (fd_out
>= 0 && fd_out
< 10);
390 ASSERT (dup2 (fd_in
, 10) >= 0);
394 ASSERT (dup2 (fd_out
, 11) >= 0);
398 const char *prog_argv
[3] = { prog_path
, "19", NULL
};
399 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
400 false, false, false, false, true, false, NULL
);
401 #if defined _WIN32 && ! defined __CYGWIN__
402 ASSERT (ret
== 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
404 ASSERT (ret
== 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
409 ASSERT (remove (BASE
".tmp") == 0);
414 /* Check that file descriptors >= 3, when inherited, preserve their
415 isatty() property, part 2 (character devices). */
416 ASSERT (dup2 (STDIN_FILENO
, 10) >= 0);
419 ASSERT (dup2 (STDOUT_FILENO
, 11) >= 0);
422 const char *prog_argv
[3] = { prog_path
, "20", NULL
};
423 int ret
= execute (progname
, prog_argv
[0], prog_argv
, NULL
,
424 false, false, false, false, true, false, NULL
);
425 #if defined _WIN32 && ! defined __CYGWIN__
426 ASSERT (ret
== 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
428 ASSERT (ret
== 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
437 /* Check execution in a different directory. */
439 ASSERT (mkdir (BASE
".sub", 0700) == 0);
442 #if defined _WIN32 && ! defined __CYGWIN__
443 ASSERT (_getcwd (cwd
, sizeof (cwd
)) != NULL
);
445 ASSERT (getcwd (cwd
, sizeof (cwd
)) != NULL
);
448 const char *prog_argv
[4] = { prog_path
, "21", cwd
, NULL
};
449 int ret
= execute (progname
, prog_argv
[0], prog_argv
, BASE
".sub",
450 false, false, false, false, true, false, NULL
);
453 ASSERT (rmdir (BASE
".sub") == 0);