system/popen: support r+, w+ mode
The standard popen uses the pipeline internally, so the stream returned by it can only support read-only or write-only. Now this patch is expanded through sockpair, which can support both read and write. Therefore, we can use the stream to read and write access this task (posix_spawn start). Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
c10e78869b
commit
e86f6c12a5
@ -115,11 +115,12 @@ FILE *popen(FAR const char *command, FAR const char *mode)
|
|||||||
posix_spawn_file_actions_t file_actions;
|
posix_spawn_file_actions_t file_actions;
|
||||||
FAR char *argv[4];
|
FAR char *argv[4];
|
||||||
int fd[2];
|
int fd[2];
|
||||||
int oldfd;
|
int oldfd[2];
|
||||||
int newfd;
|
int newfd[2];
|
||||||
int retfd;
|
int retfd;
|
||||||
int errcode;
|
int errcode;
|
||||||
int result;
|
int result = 0;
|
||||||
|
bool rw = false;
|
||||||
|
|
||||||
/* Allocate a container for returned FILE stream */
|
/* Allocate a container for returned FILE stream */
|
||||||
|
|
||||||
@ -130,35 +131,52 @@ FILE *popen(FAR const char *command, FAR const char *mode)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oldfd[1] = 0;
|
||||||
|
newfd[1] = 0;
|
||||||
|
|
||||||
/* Create a pipe. fd[0] refers to the read end of the pipe; fd[1] refers
|
/* Create a pipe. fd[0] refers to the read end of the pipe; fd[1] refers
|
||||||
* to the write end of the pipe.
|
* to the write end of the pipe.
|
||||||
|
* Is the pipe the input to the shell? Or the output?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
result = pipe(fd);
|
if (strcmp(mode, "r") == 0 && (result = pipe(fd)) >= 0)
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
errcode = errno;
|
|
||||||
goto errout_with_container;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is the pipe the input to the shell? Or the output? */
|
|
||||||
|
|
||||||
if (strcmp(mode, "r") == 0)
|
|
||||||
{
|
{
|
||||||
/* Pipe is the output from the shell */
|
/* Pipe is the output from the shell */
|
||||||
|
|
||||||
oldfd = 1; /* Replace stdout with the write side of the pipe */
|
oldfd[0] = 1; /* Replace stdout with the write side of the pipe */
|
||||||
newfd = fd[1];
|
newfd[0] = fd[1];
|
||||||
retfd = fd[0]; /* Use read side of the pipe to create the return stream */
|
retfd = fd[0]; /* Use read side of the pipe to create the return stream */
|
||||||
}
|
}
|
||||||
else if (strcmp(mode, "w") == 0)
|
else if (strcmp(mode, "w") == 0 && (result = pipe(fd)) >= 0)
|
||||||
{
|
{
|
||||||
/* Pipe is the input to the shell */
|
/* Pipe is the input to the shell */
|
||||||
|
|
||||||
oldfd = 0; /* Replace stdin with the read side of the pipe */
|
oldfd[0] = 0; /* Replace stdin with the read side of the pipe */
|
||||||
newfd = fd[0];
|
newfd[0] = fd[0];
|
||||||
retfd = fd[1]; /* Use write side of the pipe to create the return stream */
|
retfd = fd[1]; /* Use write side of the pipe to create the return stream */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a socketpair. Using fd[0] as the input and output to the shell */
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_LOCAL_STREAM)
|
||||||
|
else if ((strcmp(mode, "r+") == 0 || strcmp(mode, "w+") == 0) &&
|
||||||
|
(result = socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) >= 0)
|
||||||
|
{
|
||||||
|
/* Socketpair is the input/output to the shell */
|
||||||
|
|
||||||
|
rw = true;
|
||||||
|
oldfd[0] = 0; /* Replace stdin with the one side of a socket pair */
|
||||||
|
newfd[0] = fd[0];
|
||||||
|
oldfd[1] = 1; /* Replace stdout with the one side of a socket pair */
|
||||||
|
newfd[1] = fd[0];
|
||||||
|
retfd = fd[1]; /* Use other side of the socket pair to create the return stream */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (result < 0)
|
||||||
|
{
|
||||||
|
errcode = errno;
|
||||||
|
goto errout_with_container;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errcode = EINVAL;
|
errcode = EINVAL;
|
||||||
@ -236,12 +254,23 @@ FILE *popen(FAR const char *command, FAR const char *mode)
|
|||||||
|
|
||||||
/* Redirect input or output as determined by the mode parameter */
|
/* Redirect input or output as determined by the mode parameter */
|
||||||
|
|
||||||
errcode = posix_spawn_file_actions_adddup2(&file_actions, newfd, oldfd);
|
errcode = posix_spawn_file_actions_adddup2(&file_actions,
|
||||||
|
newfd[0], oldfd[0]);
|
||||||
if (errcode != 0)
|
if (errcode != 0)
|
||||||
{
|
{
|
||||||
goto errout_with_actions;
|
goto errout_with_actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rw)
|
||||||
|
{
|
||||||
|
errcode = posix_spawn_file_actions_adddup2(&file_actions,
|
||||||
|
newfd[1], oldfd[1]);
|
||||||
|
if (errcode != 0)
|
||||||
|
{
|
||||||
|
goto errout_with_actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Call task_spawn() (or posix_spawn), re-directing stdin or stdout
|
/* Call task_spawn() (or posix_spawn), re-directing stdin or stdout
|
||||||
* appropriately.
|
* appropriately.
|
||||||
*/
|
*/
|
||||||
@ -273,7 +302,12 @@ FILE *popen(FAR const char *command, FAR const char *mode)
|
|||||||
* the interface.
|
* the interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
close(newfd);
|
close(newfd[0]);
|
||||||
|
|
||||||
|
if (rw)
|
||||||
|
{
|
||||||
|
close(newfd[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free attributes and file actions. Ignoring return values in the case
|
/* Free attributes and file actions. Ignoring return values in the case
|
||||||
* of an error.
|
* of an error.
|
||||||
|
Loading…
Reference in New Issue
Block a user