2017-03-01 3 views
0

私はUnixコマンドを受け取り、不正なアドレスエラーを受け続けるシェル "bosh>"を作ろうとしています。私は自分のコードがコマンドを読み込んで構文解析することを知っていますが、何らかの理由でそれらを実行させることができず、代わりに「不良アドレス」エラーが発生します。execvpでアドレスが正しくありません

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <string.h> 
#include <sys/wait.h> 
#define MAX_LINE 128 
#define MAX_ARGS 10 



int main(){ 
    pid_t pid; 
    char command[MAX_LINE]; /*command line buffer*/ 
    char *commandArgs[MAX_ARGS]; /*command line arg*/ 
    int i; 
    char *sPtr=strtok(command," "); 
    int n=0; 


    printf("bosh>"); 
    fgets(command, MAX_LINE-1,stdin); 
    command[strlen(command)-1]='\0'; 


    while(strcmp(command,"quit")!=0) 
    { 
     n=0; 

     sPtr=strtok(command," "); 
     while(sPtr&&n<MAX_ARGS) 
     { 
      sPtr=strtok(NULL," "); 
      n++; 
     } 

     commandArgs[0]=malloc(strlen(command)+1); 
     strcpy(commandArgs[0],command); 

     if(fork()==0) 
     { 
      execvp(commandArgs[0],commandArgs); 
      perror("execvp failed"); 
      exit(2); 
     } 
     pid=wait(NULL); 


     printf("%s",">"); 
     fgets(command, MAX_LINE-1,stdin); 
     command[strlen(command)-1]='\0'; 
    } 

    printf("Command (%d) done\n", pid); 

    return 0; 


} 
+0

まず、美しい犬の絵です。 'fgets'によって読み込まれたバッファの最後の文字の後ろに終端のヌルバイト( '\ 0')が格納されます。だから、 ''\ 0' 'を入れる必要はありません。 –

+0

@TonyTannousそれは改行を取り除くことです...(それも間違っていますが)。 –

+0

最後の文字が実際には '' \ n ''であることを確認してから、それを切り捨てることを確認したいでしょう。 –

答えて

3

この2行が犯人です:すべての

commandArgs[0]=malloc(strlen(command)+1); 
strcpy(commandArgs[0],command); 

まず、strcpy続いmalloc(strlen(...))はPOSIX機能strdupはすでに何をするかです。

commandArgs[0] = command; 

しかし、その後、どのようにexecvpコマンドがしようとしているんどのように多くの引数:ちょうどcommandArgs[0]に元の文字列へのポインタを格納するのに十分である - しかし、その後、あなたも、文字列をコピーする必要はありません取る?

execv()execvp()、およびexecvpe()の機能は、新しいプログラムに利用できる引数リストを表すNULLで終わる文字列へのポインタの配列を提供します。あなたは慎重にマニュアルを読めば、彼らが何かのように言うだろう。規則の第1引数は、実行中のファイルに関連付けられたファイル名を指す必要があります。 ポインタの配列 MUST は、NULLポインタで終了する必要があります。

引数の配列はNULLで終了しません。それを修正するには、

commandArgs[0] = command; 
commandArgs[1] = NULL; // !!!! 

を使用します(その後、あなたが実際にあなたが実際にすべての引数を割り当てることができるように、内の引数にstrtok解析ループをを割り当てるだろうということに気づくだろうcommandArgsアレイ、およびすべての警告が有効な状態でコンパイルし、それらに対処するなど)。

1

sPtrを宣言で初期化します。これは、決して初期値を使用しないため、行う必要はありません。ただし、初期化では定義されていない動作が発生します。これは、配列が不確定なcommand配列の内容に依存するためです。

execvp()の2番目の引数として渡された配列は、最後の引数の後にNULLポインタを含むと予想されます。あなたはあなたのことを保証しません。

さらに、トークンをcommandArgs[]に割り当てないと、入力コマンドにすべての引数をドロップしているように見えます。トークン化の後、最初のトークン(コピーのみ)をコピーしてcommandArgsの最初の要素にコピーを割り当てますが、それ以外のトークンは無視されます。

+0

私はコメントでそれを指摘しました。引数の初期化に問題があります。おそらく最初の引数だけが割り当てられ、最後の引数の後にNULLはありません。 +1 –

関連する問題