bugfix> c > 投稿

executeCommand3 によって実行されるコマンドのリストを予期するプログラムがあります 。目標は、現時点ではこのリストに格納されているコマンドのリストを実行することですが、将来は実行されるシェルのような環境に入力されます。コードは次のとおりです。

MAIN.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>    //for getpid()
#include <sys/types.h> // for pid_t
#include "routines.h" //for executeCommand3()
#define SUB_PROCESSES_NUMBER 2
char *command0[] = {"ls", "tos", NULL};
char *command1[] = {"wc", NULL}; 
char *command2[] = {"wc", NULL};
char **commands[SUB_PROCESSES_NUMBER + 1] = {command0, command1, command2};
int main()
{   
    char input[1024];
    printf("scan: ");
    fgets(input,1024,stdin);
    int value=0;
    while((strcmp(input,"q\n")!=0))
    {
        value=executeCommand3(commands, SUB_PROCESSES_NUMBER+1);
        char buffer[1024];
        printf("value %i\nscan: ",value);
        fgets(input,1024,stdin);
        fgets(buffer,1024,stdin);
        printf("%s\n",input);
    }
    return 0;
}

routines.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> // for open, close,read,write on FD
#include <error.h>     // for error handling
#include <sys/types.h> // structs like time_t
#include <sys/wait.h>  // wait, waitpid, waitid - wait for process to change state
#include "routines.h"
#define READ 0  // for file descriptor index
#define WRITE 1 // for file descriptor index
#define STDIN 0
#define STDOUT 1
int executeCommand3(char ***args, int processNumb)
{
    pid_t pidList[processNumb];    //list of id of cmd processes (one for each child)
    int fdBackLog[processNumb][2]; // list of file desrciptors relative for each cmd (a pair for each child)
    int lastProcessFlag = 0;
    int i;
    for (i = 0; i < processNumb; i++) //cycle through the list of commands
    {
        if ((i + 1) == processNumb){
            lastProcessFlag = 1;
        }
        if (lastProcessFlag != 1)
        {
            int retPipe = pipe(fdBackLog[i]);
            if (retPipe < 0) // generating pipe for comunication between cmd(i) and cmd(i+1)
            {
                perror("pipe error");
                if (i > 0)
                {
                    close(fdBackLog[i - 1][READ]); 
                }
                exit(EXIT_FAILURE); //exit with failure code
            }
        }
        pidList[i] = fork();
        if (pidList[i] < 0) // error fork
        {
            perror("error fork()");
            if (i > 0)
            {                                  
                close(fdBackLog[i - 1][READ]); 
            }
            close(fdBackLog[i][READ]);  // close the read pipe end of cmd(i)
            close(fdBackLog[i][WRITE]); //close the write pipe end of cmd(i)
            exit(EXIT_FAILURE);
        }
        if (pidList[i] == 0) // CHILD PROCESS
        {
            printf("children %i process parent %i for: %s \n", getpid(), getppid(), args[i][0]);
            if (lastProcessFlag != 1)
            {

                close(fdBackLog[i][READ]); 
                dup2(fdBackLog[i][WRITE], STDOUT);
                close(fdBackLog[i][WRITE]); // duplicated pipes are not useful any more
            }
            else
            {
                close(fdBackLog[i][WRITE]); //last process has nothing to write on pipe
            }
            if (i > 0)
            {
                // Also need to redirect stdin if this is not first process
                dup2(fdBackLog[i - 1][READ], STDIN);
                close(fdBackLog[i - 1][READ]);
            }
            int exitValue = execvp(args[i][0], args[i]); 
            perror(args[i][0]);
            exit(EXIT_FAILURE); // Should not be reached;
        }
        close(fdBackLog[i][WRITE]); 
        if (i > 0)
        {
            close(fdBackLog[i - 1][READ]);
        }
    }
    int wPid, status;
    while((wPid = wait(&status))>0)
    {
        printf("Child #%i (%i)\n", wPid, status);
    }
}

私の問題はエラー処理にあります。実際、コマンドの最初のリストの2番目の項目はランダムな単語です。

コマンドを実行すると、出力は(通常のシェルのように)gooodになりますが、問題はMAIN.cのwhileループが関数 executeCommand3() を呼び出し続けることです 。 executeCommand3() のいくつかのプロセスが原因で、これが起こる可能性があると思いましたMAIN.cのstdinに何かを残して、 fgets ストリームから取得し、whileループのcicleを保持します。そのため、サイクルを中断するために別のfgetを追加しましたが、問題はまだ残っています。

executeCommand3() からエラーが発生した場合でも、どうすればプログラムを修正できますかwhileループが停止し、サイクルを通常通りにリドゥできますか? 問題は executeCommand3() 内にあります関数(おそらくいくつかの dup2() で 、 pipe() ...)またはMAIN.c

回答 1 件
  • 1つの問題は、 fgets() をエラーチェックしないことです。  呼び出します。もしそうなら、あなたはその stdin を見つけるでしょう  もう閉店した。 fcntl() の形式で診断が設定されたコードを次に示します  標準入力ファイル記述子でチェックする呼び出しはまだ有効です。

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #define READ 0
    #define WRITE 1
    #define STDIN 0
    #define STDOUT 1
    #define SUB_PROCESSES_NUMBER 2
    void executeCommand3(char ***args, int processNumb);
    char *command0[] = {"ls", "tos", NULL};
    char *command1[] = {"wc", NULL};
    char *command2[] = {"wc", NULL};
    char **commands[SUB_PROCESSES_NUMBER + 1] = {command0, command1, command2};
    int main(void)
    {
        char input[1024];
        printf("scan: ");
        fgets(input, 1024, stdin);
        if (fcntl(0, F_GETFD, 0) < 0)
        {
            perror("fcntl() - 1");
            exit(1);
        }
        while ((strcmp(input, "q\n") != 0))
        {
            executeCommand3(commands, SUB_PROCESSES_NUMBER + 1);
            char buffer[1024];
            printf("\nscan: ");
            if (fcntl(0, F_GETFD, 0) < 0)
            {
                perror("fcntl() - 2");
                exit(1);
            }
            fgets(input, 1024, stdin);
            fgets(buffer, 1024, stdin);
            printf("%s\n", input);
        }
        return 0;
    }
    void executeCommand3(char ***args, int processNumb)
    {
        pid_t pidList[processNumb];
        int fdBackLog[processNumb][2];
        int lastProcessFlag = 0;
        int i;
        for (i = 0; i < processNumb; i++)
        {
            if ((i + 1) == processNumb)
            {
                lastProcessFlag = 1;
            }
            if (lastProcessFlag != 1)
            {
                int retPipe = pipe(fdBackLog[i]);
                if (retPipe < 0)
                {
                    perror("pipe error");
                    if (i > 0)
                    {
                        close(fdBackLog[i - 1][READ]);
                    }
                    exit(EXIT_FAILURE);
                }
            }
            pidList[i] = fork();
            if (pidList[i] < 0)
            {
                perror("error fork()");
                if (i > 0)
                {
                    close(fdBackLog[i - 1][READ]);
                }
                close(fdBackLog[i][READ]);
                close(fdBackLog[i][WRITE]);
                exit(EXIT_FAILURE);
            }
            if (pidList[i] == 0)
            {
                printf("children %i process parent %i for: %s \n", getpid(), getppid(), args[i][0]);
                if (lastProcessFlag != 1)
                {
                    close(fdBackLog[i][READ]);
                    dup2(fdBackLog[i][WRITE], STDOUT);
                    close(fdBackLog[i][WRITE]);
                }
                else
                {
                    close(fdBackLog[i][WRITE]);
                }
                if (i > 0)
                {
                    dup2(fdBackLog[i - 1][READ], STDIN);
                    close(fdBackLog[i - 1][READ]);
                }
                execvp(args[i][0], args[i]);
                perror(args[i][0]);
                exit(EXIT_FAILURE);
            }
            close(fdBackLog[i][WRITE]);
            if (i > 0)
            {
                close(fdBackLog[i - 1][READ]);
            }
        }
        int wPid, status;
        while ((wPid = wait(&status)) > 0)
        {
            printf("Child #%i (%i)\n", wPid, status);
        }
    }
    
    

    サブディレクトリ tos がないディレクトリでそれを実行すると 、このような出力が得られます(プログラムの私のバージョンは pipe71 と呼ばれていました ):

    $ ./pipe71
    scan: pifflebunk
    children 35712 process parent 35711 for: ls 
    children 35713 process parent 35711 for: wc 
    children 35714 process parent 35711 for: wc 
    ls: tos: No such file or directory
    Child #35712 (256)
    Child #35713 (0)
           1       3      25
    Child #35714 (0)
    fcntl() - 2: Bad file descriptor
    scan: $
    $
    
    

    fcntl() - 2: Bad file descriptor に注意してください  ライン。それは、 executeCommand3() の何かが  関数は親プロセスの標準入力を閉じました。これはおそらくあなたが望んでいたものではなかったでしょう。 executeCommand3() を呼び出す前に分岐する必要があるかもしれません  次に、その関数を子から呼び出し、親を待機させます。または、 executeCommand3() でより注意することができます。  標準入力が閉じられている場所について。

あなたの答え