在子进程中调用dup2导致父进程stdin关闭

时间:2018-05-30 23:07:16

标签: c file pipe fork stdin

我正在尝试使用forkdup2pipe在C中编写支持多个管道的自定义shell。我的方法是c1 | c2 | c3,创建一个2 x 2矩阵来存储两个管道,顺序分叉三个子进程,调用dup2复制stdinstdout到正确的管道然后拨打exec

shell适用于以下命令:"echo foo""ls | grep something | wc"。但由于某些原因,当我执行一行只包含一个管道(例如"ls | grep something")时,shell会按预期执行此命令,但退出时无需等待读取更多行。我花了好几个小时试图找出它存在的原因,当给出一条管道用一根管子但是用不止一根管子工作但是没有运气。

以下是创建子进程并运行命令的代码:

int main()
{
    char input_line[1000];
    size_t size;
    size_t chars;

    while(fgets(input_line, sizeof(input_line), stdin))
    {
        input_line[strcspn(input_line, "\n")] = 0;
        struct PARSE_INFO* parse_info = initialize_parseInfo();
        Parse(input_line, parse_info);
        int num_commands = parse_info->num_commands;
        int num_pipes = parse_info->num_pipes;
        int pipes[num_pipes][2];
        bool piping = num_pipes > 0;

        // Piping the pipes
        for(int i = 0; i < num_pipes; i++)
            pipe(pipes[i]);

        int i;
        for(i = 0; i < num_commands; i++)
        {
            struct COMMAND* command = (parse_info->commands)[i];
            int num_args = command->argnum;

            char* newargv[num_args + 2];
            create_argv(command, newargv, "/usr/bin");  

            int pid = fork();

            if(pid == 0) // Child
            {
                char* newenviron[] = { NULL };       

                if(piping)
                {
                    if(i < num_commands - 1) // Not at end of pipe so write to next pipe
                    {
                        dup2(pipes[i][1], STDOUT_FILENO);
                    }
                    if(i > 0)                       // Not at beginning of pipe so read from previous pipe
                    {
                        dup2(pipes[i - 1][0], STDIN_FILENO);
                        close(pipes[i -1][0]);
                    }
                }
                execve(newargv[0], newargv, newenviron);
                perror("execve");
            }
            else  // Parent
            {
                int status = 0;
                wait(&status);
                close(pipes[i][1]);
            }
        }
    }
}

我独立测试了这里调用的函数,它们似乎工作正常,所以我选择不包含它们来减少混乱。我怀疑我没有正确关闭管道。令我困惑的是,如果我理解正确的话,在子进程中调用dup2应该只修改该进程中的文件描述符而不影响父进程,我不确定它为什么会导致stdin在父进程中关闭。

在我的调试过程中,我尝试在while循环结束时从stdin读取一些输入,方法是在else块之后添加此代码:

char someinput[256];
fgets(someinput, sizeof(someinput), stdin);
printf("End of loop input: %s\n");

程序仍然终止,并且没有等待读取任何输入。我尝试打印someinput,它包含从第一次调用fgets开始循环开始时从stdin输入的命令。任何帮助将非常感激!

0 个答案:

没有答案