C. Дочерний процесс. readline

Я пишу собственную shell. Вот main:

void    signal_handler(int signo)
{
    if (signo == SIGINT)
    {
        ft_putstr_fd("\n", 1);
        rl_on_new_line();
        rl_replace_line("", 1);
        rl_redisplay();
    }
}

int main(int argc, char **argv, char **envp)
{
    (void)  argc;
    (void)  argv;
    char    *line;
    t_main  main;

    main.envp = array_2d_dup(envp);
    main.exit_status = 0;
    signal(SIGINT, signal_handler);
    while (1)
    {
        line = readline("minishell -> ");
        if (line == NULL)
            exit(0);
        if (*line == '\0')
            continue ;
        add_history(line);
        if (parser(&line, &main) != -1)
        {
            execute(&main);
            waitpid(*(main.pid), &main.exit_status, 0);
        }
        else
            exit(1);
    }
    exit(1);
}

Функция парсер разбивает строку до нужного вида учитывая спец символы, она не интересна в данном вопросе.

Вот эта функция создает поток и запускает распарсенную команду из полученной строки:

void    execute(t_main *main)
{
    char    *file_path;
    char    **command;
    pid_t   pid;

    pid = fork();
    if (pid != 0)
        *(main->pid) = pid;
    if (pid == 0)
    {
        command = parse_command(main->gap->arg, main->gap->comm);//подготовка к 
        file_path = parse_filename(main->gap->comm, main->envp);//передаче в execve()
        main -> exit_status = EXIT_SUCCESS;
        execve(file_path, command, main->envp);
        perror(main->gap->comm);
        main -> exit_status = EXIT_FAILURE;
        exit(EXIT_FAILURE);
    }
}

Что-то в коде может показаться лишним действием, но я удалил много функционала для сужения круга потенциальных ошибок. В итоге вот что происходит по нажатию ctr-c:

admin@Daniils-MacBook-Pro minishell % ./minishell
minishell -> ^C
minishell -> ^C
minishell -> ^C
minishell -> ^C
minishell -> 

Но запустив команду cat и нажав ctr-c моя программа 2 раза печатает "Minishell -> ":

minishell -> ^C
minishell -> ^C
minishell -> ^C
minishell -> ^C
minishell -> cat
ekrmflker^C
minishell -> minishell -> 

Я предполагаю, что это из-за использования процессов вместе с перехватом сигнала. У меня не получается это исправить, любая информация будет полезна. Спасибо!


Ответы (1 шт):

Автор решения: Cleonia

В итоге я сам нашел решение, вот так я изменил некоторые строки в execute():

pid = fork();
if (pid != 0)
    signal(SIGINT, empty_signal_handler); //пустая функция

Не до конца понимаю почему это работает, но видимо при получении сигнала ctr-C родительский процесс выполнял обработчик и снова ждал завершение дочернего процесса. Соответственно в том случае если дочерний процесс это копия "minishell"(minishell -> ./minishell), то оба процесса выполняли обработчик и печатали "minishell -> ". Если дочерним процессом был, к примеру, "cat", то по ctr-C он завершался, а родитель выполнял и обработчик, и заходил на следующий виток цикла (while в main()), соответственно так же "minishell -> " печатался 2 раза. Еще раз оговорюсь, что я протестировал код множественными кейсами и он делает то что мне нужно, но не до конца понимаю почему это работает. Если вы зашли на эту страницу и знаете больше чем я, пожалуйста, напишите ответ. Описание функций из обработчика сигналов оставлю в комментариях.

→ Ссылка