* syscalls.cc (popen): Introduce Glibc 'e' flag to allow thread-safe
opening of the pipe with O_CLOEXEC flag. Simplify FD_CLOEXEC handling.
This commit is contained in:
parent
92a8ea56e5
commit
3507271d6b
@ -1,3 +1,8 @@
|
|||||||
|
2014-01-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* syscalls.cc (popen): Introduce Glibc 'e' flag to allow thread-safe
|
||||||
|
opening of the pipe with O_CLOEXEC flag. Simplify FD_CLOEXEC handling.
|
||||||
|
|
||||||
2014-01-17 Corinna Vinschen <corinna@vinschen.de>
|
2014-01-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* include/sys/file.h (LOCK_SH): Drop definition in favor of new
|
* include/sys/file.h (LOCK_SH): Drop definition in favor of new
|
||||||
|
@ -4236,11 +4236,36 @@ extern "C" FILE *
|
|||||||
popen (const char *command, const char *in_type)
|
popen (const char *command, const char *in_type)
|
||||||
{
|
{
|
||||||
const char *type = in_type;
|
const char *type = in_type;
|
||||||
char rw = *type++;
|
char fdopen_flags[3] = "\0\0";
|
||||||
|
int pipe_flags = 0;
|
||||||
|
|
||||||
/* Sanity check in_type */
|
#define rw fdopen_flags[0]
|
||||||
if (*type == 'b' || *type == 't')
|
#define bintext fdopen_flags[1]
|
||||||
type++;
|
|
||||||
|
/* Sanity check. GLibc allows any order and any number of repetition,
|
||||||
|
as long as the string doesn't contradict itself. We do the same here. */
|
||||||
|
while (*type)
|
||||||
|
{
|
||||||
|
if (*type == 'r' || *type == 'w')
|
||||||
|
{
|
||||||
|
if (rw && rw != *type)
|
||||||
|
break;
|
||||||
|
rw = *type++;
|
||||||
|
}
|
||||||
|
else if (*type == 'b' || *type == 't')
|
||||||
|
{
|
||||||
|
if (bintext && bintext != *type)
|
||||||
|
break;
|
||||||
|
bintext = *type++;
|
||||||
|
}
|
||||||
|
else if (*type == 'e')
|
||||||
|
{
|
||||||
|
pipe_flags = O_CLOEXEC;
|
||||||
|
++type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ((rw != 'r' && rw != 'w') || (*type != '\0'))
|
if ((rw != 'r' && rw != 'w') || (*type != '\0'))
|
||||||
{
|
{
|
||||||
set_errno (EINVAL);
|
set_errno (EINVAL);
|
||||||
@ -4248,13 +4273,13 @@ popen (const char *command, const char *in_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fds[2];
|
int fds[2];
|
||||||
if (pipe (fds) < 0)
|
if (pipe2 (fds, pipe_flags) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int myix = rw == 'r' ? 0 : 1;
|
int myix = rw == 'r' ? 0 : 1;
|
||||||
|
|
||||||
lock_process now;
|
lock_process now;
|
||||||
FILE *fp = fdopen (fds[myix], in_type);
|
FILE *fp = fdopen (fds[myix], fdopen_flags);
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
/* If fds are in the range of stdin/stdout/stderr, move them
|
/* If fds are in the range of stdin/stdout/stderr, move them
|
||||||
@ -4290,9 +4315,13 @@ popen (const char *command, const char *in_type)
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Don't pass our end of the pipe to the child process */
|
/* With 'e' flag given, we have to revert the close-on-exec on the child
|
||||||
int fd_state = fcntl64 (myfd, F_GETFD, 0);
|
end of the pipe. Otherwise don't pass our end of the pipe to the
|
||||||
fcntl64 (myfd, F_SETFD, fd_state | FD_CLOEXEC);
|
child process. */
|
||||||
|
if (pipe_flags & O_CLOEXEC)
|
||||||
|
fcntl64 (__std[stdchild], F_SETFD, 0);
|
||||||
|
else
|
||||||
|
fcntl64 (myfd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
/* Also don't pass the file handle currently associated with stdin/stdout
|
/* Also don't pass the file handle currently associated with stdin/stdout
|
||||||
to the child. This function may actually fail if the stdchild fd
|
to the child. This function may actually fail if the stdchild fd
|
||||||
@ -4318,10 +4347,8 @@ popen (const char *command, const char *in_type)
|
|||||||
if (fds[myix] != orig_fds[myix])
|
if (fds[myix] != orig_fds[myix])
|
||||||
cygheap->fdtab.move_fd (fds[myix], myfd = orig_fds[myix]);
|
cygheap->fdtab.move_fd (fds[myix], myfd = orig_fds[myix]);
|
||||||
fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[myfd];
|
fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[myfd];
|
||||||
/* Flag that this handle is associated with popen and then reset
|
/* Flag that this handle is associated with popen. */
|
||||||
the handle's original close-on-exec state. */
|
|
||||||
fh->set_popen_pid (pid);
|
fh->set_popen_pid (pid);
|
||||||
fcntl64 (myfd, F_SETFD, fd_state);
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4332,6 +4359,10 @@ popen (const char *command, const char *in_type)
|
|||||||
close (fds[0]);
|
close (fds[0]);
|
||||||
close (fds[1]);
|
close (fds[1]);
|
||||||
set_errno (save_errno);
|
set_errno (save_errno);
|
||||||
|
|
||||||
|
#undef rw
|
||||||
|
#undef bintext
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user