>From 702cba00f4ff7b22f0684a23db0fb66aea2c4086 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 2 Dec 2020 17:44:04 +0100 Subject: [PATCH 1/2] 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. --- ChangeLog | 23 +++++++++++ NEWS | 4 ++ lib/csharpcomp.c | 3 +- lib/csharpexec.c | 6 ++- lib/execute.c | 98 ++++++++++++++++++++++++++++++++++++++-------- lib/execute.h | 4 ++ lib/javacomp.c | 22 +++++++---- lib/javaexec.c | 12 ++++-- modules/execute | 5 +++ modules/execute-tests | 1 + tests/test-execute-child.c | 20 +++++++++- tests/test-execute-main.c | 66 ++++++++++++++++++++----------- tests/test-execute.sh | 2 +- 13 files changed, 210 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8e9e032..b5ea083 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2020-12-02 Bruno Haible + + 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 vma-iter: Add support for macOS11/arm64. diff --git a/NEWS b/NEWS index d76e3e7..445266d 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 fac9a89..cf68c5a 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 b54f14e..5e2aa2c 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 15556cf..03fb6ec 100644 --- a/lib/execute.c +++ b/lib/execute.c @@ -28,8 +28,11 @@ #include #include +#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 + : + "if this pathname does not start with a 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 + */ + 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 b31c4d1..34fc989 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 63efc2d..fec5180 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 a374bff..d486fb8 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 52eee5f..cb04003 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 854b1ad..9562182 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 77f99ae..8197c30 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 -/* Get _get_osfhandle, _isatty. */ +/* Get _get_osfhandle, _isatty, _chdir, _getcwd. */ # include #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 62357c1..755209e 100644 --- a/tests/test-execute-main.c +++ b/tests/test-execute-main.c @@ -26,9 +26,10 @@ #include #include #include +#include #if defined _WIN32 && ! defined __CYGWIN__ -/* Get _isatty. */ +/* Get _isatty, _getcwd. */ # include #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 1320e76..15c8b47 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 -- 2.7.4