私の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);
}
:ありがとう
だから、私はdup行を削除する必要があるという意味ですか?代わりに私は何をすべきですか? –
わかりません。その 'dup'が必要な場合、最も簡単な解決策は元のstdinを保存して(' dup'/'dup2'で)復元するようです。また、パイプライン全体をサブシェル(forkedプロセス)で実行することもできます。 – xhienne
ありがとうございました!私はついに子プロセスでピンプラインを実行しました。完璧に働く –