mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
posix: Use posix_spawn for wordexp
This patch replaces the fork+exec by posix_spawn on wordexp, which allows a better scability on Linux and simplifies the thread cancellation handling. The only change which can not be implemented with posix_spawn the /dev/null check to certify it is indeed the expected device. I am not sure how effetive this check is since /dev/null tampering means something very wrong with the system and this is the least of the issues. My view is the tests is really out of the place and the hardening provided is minimum. If the idea is still to provide such check, I think a possibilty would be to open /dev/null, check it, add a dup2 file action, and close the file descriptor. Checked on powerpc64le-linux-gnu and x86_64-linux-gnu. * include/spawn.h (__posix_spawn_file_actions_addopen): New prototype. * posix/spawn_faction_addopen.c (posix_spawn_file_actions_addopen): Add internal alias. * posix/wordexp.c (create_environment, free_environment): New functions. (exec_comm_child, exec_comm): Use posix_spawn instead of fork+exec. * posix/wordexp-test.c: Use libsupport.
This commit is contained in:
parent
edcda4c08a
commit
db8cbc6a7a
@ -1,5 +1,14 @@
|
|||||||
2019-10-09 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
2019-10-09 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
* include/spawn.h (__posix_spawn_file_actions_addopen): New
|
||||||
|
prototype.
|
||||||
|
* posix/spawn_faction_addopen.c (posix_spawn_file_actions_addopen):
|
||||||
|
Add internal alias.
|
||||||
|
* posix/wordexp.c (create_environment, free_environment): New
|
||||||
|
functions.
|
||||||
|
(exec_comm_child, exec_comm): Use posix_spawn instead of fork+exec.
|
||||||
|
* posix/wordexp-test.c: Use libsupport.
|
||||||
|
|
||||||
* sysdeps/unix/sysv/linux/mips/mips64/getdents64.c (__getdents64):
|
* sysdeps/unix/sysv/linux/mips/mips64/getdents64.c (__getdents64):
|
||||||
Add small optimization for older kernel to avoid issuing
|
Add small optimization for older kernel to avoid issuing
|
||||||
__NR_getdents64 on each call and replace scratch_buffer usage with
|
__NR_getdents64 on each call and replace scratch_buffer usage with
|
||||||
|
@ -11,6 +11,9 @@ __typeof (posix_spawn_file_actions_addclose)
|
|||||||
__typeof (posix_spawn_file_actions_adddup2)
|
__typeof (posix_spawn_file_actions_adddup2)
|
||||||
__posix_spawn_file_actions_adddup2 attribute_hidden;
|
__posix_spawn_file_actions_adddup2 attribute_hidden;
|
||||||
|
|
||||||
|
__typeof (posix_spawn_file_actions_addopen)
|
||||||
|
__posix_spawn_file_actions_addopen attribute_hidden;
|
||||||
|
|
||||||
__typeof (posix_spawn_file_actions_destroy)
|
__typeof (posix_spawn_file_actions_destroy)
|
||||||
__posix_spawn_file_actions_destroy attribute_hidden;
|
__posix_spawn_file_actions_destroy attribute_hidden;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
/* Add an action to FILE-ACTIONS which tells the implementation to call
|
/* Add an action to FILE-ACTIONS which tells the implementation to call
|
||||||
`open' for the given file during the `spawn' call. */
|
`open' for the given file during the `spawn' call. */
|
||||||
int
|
int
|
||||||
posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
|
__posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
|
||||||
int fd, const char *path, int oflag,
|
int fd, const char *path, int oflag,
|
||||||
mode_t mode)
|
mode_t mode)
|
||||||
{
|
{
|
||||||
@ -60,3 +60,5 @@ posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
weak_alias (__posix_spawn_file_actions_addopen,
|
||||||
|
posix_spawn_file_actions_addopen)
|
||||||
|
@ -15,19 +15,19 @@
|
|||||||
License along with the GNU C Library; if not, see
|
License along with the GNU C Library; if not, see
|
||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <wordexp.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <fcntl.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wordexp.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include <libc-pointer-arith.h>
|
#include <libc-pointer-arith.h>
|
||||||
#include <dso_handle.h>
|
#include <array_length.h>
|
||||||
|
#include <support/xunistd.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
#include <support/next_to_fault.h>
|
||||||
|
|
||||||
#define IFS " \n\t"
|
#define IFS " \n\t"
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ struct test_case_struct
|
|||||||
size_t wordc;
|
size_t wordc;
|
||||||
const char *wordv[10];
|
const char *wordv[10];
|
||||||
const char *ifs;
|
const char *ifs;
|
||||||
} test_case[] =
|
} static test_case[] =
|
||||||
{
|
{
|
||||||
/* Simple word- and field-splitting */
|
/* Simple word- and field-splitting */
|
||||||
{ 0, NULL, "one", 0, 1, { "one", }, IFS },
|
{ 0, NULL, "one", 0, 1, { "one", }, IFS },
|
||||||
@ -213,8 +213,6 @@ struct test_case_struct
|
|||||||
{ WRDE_SYNTAX, NULL, "`\\", 0, 0, { NULL, }, IFS }, /* BZ 18042 */
|
{ WRDE_SYNTAX, NULL, "`\\", 0, 0, { NULL, }, IFS }, /* BZ 18042 */
|
||||||
{ WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS }, /* BZ 18043 */
|
{ WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS }, /* BZ 18043 */
|
||||||
{ WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS }, /* BZ 18043#c4 */
|
{ WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS }, /* BZ 18043#c4 */
|
||||||
|
|
||||||
{ -1, NULL, NULL, 0, 0, { NULL, }, IFS },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int testit (struct test_case_struct *tc);
|
static int testit (struct test_case_struct *tc);
|
||||||
@ -226,21 +224,19 @@ command_line_test (const char *words)
|
|||||||
wordexp_t we;
|
wordexp_t we;
|
||||||
int i;
|
int i;
|
||||||
int retval = wordexp (words, &we, 0);
|
int retval = wordexp (words, &we, 0);
|
||||||
printf ("wordexp returned %d\n", retval);
|
printf ("info: wordexp returned %d\n", retval);
|
||||||
for (i = 0; i < we.we_wordc; i++)
|
for (i = 0; i < we.we_wordc; i++)
|
||||||
printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
|
printf ("info: we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
main (int argc, char *argv[])
|
do_test (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const char *globfile[] = { "one", "two", "three", NULL };
|
const char *globfile[] = { "one", "two", "three" };
|
||||||
char tmpdir[32];
|
char tmpdir[32];
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
const char *cwd;
|
const char *cwd;
|
||||||
int test;
|
int test;
|
||||||
int fail = 0;
|
|
||||||
int i;
|
|
||||||
struct test_case_struct ts;
|
struct test_case_struct ts;
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
@ -253,21 +249,18 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
/* Set up arena for pathname expansion */
|
/* Set up arena for pathname expansion */
|
||||||
tmpnam (tmpdir);
|
tmpnam (tmpdir);
|
||||||
if (mkdir (tmpdir, S_IRWXU) || chdir (tmpdir))
|
xmkdir (tmpdir, S_IRWXU);
|
||||||
return -1;
|
TEST_VERIFY_EXIT (chdir (tmpdir) == 0);
|
||||||
else
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
for (i = 0; globfile[i]; ++i)
|
for (int i = 0; i < array_length (globfile); ++i)
|
||||||
if ((fd = creat (globfile[i], S_IRUSR | S_IWUSR)) == -1
|
{
|
||||||
|| close (fd))
|
int fd = xopen (globfile[i], O_WRONLY|O_CREAT|O_TRUNC,
|
||||||
return -1;
|
S_IRUSR | S_IWUSR);
|
||||||
|
xclose (fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (test = 0; test_case[test].retval != -1; test++)
|
for (test = 0; test < array_length (test_case); test++)
|
||||||
if (testit (&test_case[test]))
|
TEST_COMPARE (testit (&test_case[test]), 0);
|
||||||
++fail;
|
|
||||||
|
|
||||||
/* Tilde-expansion tests. */
|
/* Tilde-expansion tests. */
|
||||||
pw = getpwnam ("root");
|
pw = getpwnam ("root");
|
||||||
@ -281,8 +274,7 @@ main (int argc, char *argv[])
|
|||||||
ts.wordv[0] = pw->pw_dir;
|
ts.wordv[0] = pw->pw_dir;
|
||||||
ts.ifs = IFS;
|
ts.ifs = IFS;
|
||||||
|
|
||||||
if (testit (&ts))
|
TEST_COMPARE (testit (&ts), 0);
|
||||||
++fail;
|
|
||||||
|
|
||||||
ts.retval = 0;
|
ts.retval = 0;
|
||||||
ts.env = pw->pw_dir;
|
ts.env = pw->pw_dir;
|
||||||
@ -292,8 +284,7 @@ main (int argc, char *argv[])
|
|||||||
ts.wordv[0] = "x";
|
ts.wordv[0] = "x";
|
||||||
ts.ifs = IFS;
|
ts.ifs = IFS;
|
||||||
|
|
||||||
if (testit (&ts))
|
TEST_COMPARE (testit (&ts), 0);
|
||||||
++fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "~" expands to value of $HOME when HOME is set */
|
/* "~" expands to value of $HOME when HOME is set */
|
||||||
@ -308,8 +299,7 @@ main (int argc, char *argv[])
|
|||||||
ts.wordv[1] = "/dummy/home/foo";
|
ts.wordv[1] = "/dummy/home/foo";
|
||||||
ts.ifs = IFS;
|
ts.ifs = IFS;
|
||||||
|
|
||||||
if (testit (&ts))
|
TEST_COMPARE (testit (&ts), 0);
|
||||||
++fail;
|
|
||||||
|
|
||||||
/* "~" expands to home dir from passwd file if HOME is not set */
|
/* "~" expands to home dir from passwd file if HOME is not set */
|
||||||
|
|
||||||
@ -325,14 +315,13 @@ main (int argc, char *argv[])
|
|||||||
ts.wordv[0] = pw->pw_dir;
|
ts.wordv[0] = pw->pw_dir;
|
||||||
ts.ifs = IFS;
|
ts.ifs = IFS;
|
||||||
|
|
||||||
if (testit (&ts))
|
TEST_COMPARE (testit (&ts), 0);
|
||||||
++fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
puts ("tests completed, now cleaning up");
|
puts ("tests completed, now cleaning up");
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
for (i = 0; globfile[i]; ++i)
|
for (int i = 0; i < array_length (globfile); ++i)
|
||||||
remove (globfile[i]);
|
remove (globfile[i]);
|
||||||
|
|
||||||
if (cwd == NULL)
|
if (cwd == NULL)
|
||||||
@ -341,33 +330,20 @@ main (int argc, char *argv[])
|
|||||||
chdir (cwd);
|
chdir (cwd);
|
||||||
rmdir (tmpdir);
|
rmdir (tmpdir);
|
||||||
|
|
||||||
printf ("tests failed: %d\n", fail);
|
return 0;
|
||||||
|
|
||||||
return fail != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
struct support_next_to_fault
|
||||||
at_page_end (const char *words)
|
at_page_end (const char *words)
|
||||||
{
|
{
|
||||||
const int pagesize = getpagesize ();
|
const size_t words_size = strlen (words) + 1;
|
||||||
char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE,
|
struct support_next_to_fault ntf
|
||||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
= support_next_to_fault_allocate (words_size);
|
||||||
|
|
||||||
if (start == MAP_FAILED)
|
|
||||||
return start;
|
|
||||||
|
|
||||||
if (mprotect (start + pagesize, pagesize, PROT_NONE))
|
|
||||||
{
|
|
||||||
munmap (start, 2 * pagesize);
|
|
||||||
return MAP_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Includes terminating NUL. */
|
/* Includes terminating NUL. */
|
||||||
const size_t words_size = strlen (words) + 1;
|
memcpy (ntf.buffer, words, words_size);
|
||||||
char *words_start = start + pagesize - words_size;
|
|
||||||
memcpy (words_start, words, words_size);
|
|
||||||
|
|
||||||
return words_start;
|
return ntf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -395,20 +371,20 @@ testit (struct test_case_struct *tc)
|
|||||||
sav_we.we_offs = 3;
|
sav_we.we_offs = 3;
|
||||||
we = sav_we;
|
we = sav_we;
|
||||||
|
|
||||||
printf ("Test %d (%s): ", ++tests, tc->words);
|
printf ("info: test %d (%s): ", ++tests, tc->words);
|
||||||
fflush (NULL);
|
fflush (NULL);
|
||||||
const char *words = at_page_end (tc->words);
|
struct support_next_to_fault words = at_page_end (tc->words);
|
||||||
|
|
||||||
if (tc->flags & WRDE_APPEND)
|
if (tc->flags & WRDE_APPEND)
|
||||||
{
|
{
|
||||||
/* initial wordexp() call, to be appended to */
|
/* initial wordexp() call, to be appended to */
|
||||||
if (wordexp ("pre1 pre2", &we, tc->flags & ~WRDE_APPEND) != 0)
|
if (wordexp ("pre1 pre2", &we, tc->flags & ~WRDE_APPEND) != 0)
|
||||||
{
|
{
|
||||||
printf ("FAILED setup\n");
|
printf ("info: FAILED setup\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = wordexp (words, &we, tc->flags);
|
retval = wordexp (words.buffer, &we, tc->flags);
|
||||||
|
|
||||||
if (tc->flags & WRDE_DOOFFS)
|
if (tc->flags & WRDE_DOOFFS)
|
||||||
start_offs = sav_we.we_offs;
|
start_offs = sav_we.we_offs;
|
||||||
@ -436,7 +412,7 @@ testit (struct test_case_struct *tc)
|
|||||||
if (bzzzt)
|
if (bzzzt)
|
||||||
{
|
{
|
||||||
printf ("FAILED\n");
|
printf ("FAILED\n");
|
||||||
printf ("Test words: <%s>, need retval %d, wordc %Zd\n",
|
printf ("info: Test words: <%s>, need retval %d, wordc %Zd\n",
|
||||||
tc->words, tc->retval, tc->wordc);
|
tc->words, tc->retval, tc->wordc);
|
||||||
if (start_offs != 0)
|
if (start_offs != 0)
|
||||||
printf ("(preceded by %d NULLs)\n", start_offs);
|
printf ("(preceded by %d NULLs)\n", start_offs);
|
||||||
@ -465,12 +441,11 @@ testit (struct test_case_struct *tc)
|
|||||||
if (retval == 0 || retval == WRDE_NOSPACE)
|
if (retval == 0 || retval == WRDE_NOSPACE)
|
||||||
wordfree (&we);
|
wordfree (&we);
|
||||||
|
|
||||||
const int page_size = getpagesize ();
|
support_next_to_fault_free (&words);
|
||||||
char *start = (char *) PTR_ALIGN_DOWN (words, page_size);
|
|
||||||
|
|
||||||
if (munmap (start, 2 * page_size) != 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
fflush (NULL);
|
fflush (NULL);
|
||||||
return bzzzt;
|
return bzzzt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TEST_FUNCTION_ARGV do_test
|
||||||
|
#include <support/test-driver.c>
|
||||||
|
143
posix/wordexp.c
143
posix/wordexp.c
@ -25,33 +25,18 @@
|
|||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wchar.h>
|
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
#include <kernel-features.h>
|
#include <spawn.h>
|
||||||
#include <scratch_buffer.h>
|
#include <scratch_buffer.h>
|
||||||
|
|
||||||
#include <libc-lock.h>
|
|
||||||
#include <_itoa.h>
|
#include <_itoa.h>
|
||||||
|
|
||||||
/* Undefine the following line for the production version. */
|
|
||||||
/* #define NDEBUG 1 */
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
/* Get some device information. */
|
|
||||||
#include <device-nrs.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a recursive-descent-style word expansion routine.
|
* This is a recursive-descent-style word expansion routine.
|
||||||
*/
|
*/
|
||||||
@ -812,61 +797,76 @@ parse_arith (char **word, size_t *word_length, size_t *max_length,
|
|||||||
return WRDE_SYNTAX;
|
return WRDE_SYNTAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DYNARRAY_STRUCT strlist
|
||||||
|
#define DYNARRAY_ELEMENT char *
|
||||||
|
#define DYNARRAY_PREFIX strlist_
|
||||||
|
/* Allocates about 512/1024 (32/64 bit) on stack. */
|
||||||
|
#define DYNARRAY_INITIAL_SIZE 128
|
||||||
|
#include <malloc/dynarray-skeleton.c>
|
||||||
|
|
||||||
/* Function called by child process in exec_comm() */
|
/* Function called by child process in exec_comm() */
|
||||||
static inline void
|
static pid_t
|
||||||
__attribute__ ((always_inline))
|
exec_comm_child (char *comm, int *fildes, bool showerr, bool noexec)
|
||||||
exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
|
|
||||||
{
|
{
|
||||||
const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
|
pid_t pid = -1;
|
||||||
|
|
||||||
/* Execute the command, or just check syntax? */
|
/* Execute the command, or just check syntax? */
|
||||||
if (noexec)
|
const char *args[] = { _PATH_BSHELL, noexec ? "-nc" : "-c", comm, NULL };
|
||||||
args[1] = "-nc";
|
|
||||||
|
|
||||||
/* Redirect output. */
|
posix_spawn_file_actions_t fa;
|
||||||
|
/* posix_spawn_file_actions_init does not fail. */
|
||||||
|
__posix_spawn_file_actions_init (&fa);
|
||||||
|
|
||||||
|
/* Redirect output. For check syntax only (noexec being true), exec_comm
|
||||||
|
explicits sets fildes[1] to -1, so check its value to avoid a failure in
|
||||||
|
__posix_spawn_file_actions_adddup2. */
|
||||||
|
if (fildes[1] != -1)
|
||||||
|
{
|
||||||
if (__glibc_likely (fildes[1] != STDOUT_FILENO))
|
if (__glibc_likely (fildes[1] != STDOUT_FILENO))
|
||||||
{
|
{
|
||||||
__dup2 (fildes[1], STDOUT_FILENO);
|
if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1],
|
||||||
__close (fildes[1]);
|
STDOUT_FILENO) != 0
|
||||||
|
|| __posix_spawn_file_actions_addclose (&fa, fildes[1]) != 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Reset the close-on-exec flag (if necessary). */
|
/* Reset the close-on-exec flag (if necessary). */
|
||||||
__fcntl (fildes[1], F_SETFD, 0);
|
if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1], fildes[1])
|
||||||
|
!= 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Redirect stderr to /dev/null if we have to. */
|
/* Redirect stderr to /dev/null if we have to. */
|
||||||
if (showerr == 0)
|
if (!showerr)
|
||||||
|
if (__posix_spawn_file_actions_addopen (&fa, STDERR_FILENO, _PATH_DEVNULL,
|
||||||
|
O_WRONLY, 0) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
struct strlist newenv;
|
||||||
|
strlist_init (&newenv);
|
||||||
|
|
||||||
|
bool recreate_env = getenv ("IFS") != NULL;
|
||||||
|
if (recreate_env)
|
||||||
{
|
{
|
||||||
struct stat64 st;
|
for (char **ep = __environ; *ep != NULL; ep++)
|
||||||
int fd;
|
if (strncmp (*ep, "IFS=", strlen ("IFS=")) != 0)
|
||||||
__close (STDERR_FILENO);
|
strlist_add (&newenv, *ep);
|
||||||
fd = __open (_PATH_DEVNULL, O_WRONLY);
|
strlist_add (&newenv, NULL);
|
||||||
if (fd >= 0 && fd != STDERR_FILENO)
|
if (strlist_has_failed (&newenv))
|
||||||
{
|
goto out;
|
||||||
__dup2 (fd, STDERR_FILENO);
|
|
||||||
__close (fd);
|
|
||||||
}
|
|
||||||
/* Be paranoid. Check that we actually opened the /dev/null
|
|
||||||
device. */
|
|
||||||
if (__builtin_expect (__fxstat64 (_STAT_VER, STDERR_FILENO, &st), 0) != 0
|
|
||||||
|| __builtin_expect (S_ISCHR (st.st_mode), 1) == 0
|
|
||||||
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
|
|
||||||
|| st.st_rdev != __gnu_dev_makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
/* It's not the /dev/null device. Stop right here. The
|
|
||||||
problem is: how do we stop? We use _exit() with an
|
|
||||||
hopefully unusual exit code. */
|
|
||||||
_exit (90);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the subshell doesn't field-split on our behalf. */
|
/* pid is not set if posix_spawn fails, so it keep the original value
|
||||||
__unsetenv ("IFS");
|
of -1. */
|
||||||
|
__posix_spawn (&pid, _PATH_BSHELL, &fa, NULL, (char *const *) args,
|
||||||
|
recreate_env ? strlist_begin (&newenv) : __environ);
|
||||||
|
|
||||||
__close (fildes[0]);
|
strlist_free (&newenv);
|
||||||
__execve (_PATH_BSHELL, (char *const *) args, __environ);
|
|
||||||
|
|
||||||
/* Bad. What now? */
|
out:
|
||||||
abort ();
|
__posix_spawn_file_actions_destroy (&fa);
|
||||||
|
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function to execute a command and retrieve the results */
|
/* Function to execute a command and retrieve the results */
|
||||||
@ -884,13 +884,13 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
|||||||
size_t maxnewlines = 0;
|
size_t maxnewlines = 0;
|
||||||
char buffer[bufsize];
|
char buffer[bufsize];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int noexec = 0;
|
bool noexec = false;
|
||||||
|
|
||||||
/* Do nothing if command substitution should not succeed. */
|
/* Do nothing if command substitution should not succeed. */
|
||||||
if (flags & WRDE_NOCMD)
|
if (flags & WRDE_NOCMD)
|
||||||
return WRDE_CMDSUB;
|
return WRDE_CMDSUB;
|
||||||
|
|
||||||
/* Don't fork() unless necessary */
|
/* Don't posix_spawn unless necessary */
|
||||||
if (!comm || !*comm)
|
if (!comm || !*comm)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -898,19 +898,15 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
|||||||
return WRDE_NOSPACE;
|
return WRDE_NOSPACE;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if ((pid = __fork ()) < 0)
|
pid = exec_comm_child (comm, fildes, noexec ? false : flags & WRDE_SHOWERR,
|
||||||
|
noexec);
|
||||||
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
/* Bad */
|
|
||||||
__close (fildes[0]);
|
__close (fildes[0]);
|
||||||
__close (fildes[1]);
|
__close (fildes[1]);
|
||||||
return WRDE_NOSPACE;
|
return WRDE_NOSPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0)
|
|
||||||
exec_comm_child (comm, fildes, noexec ? 0 : flags & WRDE_SHOWERR, noexec);
|
|
||||||
|
|
||||||
/* Parent */
|
|
||||||
|
|
||||||
/* If we are just testing the syntax, only wait. */
|
/* If we are just testing the syntax, only wait. */
|
||||||
if (noexec)
|
if (noexec)
|
||||||
return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid
|
return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid
|
||||||
@ -1091,7 +1087,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
|||||||
/* Check for syntax error (re-execute but with "-n" flag) */
|
/* Check for syntax error (re-execute but with "-n" flag) */
|
||||||
if (buflen < 1 && status != 0)
|
if (buflen < 1 && status != 0)
|
||||||
{
|
{
|
||||||
noexec = 1;
|
noexec = true;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,26 +1139,9 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
|
|||||||
/* Go -- give script to the shell */
|
/* Go -- give script to the shell */
|
||||||
if (comm)
|
if (comm)
|
||||||
{
|
{
|
||||||
#ifdef __libc_ptf_call
|
/* posix_spawn already handles thread cancellation. */
|
||||||
/* We do not want the exec_comm call to be cut short
|
|
||||||
by a thread cancellation since cleanup is very
|
|
||||||
ugly. Therefore disable cancellation for
|
|
||||||
now. */
|
|
||||||
// XXX Ideally we do want the thread being cancelable.
|
|
||||||
// XXX If demand is there we'll change it.
|
|
||||||
int state = PTHREAD_CANCEL_ENABLE;
|
|
||||||
__libc_ptf_call (__pthread_setcancelstate,
|
|
||||||
(PTHREAD_CANCEL_DISABLE, &state), 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
error = exec_comm (comm, word, word_length, max_length,
|
error = exec_comm (comm, word, word_length, max_length,
|
||||||
flags, pwordexp, ifs, ifs_white);
|
flags, pwordexp, ifs, ifs_white);
|
||||||
|
|
||||||
#ifdef __libc_ptf_call
|
|
||||||
__libc_ptf_call (__pthread_setcancelstate,
|
|
||||||
(state, NULL), 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free (comm);
|
free (comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user