O «sh» sendo lançado com execl () se torna um zumbi

3

Eu gasto meio dia inteiro, mas ainda não consegui descobrir, por que o traço que está sendo lançado com execl só se torna um zumbi.

Abaixo está um caso de teste mínimo - eu apenas bifurco um filho, faço uma cópia dos descritores std [in, out, err] e inicio o 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");
}

Quando eu o inicio em um depurador, e na linha com o ponto de interrupção (acima da chamada puts() ) , veja a variável pid , e então veja o acordo processo com ps, eu cada vez recebendo algo como

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

Ou seja. é um zumbi

    
por Hi-Angel 15.04.2015 / 17:34

2 respostas

7

Você está deixando um zumbi, de forma trivial, porque não usou wait no seu processo filho.

Seu shell está saindo imediatamente porque você configurou seu STDIN de maneira absurda. pipe retorna um canal de comunicação unidirecional. Você write to pipefd[1] e read de pipefd[0] . Você fez um buch de dup2 chamadas que levam o shell a tentar ler (STDIN) a partir da extremidade de gravação do pipe.

Depois de trocar os números em seu enum, você obtém o shell para sempre em read . Isso provavelmente não é o que você quer, mas é tudo o que você pode esperar quando você tem um shell canalizado para si mesmo.

Supondo que você esteja tentando usar o shell a partir do seu processo pai, você precisa chamar pipe duas vezes (e ambos no pai): um dos pipes que você escreve (e o shell lê, no stdin) e o outro o shell escreve para (stdout / stderr) e você lê. Ou se você quiser, use socketpair .

    
por 15.04.2015 / 18:15
2

Você precisa capturar o sinal SIGCHLD e "colher" o processo zumbi com uma chamada de sistema wait() . A adição quase mínima de código ao seu programa para adicionar uma função de manipulador de sinal e configurá-lo como o manipulador SIGCHLD se parece com isso:

#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

void sighandler(int signal_number);

void sighandler(int signo) {
    if (signo == SIGCHLD) {
            int status;
            (void)wait(&status);
    }
}


int main() {
    int pipefd[2];
    enum {
        STDOUT_TERM = 0,
        STDIN_TERM  = 1
    };
    signal(SIGCHLD, sighandler);
    pid_t pid = fork();

Você quase certamente deve verificar o status de retorno da chamada do sistema signal() , e olhar para lidar com o status de saída da criança (o valor de status no código do manipulador de sinal.

    
por 15.04.2015 / 18:14

Tags