0

bash コマンド (一種のシェル プログラム) を実行する小さな C プログラムがあります。

ユーザーが次のようなコマンドを送信すると:

  1. ls -l | grep .[c,h]$ | トイレ –l

  2. ls

  3. エコー | ls

リンクされたリストデータ構造を使用することにしました。これが実行する関数です

int execute(command *c) {
//create new procces and execute command 

int numOfPipe = getNumOfPipes(c);   // gets how many commands there is seperated by | (for 1 command with no pipes. getNumOfPipes returns 1
int fds[numOfPipe][2];

pid_t pids[numOfPipe];
int i;
int status;

// create pipes
for( i = 0; i < numOfPipe; i++ ) {
    pipe(fds[i]);
}

i=0;

// p set to be the head of the list (first command)
Pipe* p = c->pl->head;  

// running throw all nodes
while(i<numOfPipe) {

    if ((pids[i] = fork()) < 0) {
            perror("fork");
            abort();
    } else if (pids[i] == 0) {
        // children processes

        // there is more then one command
        if (numOfPipe > 1) {    
            if (p==c->pl->head) // first node (will be first command)
                dup2(fds[i][1],STDOUT_FILENO);
            else if(p->next!=NULL) {    // not first / last command
                dup2(fds[i-1][0],STDIN_FILENO);
                dup2(fds[i][1],STDOUT_FILENO);

            } else if(p->next==NULL)    // last command
                dup2(fds[i-1][0],STDIN_FILENO);


            // closing all pipes
            int j;
            for( j = 0; j < numOfPipe; j++ ){
                close(fds[j][0]);
                close(fds[j][1]);
            }
        }

        // execute command
        execvp(p->params[0],p->params);

        // on execute error will print this messege and returns COMMAND_ERROR
        fprintf(stderr, "%s: command not found\n",p->params[0]);    
        destroyShell(c);
        free(c);
        exit(COMMAND_ERROR);    
    }

    // parent closing all end of pipes
    int j;
    for( j = 0; j < numOfPipe && numOfPipe > 1; j++ ){
        close(fds[j][0]);
        close(fds[j][1]);
    }

    // waiting each process
    while(wait(&status)!=pids[i]);

    // if the command is valid
    if (WIFEXITED(status) && WEXITSTATUS(status)==COMMAND_ERROR) {
        destroyShell(c);
        return WEXITSTATUS(status);
    }

    p=p->next;
    i++;


}

// closing all end of pipes (necessary here????)
int j;
for (j = 0; j < numOfPipe; j++) {
    close(fds[j][0]);
    close(fds[j][1]);
}

// returns all command's return code
if (WIFEXITED(status))
    return WEXITSTATUS(status);

return 0;
}

今では、このコードは予測できない方法で動作しています。単一のコマンドでは動作し、サーバルでは動作する場合と動作しない場合があります....このコードブロックに何時間も費やしましたが、Googleはまったく役に立ちませんでした!!

いくつかのメモ:

  1. ユーザーが次のようなコマンドを送信した場合:

エコー|ls|123

戻りコードは COMMAND_ERROR マクロ定義になり、次のエラー メッセージが表示されるはずです。

123: コマンドが見つかりません

しかし、どういうわけか私のコードは「echo |」を実行します。ls' を実行し、最初の 2 つのコマンドの出力を表示します。その後、'123' コマンドのエラー メッセージが表示されます。また、いくつかの悪いコマンドの場合-最初に見つかったコマンドに対してのみエラーメッセージを表示することが想定されており、次のコマンドを実行し続けることは想定されていません...

このコマンドの場合:

ls -l | grep .[c,h]$ | トイレ –l

エンドレスループにストックされているようです....

  1. コマンド *c はリンクされたリストを保持し、リスト内の各ノードは 1 つのコマンドになり、各ノードはコマンドのすべてのパラメーターを保持する配列呼び出しパラメーターを保持します。例:

エコー 1234 | ls /ホーム

 ___________                 ___________
|           |               |           |
| COMMAND 1 |      --->     | COMMAND 2 |
|___________|               |___________|
      |                           |
      |                           |
    ______                     _______
   |      |                   |       |
   | ECHO |                   |  LS   |
   |______|                   |_______|
   |      |                   |       |
   | 1234 |                   | /HOME |
   |______|                   |_______|

私が十分に明確で、私の問題をよく説明したことを願っています。どうもありがとうございました!

4

0 に答える 0