2013-02-10 59 views
0

我正在編寫一個基本的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

回答

0

fork()調用後(即在子進程中)複製文件描述符是正確的方法。 此外,waitpid()調用使一個子進程等待另一個子進程,並掛起該shell。 wait()調用應該被移到循環後面,即父母應該等待所有的孩子。