shell – 用execl()启动的«sh»变成了一个僵尸

我花了整整半天,但仍然无法想象,为什么用execl调用启动的破折号就变成了僵尸.

下面是一个最小的测试用例 – 我只是分叉一个孩子,复制std [in,out,err]描述符,并启动sh.

#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>

int main() {
    int pipefd[2];
    enum {
        STDOUT_TERM = 0,
        STDIN_TERM  = 1
    };
    if (pipe(pipefd) == -1) { //make a pipe
        perror("pipe");
        return 0;
    }
    pid_t pid = fork();
    if (pid == 0)
    {// Child
        dup2(pipefd[STDIN_TERM], STDIN_FILENO);
        dup2(pipefd[STDOUT_TERM], STDOUT_FILENO);
        dup2(pipefd[STDOUT_TERM], STDERR_FILENO);
        execl("/bin/sh","sh", (char*)NULL);
        // Nothing below this line should be executed by child process. If so, print err
        perror("For creating a shell process");
        exit(1);
    }
    __asm("int3");
    puts("Child launched");
}

当我在调试器中启动它,并在带断点的行(在puts()调用之上)查看pid变量,然后用ps查看相应的进程,我每次都得到类似的东西

2794 pts/10   00:00:00 sh <defunct>

即它是一个僵尸

最佳答案
你正在离开一个僵尸,琐碎,因为你没有等待你的孩子过程.

你的shell会立即退出,因为你以荒谬的方式设置了它的STDIN.管道返回单向通信通道.你写入pipefd [1]并从pipefd [0]读回来.你做了一些dup2调用,导致shell尝试从管道的写端读取(STDIN).

一旦你在你的枚举中交换数字,你就可以永久地读取shell.这可能不是你想要的,但是当你有一个用自己的管道传输时它就是你所能想到的.

假设您正在尝试使用父进程中的shell,您需要调用管道两次(并且都在父进程中):您写入的一个管道(并且shell在stdin上读取)而另一个是shell写入(stdout / stderr)并从中读取.或者,如果需要,请使用socketpair.

转载注明原文:shell – 用execl()启动的«sh»变成了一个僵尸 - 代码日志