C 分叉进程的子进程中的std in/out/err重定向

C 分叉进程的子进程中的std in/out/err重定向,c,bash,io-redirection,fork,C,Bash,Io Redirection,Fork,我正在用C编写一个基本的反向shell: if(-1 == (myShell->pid = fork())) { PipeSet_close(&myShell->pipeSet); return RS_ERROR; } if(myShell->pid == 0) { /* close pipe ends child doesn't need */ close(myShell->pipeSet.stdInPipe[1]);

我正在用C编写一个基本的反向shell:

if(-1 ==  (myShell->pid = fork()))
{
    PipeSet_close(&myShell->pipeSet);
    return RS_ERROR;
}

if(myShell->pid == 0)
{
    /* close pipe ends child doesn't need */
    close(myShell->pipeSet.stdInPipe[1]);
    close(myShell->pipeSet.stdOutPipe[0]);
    close(myShell->pipeSet.stdErrPipe[0]);

    /* dupe 2 the pipes we DO need frm their originals */
    dup2(myShell->pipeSet.stdInPipe[0], fileno(stdin));
    dup2(myShell->pipeSet.stdOutPipe[1],fileno(stdout));
    dup2(myShell->pipeSet.stdErrPipe[1],fileno(stderr));

    /* bash now replaces child process. only returns after bash terminates */
    execl(getenv("SHELL"),NULL,NULL);
    return RS_SUCCESS;
}
我可以使用我的父进程从我的3个管道读写。这允许我通过子对象执行基本的shell命令。ls-l、ps、chmod+x等等。我遇到的问题是当我使用shell运行一个需要用户输入的简单程序时。我使用以下程序对此进行测试:

int main()
{
int opt;
while (1==1)
{
    printf("-----Remote Shell Menu test:------\n");
    printf("   1. print 1\n");
    printf("   2. print 2\n");
    printf("   3. exit\n");
    fflush(stdin);
    scanf("%d",&opt);

    switch (opt)
    {
    case 1: printf("Pressed 1\n"); break;
    case 2: printf("Pressed 2\n"); break;
    case 3: return 0;
    default: printf("unknown menu option %d\n",opt);
    }
}
}
我可以像平常一样通过反向shell与这个子程序进行交互,然后按“1”“2”“1”“3”,但在整个菜单程序终止并按3之前,我无法通过标准输出管道获取菜单或看到任何输出。有人能告诉我这是为什么吗


如果从我的分叉bash中生成另一个bash shell,情况就不是这样了…

您有
fflush(stdin)
,它什么都不做。fflush只在输出流上使用。我相信如果您将其更改为
fflush(stdout)
,它将解决您的缓冲问题。

您还应
dup2
之后关闭复制的管道,以便进程有机会检测EOF

您可以在
execl
之后添加
peror
;最好使用
execlp
;给出
argv[0]
而不是
NULL
。 如果
getenv(“SHELL”)
NULL
,会发生什么?您确定它是
bash


基本上,
返回
某物;在
中测试
1==1
是无用的,而
中的
和(;;)
while(1)
通常可以获得无限循环

这是因为缓冲。如果stdout是tty,则子级最有可能输出行缓冲区,但如果stdout是管道,则会阻止缓冲区。这与您的问题不完全相关,但
execl()
如果成功就不会返回。如果由于任何原因失败,它确实会返回,但随后您会返回
RS\u SUCCESS
,这可能会掩盖将来的某些事情。。。