2

ls、などのシステムコマンドを受け取りdate、このコマンド(ファイル)を含むパスがあるかどうかを確認するプログラムを作成する必要があります。commandandparameters最後のループで変化し始める変数がありますが、そのwhile理由はわかりません。

puts(commandandparameters);あなたがそれを実行したいのであれば、私は出力が良くないことを示すために置きました。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
    char *arr[5];//for the command and his parameter
    char command[10];
    int i,j;
    char *path=NULL,*tempath,*finalpath,*commandandparameters;
    do
    {
        i=0;
        printf("enter new command:");
        gets(command);
        arr[i]=strtok(command," ");
        while(arr[i]!=NULL)//save the command and also the parametrs
        {
            i++;
            arr[i]=strtok(NULL," ");
        }
        strcpy(commandandparameters,arr[0]);//add first command
        for(j=1;j<i;j++)//add the parameters
            {
                strcat(commandandparameters," ");
                strcat(commandandparameters,arr[j]);
            }
        //now we check if the command in every path
        path = getenv("PATH");
        tempath = strtok(path,":");
        while (tempath != NULL)
        {
            strcpy(finalpath,tempath);//get the current path
            puts(commandandparameters);
            strcat(finalpath,"/");//we add '/'
            execl(finalpath,commandandparameters,NULL);
            tempath = strtok(NULL, ":");//get next path
        }
    }while(command!="leave");
}
4

2 に答える 2

4

次を指すスペースを定義していませんcommandandparameters:

char *path=NULL,*tempath,*finalpath,*commandandparameters;
...
    strcpy(commandandparameters,arr[0]);

ランダム空間を指すポインターがあります。そのランダムなスペースにコピーします。面白い結果が得られます。運が良ければ、プログラムはクラッシュします。運が悪いと挙動がおかしくなります。

同様の問題がありfinalpathます:

    path = getenv("PATH");
    tempath = strtok(path,":");
    while (tempath != NULL)
    {
        strcpy(finalpath,tempath);

さらに悪いことに、あなたはあなたの環境を解体しています。によって返される文字列はgetenv()、PATH の値を変更するつもりがない限り、読み取り専用として扱う必要があります。:そのままでは、ループ後に多くの PATH が残っていません (最初の要素が の場合は PATH はありません)。

すべてのポインターが指している場所を確認してください。

あなたのコードには、非常に多くの潜在的なバッファ オーバーフローがあり、身の毛がよだつほどです。使用しないでくださいgets()。それがあなたのコンピューターを粉々に吹き飛ばすと仮定してください。


これらの問題を解決すると、do { ... } while (command != "leave");ループは無限ループに等しいものになります。そのように文字列を有効に比較することはできません。を使用する必要がありますstrcmp()


簡単なプログラムを実行しようとしましたが、うまくいかないことがわかりましたexecl()。「ls」コマンドが機能しない理由を誰か教えてもらえますか?

これは、コメントからのコードのわずかに変更されたバージョンです。印刷に 2 つのヘッダーと改行を追加しましたが、重要な変更execl()は行にあります。オリジナルはコメントにあります。作業バージョンはコメントではありません。それがあなたの主な問題なのか、コメントのタイプミスなのか、私には判断できません。修正されたコードはコンパイルおよび実行されます。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int pid, stat;

    if ((pid = fork()) == 0)
    {
        execl("/bin/ls", "ls", NULL);
        //execl("/bin/", "ls", NULL);
        printf("1\n");
        exit(1);
    }
    else
    {
        wait(&stat);
        printf("2\n");
    }
}

あなたのプログラムのコードは PATH を破壊します。最初のプログラムの実行に失敗すると、その後は元の PATH の最初のディレクトリのみが検索されます。execl()可変数の引数を処理するために使用しようとしています。これは仕事には不適切なツールです。execv()またはその親戚の1つを使用する必要があります(execvp()たとえば、PATHを台無しにすることなくPATH検索を行います)。その理由はexecl()、null ポインターで終了する引数のセットが必要なためですが、引数の数がわかっている場合にのみ記述できます。あなたは書くことができます:

execl("/bin/ls", "ls", "-l", (char *)0);

ただし、すべてのコマンドに最大 4 つの引数 (与えられたchar *arr[5];) を強制し、次のようなテンプレートを使用しない限り:

execl(finalpath, arr[0], arr[1], arr[2], arr[3], arr[4]);

execl()コマンドの実行には使用できません。しかし、それはユーザーを最大で N 個の引数に制限します。これは受け入れられません。(たとえば、 をシェル展開*すると、30 個以上の引数のリストが生成される場合があります。

また、コードはコマンド名をパス コンポーネントに追加しませんでした。の最初の引数execl()は、プログラム実行可能ファイルのパスです。

したがって、execv()(またはexecvp()またはexecve()または、もしあればexecvpe())を使用してください。これは、実行するコマンドが見つかった場合に問題なく動作するプログラムの多かれ少なかれ最小限の変更です。そうでない場合は、軽微な災害です。これはワンショット シェルです。パスを変更する前にフォークした場合、パスの変更はそれほど重要ではありませんが、実行されるプロセスには最小限のパスが存在しませfork()ん。execv()

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    char *arr[5];//for the command and his parameter
    char command[100];  // Not 10
    int i;
    int j;
    char *path=NULL;
    char *tempath;
    char finalpath[200];
    char commandandparameters[200];

    do
    {
        i = 0;
        printf("enter new command: ");
        if (fgets(command, sizeof(command), stdin) == 0)
        {
            fprintf(stderr, "EOF or error\n");
            break;
        }
        arr[i]=strtok(command, " ");
        while (i < (5-1) && arr[i]!=NULL)//save the command and also the parameters
        {
            printf("arr[%d] = %s\n", i, arr[i]);
            i++;
            arr[i]=strtok(NULL, " \n");
        }
        arr[4] = 0;

        strcpy(commandandparameters, arr[0]);//add first command
        for (j=1;j<i;j++)//add the parameters
            {
                strcat(commandandparameters, " ");
                strcat(commandandparameters, arr[j]);
            }
        printf("Cmd&Params: %s\n", commandandparameters);

        //now we check if the command in every path
        path = getenv("PATH");
        tempath = strtok(path, ":");
        while (tempath != NULL)
        {
            puts(commandandparameters);
            strcpy(finalpath, tempath);//get the current path
            strcat(finalpath, "/");//we add '/'
            strcat(finalpath, arr[0]);
            puts(finalpath);
            execv(finalpath, arr);
            tempath = strtok(NULL, ":");//get next path
        }
    } while (strcmp(command, "leave") != 0);
    return(0);
}
于 2012-11-28T13:56:56.693 に答える
1

によって返されたポインタのみを保存しています。strtok()それらは を指しcommandます。ループの反復ごとに が上書きcommandされるため、「古い」ポインタが指すデータが変更されます。

からトークンcommandを動的に割り当てられたメモリにコピーするか (ルックアップmalloc())、静的サイズの文字列の配列などを用意する必要があります。その場合、バッファ オーバーフローに注意してください。

于 2012-11-28T13:56:36.177 に答える