summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap.conf1
-rw-r--r--src/job.c72
-rw-r--r--tests/scripts/features/targetvars26
-rw-r--r--tests/scripts/misc/general441
4 files changed, 132 insertions, 8 deletions
diff --git a/bootstrap.conf b/bootstrap.conf
index 8265660c..5e1d538e 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -46,6 +46,7 @@ gnulib_files=doc/make-stds.texi
gnulib_modules="\
alloca
fdl
+findprog-in
getloadavg
host-cpu-c-abi
strerror
diff --git a/src/job.c b/src/job.c
index 0c68e01f..115d8481 100644
--- a/src/job.c
+++ b/src/job.c
@@ -17,6 +17,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include <assert.h>
+#include <string.h>
#include "job.h"
#include "debug.h"
@@ -25,8 +26,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "variable.h"
#include "os.h"
-#include <string.h>
-
/* Default shell to use. */
#ifdef WINDOWS32
# ifdef HAVE_STRINGS_H
@@ -139,6 +138,7 @@ extern int wait3 ();
#ifdef USE_POSIX_SPAWN
# include <spawn.h>
+# include "findprog.h"
#endif
#if !defined (wait) && !defined (POSIX)
@@ -1466,8 +1466,6 @@ start_job_command (struct child *child)
environ = parent_environ; /* Restore value child may have clobbered. */
jobserver_post_child (flags & COMMANDS_RECURSE);
- free (child->cmd_name);
- child->cmd_name = child->pid > 0 ? xstrdup(argv[0]) : NULL;
#endif /* !VMS */
}
@@ -2271,9 +2269,10 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
pid_t pid;
int r;
#if defined(USE_POSIX_SPAWN)
- short flags = 0;
+ char *cmd;
posix_spawnattr_t attr;
posix_spawn_file_actions_t fa;
+ short flags = 0;
#endif
/* Divert child output if we want to capture it. */
@@ -2312,7 +2311,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
/* Run the command. */
exec_command (argv, child->environment);
-#else /* use posix_spawn() */
+#else /* USE_POSIX_SPAWN */
if ((r = posix_spawnattr_init (&attr)) != 0)
goto done;
@@ -2359,10 +2358,67 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
if ((r = posix_spawnattr_setflags (&attr, flags)) != 0)
goto cleanup;
+ /* Look up the program on the child's PATH, if needed. */
+ {
+ const char *p = NULL;
+ char **pp;
+
+ for (pp = child->environment; *pp != NULL; ++pp)
+ if ((*pp)[0] == 'P' && (*pp)[1] == 'A' && (*pp)[2] == 'T'
+ && (*pp)[3] == 'H' &&(*pp)[4] == '=')
+ {
+ p = (*pp) + 5;
+ break;
+ }
+
+ cmd = (char *)find_in_given_path (argv[0], p);
+ }
+
+ if (!cmd)
+ {
+ r = ENOENT;
+ goto cleanup;
+ }
+
/* Start the program. */
- while ((r = posix_spawnp (&pid, argv[0], &fa, &attr, argv, child->environment)) == EINTR)
+ while ((r = posix_spawn (&pid, cmd, &fa, &attr, argv,
+ child->environment)) == EINTR)
;
+ /* posix_spawn() doesn't provide sh fallback like exec() does; implement
+ it here. POSIX doesn't specify the path to sh so use the default. */
+
+ if (r == ENOEXEC)
+ {
+ char **nargv;
+ char **pp;
+ size_t l = 0;
+
+ for (pp = argv; *pp != NULL; ++pp)
+ ++l;
+
+ nargv = xmalloc (sizeof (char *) * (l + 2));
+ nargv[0] = (char *)default_shell;
+ nargv[1] = cmd;
+ memcpy (&nargv[2], &argv[1], sizeof (char *) * l);
+
+ while ((r = posix_spawn (&pid, nargv[0], &fa, &attr, nargv,
+ child->environment)) == EINTR)
+ ;
+
+ free (nargv);
+ }
+
+ if (r == 0)
+ {
+ /* Spawn succeeded but may fail later: remember the command. */
+ free (child->cmd_name);
+ if (cmd != argv[0])
+ child->cmd_name = cmd;
+ else
+ child->cmd_name = xstrdup(cmd);
+ }
+
cleanup:
posix_spawn_file_actions_destroy (&fa);
posix_spawnattr_destroy (&attr);
@@ -2371,7 +2427,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
if (r != 0)
pid = -1;
-#endif /* have posix_spawn() */
+#endif /* USE_POSIX_SPAWN */
if (pid < 0)
OSS (error, NILF, "%s: %s", argv[0], strerror (r));
diff --git a/tests/scripts/features/targetvars b/tests/scripts/features/targetvars
index 72b7ddc7..1eb29a76 100644
--- a/tests/scripts/features/targetvars
+++ b/tests/scripts/features/targetvars
@@ -255,6 +255,32 @@ a: ; @echo $(A)
!,
'', "hello; world\n");
+# TEST #21: SV-56834 Ensure setting PATH in a target var works properly
+mkdir('sd', 0775);
+open(my $fh, '>', 'sd/foobar');
+print $fh "exit 0";
+close($fh);
+chmod 0755, 'sd/foobar';
+
+run_make_test(q!
+all: PATH := sd
+all: ; foobar
+!,
+ '', "foobar\n");
+
+# Don't use the general PATH if not found on the target path
+
+$extraENV{PATH} = "$ENV{PATH}:sd";
+
+run_make_test(q!
+all: PATH := ..
+all: ; foobar
+!,
+ '', "foobar\n#MAKE#: foobar: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#;3: all] Error 127", 512);
+
+unlink('sd/foobar');
+rmdir ('sd');
+
# TEST #19: Test define/endef variables as target-specific vars
# run_make_test('
diff --git a/tests/scripts/misc/general4 b/tests/scripts/misc/general4
index 6d42a16d..72f3dbd0 100644
--- a/tests/scripts/misc/general4
+++ b/tests/scripts/misc/general4
@@ -79,4 +79,45 @@ all: ; \@echo hi
",
'', "hi\n");
+# SV-56834 Ensure setting PATH in the makefile works properly
+mkdir('sd', 0775);
+open(my $fh, '>', 'sd/foobar');
+print $fh "exit 0\n";
+close($fh);
+chmod 0755, 'sd/foobar';
+
+run_make_test(q!
+PATH := sd
+all: ; foobar
+!,
+ '', "foobar\n");
+
+# Don't use the general PATH if not found on the target path
+
+$extraENV{PATH} = "$ENV{PATH}:sd";
+
+run_make_test(q!
+PATH := ..
+all: ; foobar
+!,
+ '', "foobar\n#MAKE#: foobar: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#;3: all] Error 127", 512);
+
+unlink('sd/foobar');
+rmdir('sd');
+
+# Ensure that local programs are not found if "." is not on the PATH
+
+open(my $fh, '>', 'foobar');
+print $fh "exit 0\n";
+close($fh);
+chmod 0755, 'foobar';
+
+run_make_test(q!
+PATH := ..
+all: ; foobar
+!,
+ '', "foobar\n#MAKE#: foobar: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#;3: all] Error 127", 512);
+
+unlink('foobar');
+
1;