grep зависает при выполнении функции execvp в моей программе C - PullRequest
2 голосов
/ 22 января 2020

Я написал bash как Linux оболочку в C.

(Ссылка на мой репозиторий: https://github.com/oneiro-naut/wish. Файл src/execute.c имеет файл execute_pipeline функция в нем)

У меня проблема с реализацией встроенных команд, которые производят некоторый вывод. Встроенные функции, которые не выдают никаких результатов, например cd и exit, работают просто отлично. Внешние команды работают без сбоев. В Shell есть поддержка конвейерных конструкций и перенаправление ввода / вывода. Проблема в том, что я пытаюсь запустить внутреннюю команду (которая просто печатает сообщение). Когда я перенаправляю вывод встроенной команды в команду grep, используя канал, дочерний процесс grep зависает, что, как мне кажется, происходит, потому что grep никогда не встречает конец потока (или EOF) при чтении из канала.

ПРИМЕЧАНИЕ. не происходит, когда в конвейере есть только внешние команды. (Я позаботился о том, чтобы ни одна (внешняя) команда не завершилась до того, как следующая команда еще не запущена, поэтому она там не зависает)

Вот упрощенная версия моей проблемы `

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

int main()
{

int pipe_fd[2] = {-1,-1};
int EXIT_STAT = 0;

pipe(pipe_fd);//creating pipe


char* argv[]={"grep","Radiohead",NULL};

int std_out_dup = dup(1);
dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
//close(pipe_fd[0]);//closing parent pipe's write end 

printf("Alice in Chains\n");
printf("Radiohead\n");
printf("Dinosaur Jr.\n");
printf("Pixies\n");
printf("Soundgarden\n");
printf("Porcupine Tree\n");
printf("Pain of Salvation\n");


pid_t pid = fork();
if(pid == 0)//child process
{
dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
close(pipe_fd[1]);
execvp(argv[0],argv);//executing grep command
perror("\n");
exit(-1);
}


else if(pid > 0)//parent process
{

    int i;//closing pipes for parent
    for(i=0;i<2;i++)
        close(pipe_fd[i]);

    do{ // waiting for grep to exit
        waitpid(pid,&EXIT_STAT,WUNTRACED);
        //write(,"\x4",1);
    }while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
}
else ;//fork error

dup2(std_out_dup,1); // restore stdout fd for parent process



return 0;

}

`
Программа зависает, если я пытаюсь запустить ее, ничего не печатая. Но нажатие ^ D завершает программу, производящую вывод:

Alice in Chains Radiohead Dinosaur Jr. Pixies Soundgarden Porcupine Tree Pain of Salvation

Так что кажется, что grep не может читать бесконечно, потому что не получает никакого сигнала EOF. Пожалуйста, укажите мои ошибки, я действительно запутался.

РЕДАКТИРОВАТЬ: Теперь даже нажатие ^ D не прекращается, поэтому мне нужно просто ^ C программы.

ПРОГРАММА ПОСЛЕ ИСПРАВЛЕНИЯ:

int main()
{

    int pipe_fd[2] = {-1,-1};
    int EXIT_STAT = 0;

    pipe(pipe_fd);//creating pipe


    char* argv[]={"grep","Radiohead",NULL};

    int std_out_dup = dup(1);
    //printf("%d \n",std_out_dup);
    dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
    //close(pipe_fd[0]);//closing parent pipe's write end 

    printf("Alice in Chains\n");
    printf("Radiohead\n");
    printf("Dinosaur Jr.\n");
    printf("Pixies\n");
    printf("Soundgarden\n");
    printf("Porcupine Tree\n");
    printf("Pain of Salvation\n");
    fflush(stdout);

    pid_t pid = fork();
    if(pid == 0)//child process
    {
    close(pipe_fd[1]);
    dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
    dup2(std_out_dup,1); // restore stdout fd for parent process
    execvp(argv[0],argv);//executing grep command
    perror("\n");
    exit(-1);
    }


    else if(pid > 0)//parent process
    {

        int i;//closing pipes for parent

        for(i=0;i<2;i++)
           close(pipe_fd[i]);

        dup2(std_out_dup,1); // restore stdout fd for parent process

        do{ // waiting for grep to exit
            waitpid(pid,&EXIT_STAT,WUNTRACED);
        }while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
      }
          else ;//fork error



       return 0;
    }

1 Ответ

1 голос
/ 22 января 2020

Вы должны

1. восстановить stdout у ребенка; в противном случае дочерний процесс grep запишет в конец записи канала, который является его стандартным.

Добавьте dup2(std_out_dup,1) сразу после if(pid == 0)//child process ... {

2. добавить fflush(stdout) после всех этих .... printf("Pain of Salvation\n"); printfs; в противном случае поток будет очищен дважды.

3. закройте все концы записи канала как в родительском, так и в дочернем элементах; добавьте dup2(std_out_dup,1) или close(1) перед wait l oop в родительском элементе.

...