2017-03-28 9 views
1

私のOSシグネチャにcでUNIXミニシェルを作っています。私はシェル自体を改善する必要があります。yaccを実装するための事前作成パーサと、他のファイルの中にlexを実装するためのスキャナがあります。 変更するファイルは、メインの実行可能ファイルであるmsh.cです。minishellで作成されたcが期待通りに動作していない、pipe related

問題はパイプのセキュリティを実装しようとすると始まります。これは私が作ったものです:

int executePipeLine (char*** argvv, int bg, char** filev, int n){ 
    int i; 
    int in = 0; 
    pid_t pid; 
    int fd[2]; 

for (i = 0 ; i < n-1 ; i++){ 

    pipe(fd); 
    pid_t pid = fork(); 


    if (pid == 0){ //child 

     if (in != STDIN_FILENO){ 
      dup2(in, STDIN_FILENO); 
      close(in); 

     } 

     if (fd[1] != STDOUT_FILENO){ 
      dup2(fd[1], STDOUT_FILENO); 
      close(fd[1]); 
     } 

     execvp(argvv[i][0], argvv[0]); 
    } 

    else { //parent 

     close(fd[1]); 
     in = fd[0]; 
    } 


} 

if(in != STDIN_FILENO){ 
    dup2(in, STDIN_FILENO); 
    close(in); 
} 

pid_t lastpid = fork(); 
if(lastpid == 0){ //child 

execvp(argvv[i][0], argvv[0]); 


} 

if(lastpid == -1){ 

    perror("no se pudo crear el hijo\n"); 
    exit(-1); 

} 
else { //parent 

    /* not bg*/ 
    if(!bg) { 
    int status; 
    while (wait(&status) != lastpid); /* wait the child. */ 
    } 

    else { 
    /*bg mode*/ 
     printf("pid del proceso last: %d\n", lastpid); 

    } 

    return 0; 
} 

}//end executePipeLine 

これはうまくいくようです。 mainでは、obtain_order()というextern関数があります。コマンドの数+1を返してretに保存します。 retが1の場合はプロンプトが表示され、0の場合はシェルを終了するためのEOF(Ctrl + Dキーバインディング)を意味し、> 1の場合はコマンドを実行します。ここで

あなたはそれを持っている:

int main(void) 
{ 
    char ***argvv; 
    int command_counter; 
    int num_commands; 
    int args_counter; 
    char *filev[3]; 
    int bg; 
    int ret; 
    int reset = 0; 
    setbuf(stdout, NULL);   /* Unbuffered */ 
    setbuf(stdin, NULL); 

while (1) 
{ 
    fprintf(stderr, "%s", "msh> "); /* Prompt */ 

    ret = obtain_order(&argvv, filev, &bg); 

    printf("ret: %d\n", ret); 
    if (ret == 0) break;  /* EOF */ 
    if (ret == -1) continue; /* Syntax error */ 
    num_commands = ret - 1;  /* Line */ 
    if (num_commands == 0) continue; /* Empty line */ 

    if(num_commands > 1){ 

     executePipeLine(argvv, bg, filev, num_commands); 

    } 
    else if (num_commands == 1){ 
     executeCommand(argvv, bg, filev); 

    } 

} //fin while 

return 0; 

} //end main 

すべてが簡単なコマンドで正常に動作します。問題はパイプラインを実行しようとするときです。それは良い結果を示していますが、私が知っているのは、retが常に次の繰り返しでは0なので、パイプラインを実行しようとするたびに動作しますが、シェルプロセスを閉じて、プロットを続ける。

ここで問題が分かっていますか?

あなたが私を理解してくれることを願っています。私の英語は完璧ではありません。 、子供が死んでいる場合は、あなたのパイプラインが終了、パイプがもはや読める=> STDINが考慮されていない

... 
else { //parent 
    close(fd[1]); 
    in = fd[0]; 
} 

... 

if(in != STDIN_FILENO){ 
    dup2(in, STDIN_FILENO); 
    close(in); 
} 

:ありがとう

答えて

0

は、親プロセス(つまり、あなたのミニシェル)では、あなたはdup標準入力をINGのしています閉じたままにする。後でobtain_orderをメインループに呼び出すと、0(EOF)が返され、プログラムが終了します。

+0

だから、私はdup行を削除する必要があるという意味ですか?代わりに私は何をすべきですか? –

+0

わかりません。その 'dup'が必要な場合、最も簡単な解決策は元のstdinを保存して(' dup'/'dup2'で)復元するようです。また、パイプライン全体をサブシェル(forkedプロセス)で実行することもできます。 – xhienne

+0

ありがとうございました!私はついに子プロセスでピンプラインを実行しました。完璧に働く –

関連する問題