mirror of git://gcc.gnu.org/git/gcc.git
[libiberty] Use pipe inside pex_run
https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00039.html * configure.ac (checkfuncs): Add pipe2. * config.in, configure: Rebuilt. * pex-unix.c (pex_unix_exec_child): Comminicate errors from child to parent with a pipe, when possible. From-SVN: r264769
This commit is contained in:
parent
2649038cea
commit
df1346b423
|
@ -1,3 +1,10 @@
|
||||||
|
2018-10-01 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
|
* configure.ac (checkfuncs): Add pipe2.
|
||||||
|
* config.in, configure: Rebuilt.
|
||||||
|
* pex-unix.c (pex_unix_exec_child): Comminicate errors from child
|
||||||
|
to parent with a pipe, when possible.
|
||||||
|
|
||||||
2018-08-23 Nathan Sidwell <nathan@acm.org>
|
2018-08-23 Nathan Sidwell <nathan@acm.org>
|
||||||
Martin Liska <mliska@suse.cz>
|
Martin Liska <mliska@suse.cz>
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,9 @@
|
||||||
/* Define to 1 if you have the `on_exit' function. */
|
/* Define to 1 if you have the `on_exit' function. */
|
||||||
#undef HAVE_ON_EXIT
|
#undef HAVE_ON_EXIT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `pipe2' function. */
|
||||||
|
#undef HAVE_PIPE2
|
||||||
|
|
||||||
/* Define to 1 if you have the <process.h> header file. */
|
/* Define to 1 if you have the <process.h> header file. */
|
||||||
#undef HAVE_PROCESS_H
|
#undef HAVE_PROCESS_H
|
||||||
|
|
||||||
|
|
|
@ -5727,7 +5727,7 @@ funcs="$funcs setproctitle"
|
||||||
vars="sys_errlist sys_nerr sys_siglist"
|
vars="sys_errlist sys_nerr sys_siglist"
|
||||||
|
|
||||||
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \
|
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \
|
||||||
getsysinfo gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic \
|
getsysinfo gettimeofday on_exit pipe2 psignal pstat_getdynamic pstat_getstatic \
|
||||||
realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \
|
realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \
|
||||||
sysmp table times wait3 wait4"
|
sysmp table times wait3 wait4"
|
||||||
|
|
||||||
|
@ -5743,7 +5743,7 @@ if test "x" = "y"; then
|
||||||
index insque \
|
index insque \
|
||||||
memchr memcmp memcpy memmem memmove memset mkstemps \
|
memchr memcmp memcpy memmem memmove memset mkstemps \
|
||||||
on_exit \
|
on_exit \
|
||||||
psignal pstat_getdynamic pstat_getstatic putenv \
|
pipe2 psignal pstat_getdynamic pstat_getstatic putenv \
|
||||||
random realpath rename rindex \
|
random realpath rename rindex \
|
||||||
sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \
|
sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \
|
||||||
stpcpy stpncpy strcasecmp strchr strdup \
|
stpcpy stpncpy strcasecmp strchr strdup \
|
||||||
|
|
|
@ -391,7 +391,7 @@ funcs="$funcs setproctitle"
|
||||||
vars="sys_errlist sys_nerr sys_siglist"
|
vars="sys_errlist sys_nerr sys_siglist"
|
||||||
|
|
||||||
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \
|
checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \
|
||||||
getsysinfo gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic \
|
getsysinfo gettimeofday on_exit pipe2 psignal pstat_getdynamic pstat_getstatic \
|
||||||
realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \
|
realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \
|
||||||
sysmp table times wait3 wait4"
|
sysmp table times wait3 wait4"
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ if test "x" = "y"; then
|
||||||
index insque \
|
index insque \
|
||||||
memchr memcmp memcpy memmem memmove memset mkstemps \
|
memchr memcmp memcpy memmem memmove memset mkstemps \
|
||||||
on_exit \
|
on_exit \
|
||||||
psignal pstat_getdynamic pstat_getstatic putenv \
|
pipe2 psignal pstat_getdynamic pstat_getstatic putenv \
|
||||||
random realpath rename rindex \
|
random realpath rename rindex \
|
||||||
sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \
|
sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \
|
||||||
stpcpy stpncpy strcasecmp strchr strdup \
|
stpcpy stpncpy strcasecmp strchr strdup \
|
||||||
|
|
|
@ -569,6 +569,38 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
int toclose, const char **errmsg, int *err)
|
int toclose, const char **errmsg, int *err)
|
||||||
{
|
{
|
||||||
pid_t pid = -1;
|
pid_t pid = -1;
|
||||||
|
/* Tuple to communicate error from child to parent. We can safely
|
||||||
|
transfer string literal pointers as both run with identical
|
||||||
|
address mappings. */
|
||||||
|
struct fn_err
|
||||||
|
{
|
||||||
|
const char *fn;
|
||||||
|
int err;
|
||||||
|
};
|
||||||
|
volatile int do_pipe = 0;
|
||||||
|
volatile int pipes[2]; /* [0]:reader,[1]:writer. */
|
||||||
|
#ifdef O_CLOEXEC
|
||||||
|
do_pipe = 1;
|
||||||
|
#endif
|
||||||
|
if (do_pipe)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_PIPE2
|
||||||
|
if (pipe2 ((int *)pipes, O_CLOEXEC))
|
||||||
|
do_pipe = 0;
|
||||||
|
#else
|
||||||
|
if (pipe ((int *)pipes))
|
||||||
|
do_pipe = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||||
|
{
|
||||||
|
close (pipes[0]);
|
||||||
|
close (pipes[1]);
|
||||||
|
do_pipe = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* We declare these to be volatile to avoid warnings from gcc about
|
/* We declare these to be volatile to avoid warnings from gcc about
|
||||||
them being clobbered by vfork. */
|
them being clobbered by vfork. */
|
||||||
|
@ -579,8 +611,9 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
This clobbers the parent's environ so we need to restore it.
|
This clobbers the parent's environ so we need to restore it.
|
||||||
It would be nice to use one of the exec* functions that takes an
|
It would be nice to use one of the exec* functions that takes an
|
||||||
environment as a parameter, but that may have portability
|
environment as a parameter, but that may have portability
|
||||||
issues. */
|
issues. It is marked volatile so the child doesn't consider it a
|
||||||
char **save_environ = environ;
|
dead variable and therefore clobber where ever it is stored. */
|
||||||
|
char **volatile save_environ = environ;
|
||||||
|
|
||||||
for (retries = 0; retries < 4; ++retries)
|
for (retries = 0; retries < 4; ++retries)
|
||||||
{
|
{
|
||||||
|
@ -594,6 +627,11 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
switch (pid)
|
switch (pid)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
|
if (do_pipe)
|
||||||
|
{
|
||||||
|
close (pipes[0]);
|
||||||
|
close (pipes[1]);
|
||||||
|
}
|
||||||
*err = errno;
|
*err = errno;
|
||||||
*errmsg = VFORK_STRING;
|
*errmsg = VFORK_STRING;
|
||||||
return (pid_t) -1;
|
return (pid_t) -1;
|
||||||
|
@ -601,40 +639,43 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
case 0:
|
case 0:
|
||||||
/* Child process. */
|
/* Child process. */
|
||||||
{
|
{
|
||||||
const char *bad_fn = NULL;
|
struct fn_err failed;
|
||||||
|
failed.fn = NULL;
|
||||||
|
|
||||||
if (!bad_fn && in != STDIN_FILE_NO)
|
if (do_pipe)
|
||||||
|
close (pipes[0]);
|
||||||
|
if (!failed.fn && in != STDIN_FILE_NO)
|
||||||
{
|
{
|
||||||
if (dup2 (in, STDIN_FILE_NO) < 0)
|
if (dup2 (in, STDIN_FILE_NO) < 0)
|
||||||
bad_fn = "dup2";
|
failed.fn = "dup2", failed.err = errno;
|
||||||
else if (close (in) < 0)
|
else if (close (in) < 0)
|
||||||
bad_fn = "close";
|
failed.fn = "close", failed.err = errno;
|
||||||
}
|
}
|
||||||
if (!bad_fn && out != STDOUT_FILE_NO)
|
if (!failed.fn && out != STDOUT_FILE_NO)
|
||||||
{
|
{
|
||||||
if (dup2 (out, STDOUT_FILE_NO) < 0)
|
if (dup2 (out, STDOUT_FILE_NO) < 0)
|
||||||
bad_fn = "dup2";
|
failed.fn = "dup2", failed.err = errno;
|
||||||
else if (close (out) < 0)
|
else if (close (out) < 0)
|
||||||
bad_fn = "close";
|
failed.fn = "close", failed.err = errno;
|
||||||
}
|
}
|
||||||
if (!bad_fn && errdes != STDERR_FILE_NO)
|
if (!failed.fn && errdes != STDERR_FILE_NO)
|
||||||
{
|
{
|
||||||
if (dup2 (errdes, STDERR_FILE_NO) < 0)
|
if (dup2 (errdes, STDERR_FILE_NO) < 0)
|
||||||
bad_fn = "dup2";
|
failed.fn = "dup2", failed.err = errno;
|
||||||
else if (close (errdes) < 0)
|
else if (close (errdes) < 0)
|
||||||
bad_fn = "close";
|
failed.fn = "close", failed.err = errno;
|
||||||
}
|
}
|
||||||
if (!bad_fn && toclose >= 0)
|
if (!failed.fn && toclose >= 0)
|
||||||
{
|
{
|
||||||
if (close (toclose) < 0)
|
if (close (toclose) < 0)
|
||||||
bad_fn = "close";
|
failed.fn = "close", failed.err = errno;
|
||||||
}
|
}
|
||||||
if (!bad_fn && (flags & PEX_STDERR_TO_STDOUT) != 0)
|
if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0)
|
||||||
{
|
{
|
||||||
if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
|
if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
|
||||||
bad_fn = "dup2";
|
failed.fn = "dup2", failed.err = errno;
|
||||||
}
|
}
|
||||||
if (!bad_fn)
|
if (!failed.fn)
|
||||||
{
|
{
|
||||||
if (env)
|
if (env)
|
||||||
/* NOTE: In a standard vfork implementation this clobbers
|
/* NOTE: In a standard vfork implementation this clobbers
|
||||||
|
@ -644,30 +685,35 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
if ((flags & PEX_SEARCH) != 0)
|
if ((flags & PEX_SEARCH) != 0)
|
||||||
{
|
{
|
||||||
execvp (executable, to_ptr32 (argv));
|
execvp (executable, to_ptr32 (argv));
|
||||||
bad_fn = "execvp";
|
failed.fn = "execvp", failed.err = errno;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
execv (executable, to_ptr32 (argv));
|
execv (executable, to_ptr32 (argv));
|
||||||
bad_fn = "execv";
|
failed.fn = "execv", failed.err = errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Something failed, report an error. We don't use stdio
|
/* Something failed, report an error. We don't use stdio
|
||||||
routines, because we might be here due to a vfork call. */
|
routines, because we might be here due to a vfork call. */
|
||||||
ssize_t retval = 0;
|
ssize_t retval = 0;
|
||||||
int eno = errno;
|
|
||||||
|
|
||||||
|
if (!do_pipe
|
||||||
|
|| write (pipes[1], &failed, sizeof (failed)) != sizeof (failed))
|
||||||
|
{
|
||||||
|
/* The parent will not see our scream above, so write to
|
||||||
|
stdout. */
|
||||||
#define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s)))
|
#define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s)))
|
||||||
writeerr (obj->pname);
|
writeerr (obj->pname);
|
||||||
writeerr (": error trying to exec '");
|
writeerr (": error trying to exec '");
|
||||||
writeerr (executable);
|
writeerr (executable);
|
||||||
writeerr ("': ");
|
writeerr ("': ");
|
||||||
writeerr (bad_fn);
|
writeerr (failed.fn);
|
||||||
writeerr (": ");
|
writeerr (": ");
|
||||||
writeerr (xstrerror (eno));
|
writeerr (xstrerror (failed.err));
|
||||||
writeerr ("\n");
|
writeerr ("\n");
|
||||||
#undef writeerr
|
#undef writeerr
|
||||||
|
}
|
||||||
|
|
||||||
/* Exit with -2 if the error output failed, too. */
|
/* Exit with -2 if the error output failed, too. */
|
||||||
_exit (retval < 0 ? -2 : -1);
|
_exit (retval < 0 ? -2 : -1);
|
||||||
|
@ -678,8 +724,6 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
default:
|
default:
|
||||||
/* Parent process. */
|
/* Parent process. */
|
||||||
{
|
{
|
||||||
const char *bad_fn = NULL;
|
|
||||||
|
|
||||||
/* Restore environ. Note that the parent either doesn't run
|
/* Restore environ. Note that the parent either doesn't run
|
||||||
until the child execs/exits (standard vfork behaviour), or
|
until the child execs/exits (standard vfork behaviour), or
|
||||||
if it does run then vfork is behaving more like fork. In
|
if it does run then vfork is behaving more like fork. In
|
||||||
|
@ -687,24 +731,34 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
||||||
copy of environ. */
|
copy of environ. */
|
||||||
environ = save_environ;
|
environ = save_environ;
|
||||||
|
|
||||||
if (!bad_fn && in != STDIN_FILE_NO)
|
struct fn_err failed;
|
||||||
if (close (in) < 0)
|
failed.fn = NULL;
|
||||||
bad_fn = "close";
|
if (do_pipe)
|
||||||
if (!bad_fn && out != STDOUT_FILE_NO)
|
|
||||||
if (close (out) < 0)
|
|
||||||
bad_fn = "close";
|
|
||||||
if (!bad_fn && errdes != STDERR_FILE_NO)
|
|
||||||
if (close (errdes) < 0)
|
|
||||||
bad_fn = "close";
|
|
||||||
|
|
||||||
if (bad_fn)
|
|
||||||
{
|
{
|
||||||
*err = errno;
|
close (pipes[1]);
|
||||||
*errmsg = bad_fn;
|
ssize_t len = read (pipes[0], &failed, sizeof (failed));
|
||||||
|
if (len < 0)
|
||||||
|
failed.fn = NULL;
|
||||||
|
close (pipes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failed.fn && in != STDIN_FILE_NO)
|
||||||
|
if (close (in) < 0)
|
||||||
|
failed.fn = "close", failed.err = errno;
|
||||||
|
if (!failed.fn && out != STDOUT_FILE_NO)
|
||||||
|
if (close (out) < 0)
|
||||||
|
failed.fn = "close", failed.err = errno;
|
||||||
|
if (!failed.fn && errdes != STDERR_FILE_NO)
|
||||||
|
if (close (errdes) < 0)
|
||||||
|
failed.fn = "close", failed.err = errno;
|
||||||
|
|
||||||
|
if (failed.fn)
|
||||||
|
{
|
||||||
|
*err = failed.err;
|
||||||
|
*errmsg = failed.fn;
|
||||||
return (pid_t) -1;
|
return (pid_t) -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue