summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2020-12-02 17:44:04 +0100
committerBruno Haible <bruno@clisp.org>2020-12-02 17:44:58 +0100
commit702cba00f4ff7b22f0684a23db0fb66aea2c4086 (patch)
tree70d1a7a885bc8cbf61a0512f903588c481c5a2ca
parenta10b317852a1bfbc7f26818ced908aa654709f0a (diff)
downloadgnulib-702cba00f4ff7b22f0684a23db0fb66aea2c4086.tar.gz
execute: Allow caller to specify directory for the subprocess.
* lib/execute.h (execute): Add directory argument. * lib/execute.c: Include canonicalize.h, filename.h, findprog.h. (execute): Add directory argument. If specified, resolve the program file name and make it absolute, first. Pass the directory to spawnpvech and posix_spawn_file_actions_addchdir. * modules/execute (Depends-on): Add canonicalize, filename, findprog-in, posix_spawn, posix_spawn_file_actions_addchdir. * tests/test-execute-main.c: Add test for passing a directory. * tests/test-execute-child.c: Likewise. * tests/test-execute.sh: Update. * modules/execute-tests (Depends-on): Add mkdir. * NEWS: Mention the change. * lib/csharpcomp.c (compile_csharp_using_sscli): Update. * lib/csharpexec.c (execute_csharp_using_mono, execute_csharp_using_sscli): Update. * lib/javacomp.c (compile_using_envjavac, compile_using_gcj, compile_using_javac, compile_using_jikes, is_javac_present, is_jikes_present): Update. * lib/javaexec.c (execute_java_class): Update.
-rw-r--r--ChangeLog23
-rw-r--r--NEWS4
-rw-r--r--lib/csharpcomp.c3
-rw-r--r--lib/csharpexec.c6
-rw-r--r--lib/execute.c98
-rw-r--r--lib/execute.h4
-rw-r--r--lib/javacomp.c22
-rw-r--r--lib/javaexec.c12
-rw-r--r--modules/execute5
-rw-r--r--modules/execute-tests1
-rw-r--r--tests/test-execute-child.c20
-rw-r--r--tests/test-execute-main.c66
-rwxr-xr-xtests/test-execute.sh2
13 files changed, 210 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index 8e9e032ba7..b5ea083ff5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2020-12-02 Bruno Haible <bruno@clisp.org>
+
+ execute: Allow caller to specify directory for the subprocess.
+ * lib/execute.h (execute): Add directory argument.
+ * lib/execute.c: Include canonicalize.h, filename.h, findprog.h.
+ (execute): Add directory argument. If specified, resolve the program
+ file name and make it absolute, first. Pass the directory to spawnpvech
+ and posix_spawn_file_actions_addchdir.
+ * modules/execute (Depends-on): Add canonicalize, filename, findprog-in,
+ posix_spawn, posix_spawn_file_actions_addchdir.
+ * tests/test-execute-main.c: Add test for passing a directory.
+ * tests/test-execute-child.c: Likewise.
+ * tests/test-execute.sh: Update.
+ * modules/execute-tests (Depends-on): Add mkdir.
+ * NEWS: Mention the change.
+ * lib/csharpcomp.c (compile_csharp_using_sscli): Update.
+ * lib/csharpexec.c (execute_csharp_using_mono,
+ execute_csharp_using_sscli): Update.
+ * lib/javacomp.c (compile_using_envjavac, compile_using_gcj,
+ compile_using_javac, compile_using_jikes, is_javac_present,
+ is_jikes_present): Update.
+ * lib/javaexec.c (execute_java_class): Update.
+
2020-12-01 Bruno Haible <bruno@clisp.org>
vma-iter: Add support for macOS11/arm64.
diff --git a/NEWS b/NEWS
index d76e3e77ce..445266d6e8 100644
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,10 @@ User visible incompatible changes
Date Modules Changes
+2020-12-02 execute The function 'execute' now takes a 4th argument
+ 'const char *directory'. To maintain the previous
+ behaviour, insert NULL as additional 4th argument.
+
2020-10-16 hash This module deprecates the 'hash_delete' function
using gcc's "deprecated" attribute. Use the better-
named 'hash_remove' equivalent.
diff --git a/lib/csharpcomp.c b/lib/csharpcomp.c
index fac9a895d9..cf68c5a82b 100644
--- a/lib/csharpcomp.c
+++ b/lib/csharpcomp.c
@@ -378,7 +378,8 @@ compile_csharp_using_sscli (const char * const *sources,
free (command);
}
- exitstatus = execute ("csc", "csc", argv, false, false, false, false,
+ exitstatus = execute ("csc", "csc", argv, NULL,
+ false, false, false, false,
true, true, NULL);
for (i = 2; i < 3 + libdirs_count + libraries_count; i++)
diff --git a/lib/csharpexec.c b/lib/csharpexec.c
index b54f14e526..5e2aa2c753 100644
--- a/lib/csharpexec.c
+++ b/lib/csharpexec.c
@@ -106,7 +106,8 @@ execute_csharp_using_mono (const char *assembly_path,
argv[0] = "mono";
argv[1] = "--version";
argv[2] = NULL;
- exitstatus = execute ("mono", "mono", argv, false, false, true, true,
+ exitstatus = execute ("mono", "mono", argv, NULL,
+ false, false, true, true,
true, false, NULL);
mono_present = (exitstatus == 0);
mono_tested = true;
@@ -167,7 +168,8 @@ execute_csharp_using_sscli (const char *assembly_path,
argv[0] = "clix";
argv[1] = NULL;
- exitstatus = execute ("clix", "clix", argv, false, false, true, true,
+ exitstatus = execute ("clix", "clix", argv, NULL,
+ false, false, true, true,
true, false, NULL);
clix_present = (exitstatus == 0 || exitstatus == 1);
clix_tested = true;
diff --git a/lib/execute.c b/lib/execute.c
index 15556cf791..03fb6ec279 100644
--- a/lib/execute.c
+++ b/lib/execute.c
@@ -28,8 +28,11 @@
#include <signal.h>
#include <unistd.h>
+#include "canonicalize.h"
#include "error.h"
#include "fatal-signal.h"
+#include "filename.h"
+#include "findprog.h"
#include "wait-process.h"
#include "gettext.h"
@@ -94,17 +97,66 @@ nonintr_open (const char *pathname, int oflag, mode_t mode)
int
execute (const char *progname,
const char *prog_path, char **prog_argv,
+ const char *directory,
bool ignore_sigpipe,
bool null_stdin, bool null_stdout, bool null_stderr,
bool slave_process, bool exit_on_error,
int *termsigp)
{
+ int saved_errno;
+ char *prog_path_to_free = NULL;
+
+ if (directory != NULL)
+ {
+ /* If a change of directory is requested, make sure PROG_PATH is absolute
+ before we do so. This is needed because
+ - posix_spawn and posix_spawnp are required to resolve a relative
+ PROG_PATH *after* changing the directory. See
+ <https://www.austingroupbugs.net/view.php?id=1208>:
+ "if this pathname does not start with a <slash> it shall be
+ interpreted relative to the working directory of the child
+ process _after_ all file_actions have been performed."
+ But this would be a surprising application behaviour, possibly
+ even security relevant.
+ - For the Windows CreateProcess() function, it is unspecified whether
+ a relative file name is interpreted to the parent's current
+ directory or to the specified directory. See
+ <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
+ if (! IS_ABSOLUTE_FILE_NAME (prog_path))
+ {
+ const char *resolved_prog =
+ find_in_given_path (prog_path, getenv ("PATH"), false);
+ if (resolved_prog == NULL)
+ goto fail_with_errno;
+ if (resolved_prog != prog_path)
+ prog_path_to_free = (char *) resolved_prog;
+ prog_path = resolved_prog;
+
+ if (! IS_ABSOLUTE_FILE_NAME (prog_path))
+ {
+ char *absolute_prog =
+ canonicalize_filename_mode (prog_path,
+ CAN_MISSING | CAN_NOLINKS);
+ if (absolute_prog == NULL)
+ {
+ saved_errno = errno;
+ free (prog_path_to_free);
+ goto fail_with_saved_errno;
+ }
+ free (prog_path_to_free);
+ prog_path_to_free = absolute_prog;
+ prog_path = absolute_prog;
+
+ if (! IS_ABSOLUTE_FILE_NAME (prog_path))
+ abort ();
+ }
+ }
+ }
+
#if defined _WIN32 && ! defined __CYGWIN__
/* Native Windows API. */
- int saved_errno;
-
/* FIXME: Need to free memory allocated by prepare_spawn. */
prog_argv = prepare_spawn (prog_argv);
@@ -133,16 +185,17 @@ execute (const char *progname,
(HANDLE) _get_osfhandle (null_stderr ? nulloutfd : STDERR_FILENO);
exitcode = spawnpvech (P_WAIT, prog_path, (const char **) prog_argv,
- (const char **) environ, NULL,
+ (const char **) environ, directory,
stdin_handle, stdout_handle, stderr_handle);
if (exitcode == -1 && errno == ENOEXEC)
{
/* prog is not a native executable. Try to execute it as a
shell script. Note that prepare_spawn() has already prepended
a hidden element "sh.exe" to prog_argv. */
+ prog_argv[0] = prog_path;
--prog_argv;
exitcode = spawnpvech (P_WAIT, prog_argv[0], (const char **) prog_argv,
- (const char **) environ, NULL,
+ (const char **) environ, directory,
stdin_handle, stdout_handle, stderr_handle);
}
}
@@ -152,17 +205,13 @@ execute (const char *progname,
close (nulloutfd);
if (nullinfd >= 0)
close (nullinfd);
+ free (prog_path_to_free);
if (termsigp != NULL)
*termsigp = 0;
if (exitcode == -1)
- {
- if (exit_on_error || !null_stderr)
- error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
- _("%s subprocess failed"), progname);
- return 127;
- }
+ goto fail_with_saved_errno;
return exitcode;
@@ -209,6 +258,9 @@ execute (const char *progname,
"/dev/null", O_RDWR,
0))
!= 0)
+ || (directory != NULL
+ && (err = posix_spawn_file_actions_addchdir (&actions,
+ directory)))
|| (slave_process
&& ((err = posix_spawnattr_init (&attrs)) != 0
|| (attrs_allocated = true,
@@ -218,9 +270,13 @@ execute (const char *progname,
|| (err = posix_spawnattr_setflags (&attrs,
POSIX_SPAWN_SETSIGMASK))
!= 0)))
- || (err = posix_spawnp (&child, prog_path, &actions,
- attrs_allocated ? &attrs : NULL, prog_argv,
- environ))
+ || (err = (directory != NULL
+ ? posix_spawn (&child, prog_path, &actions,
+ attrs_allocated ? &attrs : NULL, prog_argv,
+ environ)
+ : posix_spawnp (&child, prog_path, &actions,
+ attrs_allocated ? &attrs : NULL, prog_argv,
+ environ)))
!= 0))
{
if (actions_allocated)
@@ -229,12 +285,11 @@ execute (const char *progname,
posix_spawnattr_destroy (&attrs);
if (slave_process)
unblock_fatal_signals ();
+ free (prog_path_to_free);
if (termsigp != NULL)
*termsigp = 0;
- if (exit_on_error || !null_stderr)
- error (exit_on_error ? EXIT_FAILURE : 0, err,
- _("%s subprocess failed"), progname);
- return 127;
+ saved_errno = err;
+ goto fail_with_saved_errno;
}
posix_spawn_file_actions_destroy (&actions);
if (attrs_allocated)
@@ -244,9 +299,18 @@ execute (const char *progname,
register_slave_subprocess (child);
unblock_fatal_signals ();
}
+ free (prog_path_to_free);
return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
slave_process, exit_on_error, termsigp);
#endif
+
+ fail_with_errno:
+ saved_errno = errno;
+ fail_with_saved_errno:
+ if (exit_on_error || !null_stderr)
+ error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
+ _("%s subprocess failed"), progname);
+ return 127;
}
diff --git a/lib/execute.h b/lib/execute.h
index b31c4d1fe4..34fc989668 100644
--- a/lib/execute.h
+++ b/lib/execute.h
@@ -32,6 +32,9 @@
prog_argv is the array of strings that the subprocess shall receive in
argv[]. It is a NULL-terminated array. prog_argv[0] should normally be
identical to prog_path.
+ If directory is not NULL, the command is executed in that directory. If
+ prog_path is a relative file name, it resolved before changing to that
+ directory. The current directory of the current process remains unchanged.
If ignore_sigpipe is true, consider a subprocess termination due to SIGPIPE
as equivalent to a success. This is suitable for processes whose only
purpose is to write to standard output.
@@ -44,6 +47,7 @@
is called. See spawn-pipe.h for the reason. */
extern int execute (const char *progname,
const char *prog_path, char **prog_argv,
+ const char *directory,
bool ignore_sigpipe,
bool null_stdin, bool null_stdout, bool null_stderr,
bool slave_process, bool exit_on_error,
diff --git a/lib/javacomp.c b/lib/javacomp.c
index 63efc2d782..fec5180394 100644
--- a/lib/javacomp.c
+++ b/lib/javacomp.c
@@ -343,8 +343,9 @@ compile_using_envjavac (const char *javac,
argv[1] = "-c";
argv[2] = command;
argv[3] = NULL;
- exitstatus = execute (javac, BOURNE_SHELL, argv, false, false, false,
- null_stderr, true, true, NULL);
+ exitstatus = execute (javac, BOURNE_SHELL, argv, NULL,
+ false, false, false, null_stderr,
+ true, true, NULL);
err = (exitstatus != 0);
freea (command);
@@ -425,7 +426,8 @@ compile_using_gcj (const char * const *java_sources,
free (command);
}
- exitstatus = execute ("gcj", "gcj", argv, false, false, false, null_stderr,
+ exitstatus = execute ("gcj", "gcj", argv, NULL,
+ false, false, false, null_stderr,
true, true, NULL);
err = (exitstatus != 0);
@@ -496,7 +498,8 @@ compile_using_javac (const char * const *java_sources,
free (command);
}
- exitstatus = execute ("javac", "javac", argv, false, false, false,
+ exitstatus = execute ("javac", "javac", argv, NULL,
+ false, false, false,
null_stderr, true, true, NULL);
err = (exitstatus != 0);
@@ -551,8 +554,9 @@ compile_using_jikes (const char * const *java_sources,
free (command);
}
- exitstatus = execute ("jikes", "jikes", argv, false, false, false,
- null_stderr, true, true, NULL);
+ exitstatus = execute ("jikes", "jikes", argv, NULL,
+ false, false, false, null_stderr,
+ true, true, NULL);
err = (exitstatus != 0);
freea (argv);
@@ -1872,7 +1876,8 @@ is_javac_present (void)
argv[0] = "javac";
argv[1] = NULL;
- exitstatus = execute ("javac", "javac", argv, false, false, true, true,
+ exitstatus = execute ("javac", "javac", argv, NULL,
+ false, false, true, true,
true, false, NULL);
javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2);
javac_tested = true;
@@ -2138,7 +2143,8 @@ is_jikes_present (void)
argv[0] = "jikes";
argv[1] = NULL;
- exitstatus = execute ("jikes", "jikes", argv, false, false, true, true,
+ exitstatus = execute ("jikes", "jikes", argv, NULL,
+ false, false, true, true,
true, false, NULL);
jikes_present = (exitstatus == 0 || exitstatus == 1);
jikes_tested = true;
diff --git a/lib/javaexec.c b/lib/javaexec.c
index a374bff348..d486fb8715 100644
--- a/lib/javaexec.c
+++ b/lib/javaexec.c
@@ -208,7 +208,8 @@ execute_java_class (const char *class_name,
argv[0] = "gij";
argv[1] = "--version";
argv[2] = NULL;
- exitstatus = execute ("gij", "gij", argv, false, false, true, true,
+ exitstatus = execute ("gij", "gij", argv, NULL,
+ false, false, true, true,
true, false, NULL);
gij_present = (exitstatus == 0);
gij_tested = true;
@@ -261,7 +262,8 @@ execute_java_class (const char *class_name,
argv[0] = "java";
argv[1] = "-version";
argv[2] = NULL;
- exitstatus = execute ("java", "java", argv, false, false, true, true,
+ exitstatus = execute ("java", "java", argv, NULL,
+ false, false, true, true,
true, false, NULL);
java_present = (exitstatus == 0);
java_tested = true;
@@ -315,7 +317,8 @@ execute_java_class (const char *class_name,
argv[0] = "jre";
argv[1] = NULL;
- exitstatus = execute ("jre", "jre", argv, false, false, true, true,
+ exitstatus = execute ("jre", "jre", argv, NULL,
+ false, false, true, true,
true, false, NULL);
jre_present = (exitstatus == 0 || exitstatus == 1);
jre_tested = true;
@@ -372,7 +375,8 @@ execute_java_class (const char *class_name,
argv[0] = "jview";
argv[1] = "-?";
argv[2] = NULL;
- exitstatus = execute ("jview", "jview", argv, false, false, true, true,
+ exitstatus = execute ("jview", "jview", argv, NULL,
+ false, false, true, true,
true, false, NULL);
jview_present = (exitstatus == 0 || exitstatus == 1);
jview_tested = true;
diff --git a/modules/execute b/modules/execute
index 52eee5fed0..cb04003288 100644
--- a/modules/execute
+++ b/modules/execute
@@ -8,15 +8,20 @@ m4/execute.m4
Depends-on:
dup2
+canonicalize
environ
error
fatal-signal
+filename
+findprog-in
msvc-nothrow
gettext-h
spawn
+posix_spawn
posix_spawnp
posix_spawn_file_actions_init
posix_spawn_file_actions_addopen
+posix_spawn_file_actions_addchdir
posix_spawn_file_actions_destroy
posix_spawnattr_init
posix_spawnattr_setsigmask
diff --git a/modules/execute-tests b/modules/execute-tests
index 854b1ad8f6..9562182131 100644
--- a/modules/execute-tests
+++ b/modules/execute-tests
@@ -7,6 +7,7 @@ tests/macros.h
Depends-on:
dup2
fcntl
+mkdir
msvc-inval
read-file
stdint
diff --git a/tests/test-execute-child.c b/tests/test-execute-child.c
index 77f99ae0db..8197c300de 100644
--- a/tests/test-execute-child.c
+++ b/tests/test-execute-child.c
@@ -29,7 +29,7 @@
/* Get declarations of the native Windows API functions. */
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
-/* Get _get_osfhandle, _isatty. */
+/* Get _get_osfhandle, _isatty, _chdir, _getcwd. */
# include <io.h>
#endif
@@ -41,6 +41,7 @@
#undef fprintf
#undef fputs
#undef fstat
+#undef getcwd
#undef isatty
#undef raise
#undef read
@@ -201,6 +202,23 @@ main (int argc, char *argv[])
return 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0);
#endif
}
+ case 21:
+ /* Check execution in a different directory. */
+ {
+ char cwd[1024];
+ #if defined _WIN32 && ! defined __CYGWIN__
+ if (_chdir ("..") != 0)
+ return 1;
+ if (_getcwd (cwd, sizeof (cwd)) == NULL)
+ return 2;
+ #else
+ if (chdir ("..") != 0)
+ return 1;
+ if (getcwd (cwd, sizeof (cwd)) == NULL)
+ return 2;
+ #endif
+ return (argc == 3 && strcmp (argv[2], cwd) == 0 ? 0 : 3);
+ }
default:
abort ();
}
diff --git a/tests/test-execute-main.c b/tests/test-execute-main.c
index 62357c1e61..755209e682 100644
--- a/tests/test-execute-main.c
+++ b/tests/test-execute-main.c
@@ -26,9 +26,10 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
#if defined _WIN32 && ! defined __CYGWIN__
-/* Get _isatty. */
+/* Get _isatty, _getcwd. */
# include <io.h>
#endif
@@ -63,7 +64,7 @@ main (int argc, char *argv[])
{
/* Check an invocation without arguments. Check the exit code. */
char *prog_argv[2] = { prog_path, NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 40);
}
@@ -72,7 +73,7 @@ main (int argc, char *argv[])
{
/* Check an invocation of a non-existent program. */
char *prog_argv[3] = { "./non-existent", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 127);
}
@@ -96,7 +97,7 @@ main (int argc, char *argv[])
(char *) "",
NULL
};
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -107,7 +108,7 @@ main (int argc, char *argv[])
/* Check SIGPIPE handling with ignore_sigpipe = false. */
char *prog_argv[3] = { prog_path, (char *) "3", NULL };
int termsig = 0xDEADBEEF;
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, &termsig);
ASSERT (ret == 127);
ASSERT (termsig == SIGPIPE);
@@ -120,7 +121,7 @@ main (int argc, char *argv[])
/* Check SIGPIPE handling with ignore_sigpipe = true. */
char *prog_argv[3] = { prog_path, (char *) "4", NULL };
int termsig = 0xDEADBEEF;
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
true, false, false, false, true, false, &termsig);
ASSERT (ret == 0);
ASSERT (termsig == SIGPIPE);
@@ -132,7 +133,7 @@ main (int argc, char *argv[])
/* Check other signal. */
char *prog_argv[3] = { prog_path, (char *) "5", NULL };
int termsig = 0xDEADBEEF;
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, &termsig);
#if defined _WIN32 && !defined __CYGWIN__
ASSERT (ret == 3);
@@ -154,7 +155,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "6", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -173,7 +174,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "7", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, true, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -188,7 +189,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "8", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -208,7 +209,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "9", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -220,7 +221,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "10", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, true, false, true, false, NULL);
ASSERT (ret == 0);
@@ -240,7 +241,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "11", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -260,7 +261,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "12", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -272,7 +273,7 @@ main (int argc, char *argv[])
ASSERT (fp != NULL);
char *prog_argv[3] = { prog_path, (char *) "13", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, true, true, false, NULL);
ASSERT (ret == 0);
@@ -290,7 +291,7 @@ main (int argc, char *argv[])
/* Check file descriptors >= 3 can be inherited. */
ASSERT (dup2 (STDOUT_FILENO, 10) >= 0);
char *prog_argv[3] = { prog_path, (char *) "14", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
true, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -300,7 +301,7 @@ main (int argc, char *argv[])
/* Check file descriptors >= 3 can be inherited. */
ASSERT (fcntl (STDOUT_FILENO, F_DUPFD, 10) >= 0);
char *prog_argv[3] = { prog_path, (char *) "15", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
true, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -310,7 +311,7 @@ main (int argc, char *argv[])
/* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */
ASSERT (fcntl (STDOUT_FILENO, F_DUPFD_CLOEXEC, 10) >= 0);
char *prog_argv[3] = { prog_path, (char *) "16", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
true, false, false, false, true, false, NULL);
ASSERT (ret == 0);
}
@@ -335,7 +336,7 @@ main (int argc, char *argv[])
/* The file position is now 2. */
char *prog_argv[3] = { prog_path, (char *) "17", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -359,7 +360,7 @@ main (int argc, char *argv[])
/* The file position is now 3. */
char *prog_argv[3] = { prog_path, (char *) "18", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
ASSERT (ret == 0);
@@ -395,7 +396,7 @@ main (int argc, char *argv[])
fd_out = 11;
char *prog_argv[3] = { prog_path, (char *) "19", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
#if defined _WIN32 && ! defined __CYGWIN__
ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
@@ -419,7 +420,7 @@ main (int argc, char *argv[])
int fd_out = 11;
char *prog_argv[3] = { prog_path, (char *) "20", NULL };
- int ret = execute (progname, prog_argv[0], prog_argv,
+ int ret = execute (progname, prog_argv[0], prog_argv, NULL,
false, false, false, false, true, false, NULL);
#if defined _WIN32 && ! defined __CYGWIN__
ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
@@ -431,6 +432,27 @@ main (int argc, char *argv[])
close (fd_out);
}
break;
+ case 21:
+ {
+ /* Check execution in a different directory. */
+ rmdir (BASE ".sub");
+ ASSERT (mkdir (BASE ".sub", 0700) == 0);
+
+ char cwd[1024];
+ #if defined _WIN32 && ! defined __CYGWIN__
+ ASSERT (_getcwd (cwd, sizeof (cwd)) != NULL);
+ #else
+ ASSERT (getcwd (cwd, sizeof (cwd)) != NULL);
+ #endif
+
+ char *prog_argv[4] = { prog_path, (char *) "21", cwd, NULL };
+ int ret = execute (progname, prog_argv[0], prog_argv, BASE ".sub",
+ false, false, false, false, true, false, NULL);
+ ASSERT (ret == 0);
+
+ ASSERT (rmdir (BASE ".sub") == 0);
+ }
+ break;
default:
ASSERT (false);
}
diff --git a/tests/test-execute.sh b/tests/test-execute.sh
index 1320e76453..15c8b479b9 100755
--- a/tests/test-execute.sh
+++ b/tests/test-execute.sh
@@ -1,7 +1,7 @@
#!/bin/sh
st=0
-for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
+for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
${CHECKER} ./test-execute-main${EXEEXT} ./test-execute-child${EXEEXT} $i \
|| { echo test-execute.sh: test case $i failed >&2; st=1; }
done