2016-03-20 60 views
1

我想在Linux上編寫一個可以執行單進程命令,雙進程管道和I/O重定向的shell模擬器。 然而,正如我正確執行單個過程一樣,流水線也存在一些問題。在Linux上使用管道和I/O重定向的Shell模擬器

Copy_STDIO();          //Copy the stdio for the restoration. 
Redirection();          //Determine whether should do Redirection. 
Pipeline(); 
Restore_stdio();         //Restore the stdio. 

以上是我的主要功能。首先,我在I/O重定向之後複製STDIO以進行恢復。然後我將我的文件描述符複製到STD_IN和STD_OUT。然後我執行Pipeline,最後我恢復我的STD_IN和STD_OUT。一切都聽起來很完美,但實際上並非如此。我的OUTPUT重定向失敗,這意味着它沒有向目標文件寫入任何內容(即,如果在單個情況下:ls> 123,123不顯示任何內容),當我的程序仍在運行時。但是當我用exit(EXIT_SUCCESS)終止程序時,它出現了!!(如果用ctrl + c,它也會失敗),我不知道爲什麼!

void Redirection() 
{ 
    fd_out = open(filename[0],O_WRONLY | O_TRUNC | O_CREAT,S_IRWXU | S_IRWXG | S_IRWXO); //O_WRONLY and O_CREAT must use at the same time. 
    dup2(fd_out,STD_OUTPUT); 
    close(fd_out); 
} 
void Copy_STDIO() 
{ 
    STDIN_COPY = dup(STD_INPUT);        //Copy for the stdin and stdout 
    STDOUT_COPY = dup(STD_OUTPUT); 
} 
void Pipeline() 
{ 
if(pipeline) 
{ 
    pipe(&fd[0]); 
    childID=fork(); 

    if(childID==0) 
    { 

     if(fork()!=0) 
     { 
      close(fd[1]); 
      dup2(fd[0],STD_INPUT); 
      close(fd[0]); 

      execvp(args2[0],args2); 

     } 
     else 
     { 
      close(fd[0]); 
      dup2(fd[1],STD_OUTPUT); 
      close(fd[1]); 

      execvp(args[0],args); 

     } 

    } 

    usleep(5000);            
} 
} 
void Restore_stdio() 
{ 
    dup2(STDIN_COPY,STD_INPUT);         //Restore the output and input to the stdin and stdout. 
    dup2(STDOUT_COPY,STD_OUTPUT); 
    close(STDIN_COPY); 
    close(STDOUT_COPY); 
} 
+0

你能提供一個最小的可覈查的例子,又名一段代碼可以編譯? –

+0

文件需要被關閉才能看到和閱讀。退出(0);關閉所有打開的文件。 –

+0

@ArifBurhan我應該在哪裏添加exit(0); ?我將它重定向到STD_OUTPUT後關閉了我的fd_out。 –

回答

0

我在自己的倉庫推兩次提交,它們所包含的修復需要

void Pipelining() 
{ 
    int otherID = 0; 
    childID = 0; 
    int childs = 0; 
    int ret = 0; 
    if(pipeline) 
    { 
    pipe(fd); 
    childID=fork(); 

     if (childID < 0) { 
      fprintf(stderr, "error: 1 ... %s\n", strerror(errno)); 
      return; 
     } else if (childID > 0) { 
      ++childs; 
      otherID = fork(); 
      if (otherID < 0) { 
       fprintf(stderr, "error: 2 ... %s\n", strerror(errno)); 
       ret = waitpid(childID, NULL, 0); 
       if (ret < 0) { 
        fprintf(stderr, "error: 3 ... %s\n", strerror(errno)); 
       } 
       return; 
      } else if (otherID > 0) { 
       ++childs; 
      } else { 
      close(fd[0]); 
      ret = dup2(fd[1],STD_OUTPUT); 
       if (ret < 0) { 
        fprintf(stderr, "error: 4 ... %s\n", strerror(errno)); 
       } 
      close(fd[1]); 

      ret = execvp(args[0], args); 
       if (ret < 0) { 
        fprintf(stderr, "error: 5 ... %s\n", strerror(errno)); 
       } 
      } 
     } else { 
      close(fd[1]); 
      ret = dup2(fd[0],STD_INPUT); 
      if (ret < 0) { 
       fprintf(stderr, "error: 6 ... %s\n", strerror(errno)); 
      } 
      close(fd[0]); 

      ret = execvp(args2[0],args2); 
      if (ret < 0) { 
       fprintf(stderr, "error: 7 ... %s\n", strerror(errno)); 
      } 
     } 
     /* now it is safe to close pipe */ 
     close(fd[0]); 
     close(fd[1]); 
     /* wait children */ 
     ret = waitpid(childID, NULL, 0); 
     if (ret < 0) { 
      if (errno != ECHILD) 
       fprintf(stderr, "error: 8 ... %s\n", strerror(errno)); 
     } 
     ret = waitpid(otherID, NULL, 0); 
     if (ret < 0) { 
      if (errno != ECHILD) 
       fprintf(stderr, "error: 9 ... %s\n", strerror(errno)); 
     } 
    } 
} 

我做了以下修改:

  1. 現在兩個孩子都從相同的頂部形成-parent
  2. 現在頂級父級關閉了他的管道文件描述符副本
  3. now頂部父母正確地等待它的孩子
  4. 補充急需的狀態檢查
+0

謝謝!這對我很有幫助! –

+0

不客氣。 –

+0

我在我的代碼中發現了我的錯誤。我把我的管子()放在錯誤的地方。它應該在第二個fork()之前的第一個fork()之後調用,而不是在第一個fork()hahaha之前調用!我也想出了我的waitpid()問題。不管怎樣,謝謝! –