2016-09-04 5 views
3

私のプログラムは、forkシステムコールとexecシステムコールを使用する必要があります。 execは、別のコマンドを引数として子プロセスを変更し、そのコマンドを 実行する必要があります。 ./myexecv cat etc/motd何も起こらを実行していない後これは私の現在のコードフォークとexecveセグメンテーションフォールト

extern char **environ;  /* environment info */ 
main(int argc, char **argv) { 
    /* argc -- number of arguments */ 
    /* argv -- an array of strings */ 

    char *argvNew[argc + 1]; 
    int pid; 

    for(int i=0; i<argc; i++){ 
     argvNew[i] = argv[i]; 
    } 
    argvNew[argc + 1] = NULL; 
    printf("After For: %s\n",argvNew[0]); 
    printf("After For: %s\n",argvNew[1]); 
    printf("After For: %s\n",argvNew[2]); 
    printf("After For: %s\n",argvNew[3]); 


    if ((pid = fork()) < 0) { 
     fprintf(stderr, "Fork error%sstrerror\n", strerror(errno)); 

     exit(1); 
    } 
    else if (pid == 0) { 
     /* child process */ 
     if (execve(argvNew[0], argvNew, environ) < 0) { 
      fprintf(stderr, "Execve error%d %s\n",errno,strerror(errno)); 
      exit(1); 
     } 
    } 
    else { 
     /* parent */ 
    wait(0);  /* wait for the child to finish */ 
    } 

} 

./myexec cat /etc/motd 

であり、たとえば、その日のメッセージを表示します単にprintステートメントだけです。今後のアドバイスはありますか?

+0

引数リストをコピーする必要はありません。 'execv()'ではなく 'execve()'を使用する正式な命令がない限り、それを使用します。 'execv(argv [1]、&argv [1]);' - フォークなし、コピーなし、待機なし、その他はありません。元のコードのfork/exec/waitレジデンスの唯一の限界的な「利益」は、実行されたコマンドが成功するかどうかにかかわらず、親からの戻りコードが常に0であることです(C99以上のコンパイラを使用すると仮定すると、 mainの終了は 'return 0'と同じですが、' main'は明示的な 'int'戻り値の型を持たなければなりません)。 –

+0

あなたの答えをありがとう。しかし、コマンドを書き込んだ後も何も起こりません。 〜/ Documents $ ./myfork ls -l の後:ls の後:-l の後:(null) の後:(null) Execveのエラー2このようなファイルはありません。ディレクトリ – SolRac

+0

ああ...'execv()'または 'execve()'を使って、実行可能ファイルの絶対名(または現在のディレクトリとの相対的な名前)を指定する必要があります。 './myexec/bin/cat/etc/motd'(もしくは' cat/'がある場合は' ./myexec/usr/bin/cat/etc/motd')を試してみてください。それはうまくいくはずです。シェルのようなPATHベースの 'cat'検索を行うには、' execvp() 'を使うか、コードを見つけて本当に望むなら、[' execvpe() '](http:// stackoverflow。 com/questions/7789750)、あなたは環境を変更しないので、環境設定バリアントの使用にはまったく意味がありません。 –

答えて

2

示されたコードには複数のバグがあります。それの額面で

for(int i=0; i<argc; i++){ 
      argvNew[i] = argv[i]; 
    } 
    argvNew[argc+1] = NULL; 

argvNewは、だから、配列は過去オフ値argvNew[argc]通じargvNew[0]、およびargvNew[argc+1]=NULL;の実行が含まれてい

char *argvNew[argc + 1]; 

として宣言されているため、NULLの割り当てが間違っている、と未定義の動作になります配列の終わりで、結果として未定義の動作をします。これは明らかに

argvNew[argc] = NULL; 

でなければなりません。しかしのでそれさえも、間違って次のようになります。

execve(argvNew[0], argvNew, environ); 

argvNew[0]が実行されて、このプログラムの名前である、argv[0]からコピーされます。これは、子プロセスで同じプログラムをforkして実行します。

あなたは自分をforkbombingなってしまいます。これが共有サーバーの場合は、システム管理者に非常に怒ってしまいます。

式からargv[0]を削除して、argv[1]以降のみをコピーする必要があります。正しいループ、およびコピーは、次のとおりです。

int pid; 
    char *argvNew[argc]; 

    for(int i=1; i<argc; i++){ 
      argvNew[i-1] = argv[i]; 
    } 
    argvNew[argc-1] = NULL; 
+0

コピーの利点は何ですか?なぜexecve(argv [1]、&argv [1]、environ);またはexecv(argv [1]、&argv [1]); –

+0

利点はありません。しかし、これはちょうど[mcve]であり、OPの実際のコードはargvで追加の操作を行うことができます。 –

1

execve()の呼び出しのパラメータは、実行するファイル名であることを最初のパラメータが必要です。残念ながらargvNew[0]にはと同じ値が渡されます。これは、自分のプログラムを呼び出して呼び出し、スクリプトを呼び出さないことを意味します。パラメータを1つずつシフトする必要があります。

... 
for(int i=1; i<argc; i++){ 
    argvNew[i-1] = argv[i]; 
} 
argvNew[argc-1] = NULL; 
... 
+0

コピーのメリットは何ですか?なぜexecve(argv [1]、&argv [1]、environ);またはexecv(argv [1]、&argv [1]); –

+0

@JonathanLeffler優秀な提案! OPがケースを簡略化したと思うのでコピーを保管しておきました。現実には、いくつかのパラメータを追加/変更/削除すると思います。そうでなければ、このプログラムによって追加された価値は何ですか? – Christophe

関連する問題