子 shell 进程双向重定向到父进程
Child shell process bidirectional redirection to parent process
你好 Whosebug 我试图创建一个程序来执行子 shell 进程并将他的 I/O 重定向到管道以便与他的父进程通信。
我可以通过写入管道 (wpipefd) 执行命令,但我无法从读取管道 (rpipefd) 上的 shell 进程获得响应。
到目前为止,根据 Strace,我有 3 个错误:首先,读取函数阻塞了程序,所以我将读取管道的读取 fd 设置为非阻塞 (rpipe[0]
)。然后我在读取函数时遇到了一个 EAGAIN 错误......最后,当我在使用 dup2()
之后的分叉进程中关闭来自 rpipe (close(rpipefd[0])
) 的读取 fd 时,我得到了一个 EPIPE 错误。
我不明白我做错了什么。这是我到目前为止所做的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
int flags = fcntl(rpipefd[0], F_GETFL, 0);
fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],1);
dup2(rpipefd[1],2);
close(wpipefd[1]);
dup2(wpipefd[0],0);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
}
close(wpipefd[0]);
write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
close(rpipefd[1]);
read(rpipefd[0],buffer,BUF_SIZE);
//perror("read()");
printf("%s",buffer);
exit(0);
}
请帮忙!
主要问题并非来自代码本身:传递给 shell 的命令不完整,您错过了最后的 '\n' 以及子进程(您的 shell ) 正在等待命令的其余部分。
非阻塞部分不是一个好主意(或者至少,您应该围绕管道旋转以检索其内容。)
完成命令后,您应该关闭输出管道,以便 shell 在其输入中获取文件结尾。
其他说明:您应该等待子进程终止(使用 wait(2)),您应该在子进程中的 execl 之后离开(使用 with err(3) 来处理错误信息)来处理 exec 错误。而且,说真的,在字符串文字上调用 strlen ?我知道 gcc 会在编译时替换它,但是 …
这是您的代码的修改版本:
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],STDOUT_FILENO);
dup2(rpipefd[1],STDERR_FILENO);
close(wpipefd[1]);
dup2(wpipefd[0],STDIN_FILENO);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
err(1, "execl()");
}
close(wpipefd[0]);
close(rpipefd[1]);
write(wpipefd[1], "echo helloWorld\n", 16);
close(wpipefd[1]); // we're done, say it to the shell
int r;
while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
{
if (r == -1)
{
if (errno == EAGAIN || errno == EINTR) continue;
err(1, "read()");
}
write(STDOUT_FILENO, buffer, r);
}
wait(NULL);
return 0;
}
你好 Whosebug 我试图创建一个程序来执行子 shell 进程并将他的 I/O 重定向到管道以便与他的父进程通信。
我可以通过写入管道 (wpipefd) 执行命令,但我无法从读取管道 (rpipefd) 上的 shell 进程获得响应。
到目前为止,根据 Strace,我有 3 个错误:首先,读取函数阻塞了程序,所以我将读取管道的读取 fd 设置为非阻塞 (rpipe[0]
)。然后我在读取函数时遇到了一个 EAGAIN 错误......最后,当我在使用 dup2()
之后的分叉进程中关闭来自 rpipe (close(rpipefd[0])
) 的读取 fd 时,我得到了一个 EPIPE 错误。
我不明白我做错了什么。这是我到目前为止所做的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
int flags = fcntl(rpipefd[0], F_GETFL, 0);
fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],1);
dup2(rpipefd[1],2);
close(wpipefd[1]);
dup2(wpipefd[0],0);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
}
close(wpipefd[0]);
write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
close(rpipefd[1]);
read(rpipefd[0],buffer,BUF_SIZE);
//perror("read()");
printf("%s",buffer);
exit(0);
}
请帮忙!
主要问题并非来自代码本身:传递给 shell 的命令不完整,您错过了最后的 '\n' 以及子进程(您的 shell ) 正在等待命令的其余部分。
非阻塞部分不是一个好主意(或者至少,您应该围绕管道旋转以检索其内容。)
完成命令后,您应该关闭输出管道,以便 shell 在其输入中获取文件结尾。
其他说明:您应该等待子进程终止(使用 wait(2)),您应该在子进程中的 execl 之后离开(使用 with err(3) 来处理错误信息)来处理 exec 错误。而且,说真的,在字符串文字上调用 strlen ?我知道 gcc 会在编译时替换它,但是 …
这是您的代码的修改版本:
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],STDOUT_FILENO);
dup2(rpipefd[1],STDERR_FILENO);
close(wpipefd[1]);
dup2(wpipefd[0],STDIN_FILENO);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
err(1, "execl()");
}
close(wpipefd[0]);
close(rpipefd[1]);
write(wpipefd[1], "echo helloWorld\n", 16);
close(wpipefd[1]); // we're done, say it to the shell
int r;
while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
{
if (r == -1)
{
if (errno == EAGAIN || errno == EINTR) continue;
err(1, "read()");
}
write(STDOUT_FILENO, buffer, r);
}
wait(NULL);
return 0;
}