summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--include/spawn.h3
-rw-r--r--posix/spawn_faction_addopen.c8
-rw-r--r--posix/wordexp-test.c113
-rw-r--r--posix/wordexp.c151
5 files changed, 126 insertions, 158 deletions
diff --git a/ChangeLog b/ChangeLog
index 1d4f418e17..2e34b2da34 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
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):
Add small optimization for older kernel to avoid issuing
__NR_getdents64 on each call and replace scratch_buffer usage with
diff --git a/include/spawn.h b/include/spawn.h
index 7fdd965bd7..4a0b1849da 100644
--- a/include/spawn.h
+++ b/include/spawn.h
@@ -11,6 +11,9 @@ __typeof (posix_spawn_file_actions_addclose)
__typeof (posix_spawn_file_actions_adddup2)
__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)
__posix_spawn_file_actions_destroy attribute_hidden;
diff --git a/posix/spawn_faction_addopen.c b/posix/spawn_faction_addopen.c
index d5694ee4d7..4fd64bb005 100644
--- a/posix/spawn_faction_addopen.c
+++ b/posix/spawn_faction_addopen.c
@@ -25,9 +25,9 @@
/* Add an action to FILE-ACTIONS which tells the implementation to call
`open' for the given file during the `spawn' call. */
int
-posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
- int fd, const char *path, int oflag,
- mode_t mode)
+__posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
+ int fd, const char *path, int oflag,
+ mode_t mode)
{
struct __spawn_action *rec;
@@ -60,3 +60,5 @@ posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
return 0;
}
+weak_alias (__posix_spawn_file_actions_addopen,
+ posix_spawn_file_actions_addopen)
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index a4d8bcf1da..7cbac030ab 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -15,19 +15,19 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
+#include <wordexp.h>
+#include <stdio.h>
#include <fcntl.h>
-#include <unistd.h>
#include <pwd.h>
-#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <wordexp.h>
+#include <sys/mman.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"
@@ -40,7 +40,7 @@ struct test_case_struct
size_t wordc;
const char *wordv[10];
const char *ifs;
-} test_case[] =
+} static test_case[] =
{
/* Simple word- and field-splitting */
{ 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 18043 */
{ 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);
@@ -226,21 +224,19 @@ command_line_test (const char *words)
wordexp_t we;
int i;
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++)
- printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
+ printf ("info: we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
}
-int
-main (int argc, char *argv[])
+static int
+do_test (int argc, char *argv[])
{
- const char *globfile[] = { "one", "two", "three", NULL };
+ const char *globfile[] = { "one", "two", "three" };
char tmpdir[32];
struct passwd *pw;
const char *cwd;
int test;
- int fail = 0;
- int i;
struct test_case_struct ts;
if (argc > 1)
@@ -253,21 +249,18 @@ main (int argc, char *argv[])
/* Set up arena for pathname expansion */
tmpnam (tmpdir);
- if (mkdir (tmpdir, S_IRWXU) || chdir (tmpdir))
- return -1;
- else
- {
- int fd;
+ xmkdir (tmpdir, S_IRWXU);
+ TEST_VERIFY_EXIT (chdir (tmpdir) == 0);
- for (i = 0; globfile[i]; ++i)
- if ((fd = creat (globfile[i], S_IRUSR | S_IWUSR)) == -1
- || close (fd))
- return -1;
+ for (int i = 0; i < array_length (globfile); ++i)
+ {
+ int fd = xopen (globfile[i], O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ xclose (fd);
}
- for (test = 0; test_case[test].retval != -1; test++)
- if (testit (&test_case[test]))
- ++fail;
+ for (test = 0; test < array_length (test_case); test++)
+ TEST_COMPARE (testit (&test_case[test]), 0);
/* Tilde-expansion tests. */
pw = getpwnam ("root");
@@ -281,8 +274,7 @@ main (int argc, char *argv[])
ts.wordv[0] = pw->pw_dir;
ts.ifs = IFS;
- if (testit (&ts))
- ++fail;
+ TEST_COMPARE (testit (&ts), 0);
ts.retval = 0;
ts.env = pw->pw_dir;
@@ -292,8 +284,7 @@ main (int argc, char *argv[])
ts.wordv[0] = "x";
ts.ifs = IFS;
- if (testit (&ts))
- ++fail;
+ TEST_COMPARE (testit (&ts), 0);
}
/* "~" 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.ifs = IFS;
- if (testit (&ts))
- ++fail;
+ TEST_COMPARE (testit (&ts), 0);
/* "~" 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.ifs = IFS;
- if (testit (&ts))
- ++fail;
+ TEST_COMPARE (testit (&ts), 0);
}
puts ("tests completed, now cleaning up");
/* Clean up */
- for (i = 0; globfile[i]; ++i)
+ for (int i = 0; i < array_length (globfile); ++i)
remove (globfile[i]);
if (cwd == NULL)
@@ -341,33 +330,20 @@ main (int argc, char *argv[])
chdir (cwd);
rmdir (tmpdir);
- printf ("tests failed: %d\n", fail);
-
- return fail != 0;
+ return 0;
}
-static const char *
+struct support_next_to_fault
at_page_end (const char *words)
{
- const int pagesize = getpagesize ();
- char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-
- if (start == MAP_FAILED)
- return start;
-
- if (mprotect (start + pagesize, pagesize, PROT_NONE))
- {
- munmap (start, 2 * pagesize);
- return MAP_FAILED;
- }
+ const size_t words_size = strlen (words) + 1;
+ struct support_next_to_fault ntf
+ = support_next_to_fault_allocate (words_size);
/* Includes terminating NUL. */
- const size_t words_size = strlen (words) + 1;
- char *words_start = start + pagesize - words_size;
- memcpy (words_start, words, words_size);
+ memcpy (ntf.buffer, words, words_size);
- return words_start;
+ return ntf;
}
static int
@@ -395,20 +371,20 @@ testit (struct test_case_struct *tc)
sav_we.we_offs = 3;
we = sav_we;
- printf ("Test %d (%s): ", ++tests, tc->words);
+ printf ("info: test %d (%s): ", ++tests, tc->words);
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)
{
/* initial wordexp() call, to be appended to */
if (wordexp ("pre1 pre2", &we, tc->flags & ~WRDE_APPEND) != 0)
{
- printf ("FAILED setup\n");
+ printf ("info: FAILED setup\n");
return 1;
}
}
- retval = wordexp (words, &we, tc->flags);
+ retval = wordexp (words.buffer, &we, tc->flags);
if (tc->flags & WRDE_DOOFFS)
start_offs = sav_we.we_offs;
@@ -436,7 +412,7 @@ testit (struct test_case_struct *tc)
if (bzzzt)
{
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);
if (start_offs != 0)
printf ("(preceded by %d NULLs)\n", start_offs);
@@ -465,12 +441,11 @@ testit (struct test_case_struct *tc)
if (retval == 0 || retval == WRDE_NOSPACE)
wordfree (&we);
- const int page_size = getpagesize ();
- char *start = (char *) PTR_ALIGN_DOWN (words, page_size);
-
- if (munmap (start, 2 * page_size) != 0)
- return 1;
+ support_next_to_fault_free (&words);
fflush (NULL);
return bzzzt;
}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 6a6e3a8e11..2aa6085fb2 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -25,33 +25,18 @@
#include <libintl.h>
#include <paths.h>
#include <pwd.h>
-#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.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 <unistd.h>
-#include <wchar.h>
#include <wordexp.h>
-#include <kernel-features.h>
+#include <spawn.h>
#include <scratch_buffer.h>
-
-#include <libc-lock.h>
#include <_itoa.h>
-
-/* Undefine the following line for the production version. */
-/* #define NDEBUG 1 */
#include <assert.h>
-/* Get some device information. */
-#include <device-nrs.h>
-
/*
* 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;
}
+#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() */
-static inline void
-__attribute__ ((always_inline))
-exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
+static pid_t
+exec_comm_child (char *comm, int *fildes, bool showerr, bool noexec)
{
- const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
+ pid_t pid = -1;
- /* Execute the command, or just check syntax? */
- if (noexec)
- args[1] = "-nc";
+ /* Execute the command, or just check syntax? */
+ const char *args[] = { _PATH_BSHELL, noexec ? "-nc" : "-c", comm, NULL };
+
+ posix_spawn_file_actions_t fa;
+ /* posix_spawn_file_actions_init does not fail. */
+ __posix_spawn_file_actions_init (&fa);
- /* Redirect output. */
- if (__glibc_likely (fildes[1] != STDOUT_FILENO))
+ /* 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)
{
- __dup2 (fildes[1], STDOUT_FILENO);
- __close (fildes[1]);
+ if (__glibc_likely (fildes[1] != STDOUT_FILENO))
+ {
+ if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1],
+ STDOUT_FILENO) != 0
+ || __posix_spawn_file_actions_addclose (&fa, fildes[1]) != 0)
+ goto out;
+ }
+ else
+ /* Reset the close-on-exec flag (if necessary). */
+ if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1], fildes[1])
+ != 0)
+ goto out;
}
- else
- /* Reset the close-on-exec flag (if necessary). */
- __fcntl (fildes[1], F_SETFD, 0);
/* 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;
- int fd;
- __close (STDERR_FILENO);
- fd = __open (_PATH_DEVNULL, O_WRONLY);
- if (fd >= 0 && fd != STDERR_FILENO)
- {
- __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);
+ for (char **ep = __environ; *ep != NULL; ep++)
+ if (strncmp (*ep, "IFS=", strlen ("IFS=")) != 0)
+ strlist_add (&newenv, *ep);
+ strlist_add (&newenv, NULL);
+ if (strlist_has_failed (&newenv))
+ goto out;
}
- /* Make sure the subshell doesn't field-split on our behalf. */
- __unsetenv ("IFS");
+ /* pid is not set if posix_spawn fails, so it keep the original value
+ of -1. */
+ __posix_spawn (&pid, _PATH_BSHELL, &fa, NULL, (char *const *) args,
+ recreate_env ? strlist_begin (&newenv) : __environ);
- __close (fildes[0]);
- __execve (_PATH_BSHELL, (char *const *) args, __environ);
+ strlist_free (&newenv);
+
+out:
+ __posix_spawn_file_actions_destroy (&fa);
- /* Bad. What now? */
- abort ();
+ return pid;
}
/* 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;
char buffer[bufsize];
pid_t pid;
- int noexec = 0;
+ bool noexec = false;
/* Do nothing if command substitution should not succeed. */
if (flags & WRDE_NOCMD)
return WRDE_CMDSUB;
- /* Don't fork() unless necessary */
+ /* Don't posix_spawn unless necessary */
if (!comm || !*comm)
return 0;
@@ -898,19 +898,15 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
return WRDE_NOSPACE;
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[1]);
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 (noexec)
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) */
if (buflen < 1 && status != 0)
{
- noexec = 1;
+ noexec = true;
goto again;
}
@@ -1143,26 +1139,9 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
/* Go -- give script to the shell */
if (comm)
{
-#ifdef __libc_ptf_call
- /* 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
-
+ /* posix_spawn already handles thread cancellation. */
error = exec_comm (comm, word, word_length, max_length,
flags, pwordexp, ifs, ifs_white);
-
-#ifdef __libc_ptf_call
- __libc_ptf_call (__pthread_setcancelstate,
- (state, NULL), 0);
-#endif
-
free (comm);
}