2011-01-30 10 views
4

主に配管を行うシェルを実装しようとしています。私はこのテストケースを書いていますが、私は単にlsをwcにパイプすることを期待しています...それは間違いなく期待どおりに動作しません。 lsを端末に出力し、メモリを使い果たします。 これを修正して動作させる方法がとても失われています。 find_pathはすべてのテストで動作します。C Unix Pipes例

編集 - 私はプロジェクトのためにexecvを使う必要があります。そのクラスのことですが、私はexecvpで試してみました。まったく同じことをします。これは単なる例であり、なぜ動作しないのかを調べるためのテストです。私はコマンドとwaitpidの両方に対してforkを2回呼びます。何もする必要がないからです。

#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 
int find_path(char* execname, char** dst) 
{   
     char *path = getenv("PATH"); 
     path = strdup(path); 
     char *pos; 
     path = strtok_r(path, ":", &pos); 
     char *originalpath = path; 
     do 
     { 
       char* test = (char*)calloc(strlen(path) + strlen(execname) + 2, sizeof(char)); 
       test = strcpy(test, path); 
       int testlen = strlen(test); 
       (*(test+testlen)) = '/'; 
       strcpy(test + testlen + 1,execname); 
       struct stat buf; 
       int result = stat(test, &buf); 
       if (result == 0) 
       { 
         *dst = test; 
         free (originalpath); 
         return 1; 
       } 
       else 
       { 
         free(test); 
       } 

     } while ((path = strtok_r(NULL, ":", &pos)) != NULL); 
     free(originalpath); 
     return 0; 
} 

int main() 
{ 
    char *cmd1 = "ls"; 
    char *cmd2 = "wc"; 
    int filedes[2]; 
    pipe(filedes); 
    char** argv = (char**)calloc(1, sizeof(char*)); 
    argv[0] = (char*)malloc(sizeof(char*)); 
    argv[0] = NULL; 

    pid_t pid = fork(); 
    if (pid == 0) 
    { 
     char *path; 
       find_path(cmd1, &path); 
     dup2(filedes[1],stdout); 

     execv(path,argv); 
    } 
    pid = fork(); 
    if (pid == 0) 
    { 
     dup2(filedes[0], stdin); 
     char *path; 
     find_path(cmd2, &path); 
     execv(path, argv); 

    } 
    else 
     waitpid(pid); 

} 
+0

を(タイプFILE*である)の値stdoutstdinを混乱されたあなたは、昨年のラッシュを見てきました"fork ... pipe ... exec ..."という質問でシェルを実装するには?その答えはおそらくそれらのうちの1つ(より多くの可能性が高い)にあります。 –

答えて

8

多くの場合、プログラムをデバッグするのが難しい場合は、エラーの原因を取り除くためにプログラムを少し簡略化することをお勧めします。ここでは、あなたのプログラムは、エラーの原因としてfind_pathを取り除くために簡略化され、次のとおりです。

#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 

int main(void) 
{ 
    int filedes[2]; 
    pipe(filedes); 

    /* Run LS. */ 
    pid_t pid = fork(); 
    if (pid == 0) { 
     /* Set stdout to the input side of the pipe, and run 'ls'. */ 
     dup2(filedes[1], 1); 
     char *argv[] = {"ls", NULL}; 
     execv("/bin/ls", argv); 
    } else { 
     /* Close the input side of the pipe, to prevent it staying open. */ 
     close(filedes[1]); 
    } 

    /* Run WC. */ 
    pid = fork(); 
    if (pid == 0) { 
     dup2(filedes[0], 0); 
     char *argv[] = {"wc", NULL}; 
     execv("/usr/bin/wc", argv); 
    } 

    /* Wait for WC to finish. */ 
    waitpid(pid); 
} 

あなたが期待するように、これは振る舞うべきです。簡素化の際

は、いくつかのエラーが出てきた:

  • argv[]は正しく、特に、ARGV [0]がNULLに設定されていたセットアップされていませんでした。
  • プログラムは、lsに与えられていたパイプの入力側を閉じていませんでした。 lsが終了すると、パイプは閉じていませんでした(wcプロセスがまだ開いていたため)wcの処理が終了しませんでした。
  • プログラムは(duppipeなどで使用される)ファイルディスクリプタ番号01
+0

すごい、あなたは私のばかな間違いのすべてを持っています。私のテストでは、あなたが提案したすべてのものを試しましたが、実行可能な名前でなければならない最初のコマンドライン引数が完全に忘れていました!本当にありがとう。 – Ben

1

たあなたが、)がありますが、このコードを改善するために行うことができ、多く(例えば小さな機能にこれを破ることは、スタートになりますが)ですが、私は、メモリの問題のあなたのうちは(find_path内のコードからある疑いexecvpを使って完全に回避することができます。これは、標準のPATHメカニズムを使って実行可能ファイルを探し出します。 sigactionを使ってシグナルハンドラをインストールして、SIGCHLDを処理し、シグナルハンドラからwaitpidを呼び出すことをお勧めします。あなたのやり方と同じようにwaitpid()ad-hocを呼び出すのではなく、あなたはあなたが望むよりも多くの時間をフォークしているように見え、あなたはエラーをチェックしていません。これらの提案が役立つことを願っています。

+0

私はfind_pathを使う理由を説明するために私の投稿を編集しましたが、execvpは同じことを行い、待つことは最良の方法ではないかもしれませんが、ここで問題の例を作成しています。 – Ben

関連する問題