使用管道分岔过程中的程序崩溃

问题描述:

我正在编写一个基本的shell课程作业,它将在给定的路径列表中找到一个命令,并执行该命令。它也意味着处理管道。 但是,当我fork一个子进程时,在gdb中出现“Write error:Broken Pipe”消息,并且程序突然终止。使用管道分岔过程中的程序崩溃

我似乎无法理解为什么会发生这种情况,因为我一直对打开和关闭正确的管道和流程分叉持谨慎态度,似乎按需要工作。能有更多C和unix编程经验的人能帮我诊断问题吗?我的fork实现/管道实现有没有逻辑上不正确的东西?

//commands is of the format {"ls -al", "more", NULL} 
//it represents commands connected by pipes, ex. ls -al | more 
char **commands = parseArgv(consoleinput, SPECIAL_CHARS[4]); 

int numcommands = 0; 

while(commands[numcommands]!=NULL) 
{ 
    numcommands++; 
} 

const int numpipes = 2*(numcommands-1); 

int pipefds[numpipes]; 

int i=0; 
for(i=0; i<numpipes;i=i+2) 
{ 
    pipe(pipefds+i); 
} 

int pipe_w = 1; 
int pipe_r = pipe_w - 3; 
int curcommand = 0; 

while(curcommand < numcommands) 
{ 
    if(pipe_w < numpipes) 
    { 
     //open write end 
     dup2(pipefds[pipe_w], 1); 
    } 

    if(pipe_r > 0) 
    { 
     //open read end 
     dup2(pipefds[pipe_r], 0); 
    } 

    for(i=0;i<numpipes;i++) //close off all pipes 
    { 
     close(pipefds[i]); 
    } 

    //Parse current command and Arguments into format needed by execv 

    char **argv = parseArgv(commands[curcommand], SPECIAL_CHARS[0]); 

    //findpath() replaces argv[0], i.e. command name by its full path ex. ls by /bin/ls 
    if(findPath(argv) == 0) 
    { 
     int child_pid = fork(); 

     //Program crashes after this point 
     //Reason: /bin/ls: write error, broken pipe 

     if(child_pid < 0) 
     { 
      perror("fork error:"); 
     } 
     else if(child_pid == 0)  //fork success 
     { 
      if(execv(argv[0], argv) == -1) 
      { 
       perror("Bad command or filename:"); 
      } 

     } 
     else 
     { 
      int child_status; 
      child_pid = waitpid(child_pid, &child_status, 0); 
      if(child_pid < 0) 
      { 
       perror("waitpid error:"); 
      } 
     } 
    } 
    else 
    { 
     printf("Bad command or filename"); 
    } 
    free(argv); 

    curcommand++; 
    pipe_w = pipe_w + 2; 
    pipe_r = pipe_r + 2; 
} 

//int i=0; 
for(i=0;i<numpipes;i++) //close off all pipes 
{ 
    close(pipefds[i]); 
} 

free(commands); 
+0

你能构建一个[最小测试用例](http://sscce.org)吗? – 2013-02-10 17:14:18

+1

'pipe_w - 3'?真? – 2013-02-10 17:15:43

+0

在关闭正常标准输入/输出描述符之前复制管道描述符,请检查errors_。你也应该在孩子身上复制它们。 – 2013-02-10 17:17:16

fork()调用后(即在子进程中)复制文件描述符是正确的方法。 此外,waitpid()调用使一个子进程等待另一个子进程,并挂起该shell。 wait()调用应该被移到循环后面,即父母应该等待所有的孩子。