程序在执行通过管道和 fork 给出的 shell 命令期间挂起

问题描述

我不知道我为什么挂在这里。据我所知,我已经正确地进行了管道和分叉,当我检查数组中的数据时,它很好。然而,当我尝试运行“ls -l | grep total”之类的命令时,它会挂起。有人可以帮我吗?

当我运行一个不涉及管道的命令时,它很好。但是当我尝试实现管道部分时,它挂了。奇怪的是,在我将所有内容分解为单独的功能之前,这对我有用。我假设我在某个地方犯了错误,但我只是没有看到它是什么。在重构我的代码之前,我试图保持所有内容与我的状态相似。


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <fcntl.h>

#define MAX_BUF_SZ 1024
#define MAX_ARGS 10

bool checkForPipe(const char *string);
bool checkForRedirect(const char *string);
void tokenizeInput(char * string,char ** l_array,char **m_array,char **r_array,bool pipey,bool redirect,int *status);
void createArguments(char *string,char **arg_array);
void executeCommand(int status,char **l_array,char **r_array);

int main()
{
    char *ptr;
    bool is_pipe = false;
    bool is_redirect_out = false;
    bool is_exit = false;
    int exec_status = 0;                     //Will determine how to execute execvp()
    char *l_args[MAX_ARGS] = {NULL};
    char *m_args[MAX_ARGS] = {NULL};
    char *r_args[MAX_ARGS] = {NULL};


    ptr = (char*)malloc(MAX_BUF_SZ);

    while(!is_exit)
    {
        // Diplay prompt
        char cur_dir[MAX_BUF_SZ];
        getcwd(cur_dir,MAX_BUF_SZ);
        printf("SHELL:%s$ ",cur_dir);

        fgets(ptr,MAX_BUF_SZ,stdin);
        is_pipe = checkForPipe(ptr);
        is_redirect_out = checkForRedirect(ptr);

        if(strcmp(ptr,"exit\n") == 0)
        {
            is_exit = true;
        }

        tokenizeInput(ptr,l_args,m_args,r_args,is_pipe,is_redirect_out,&exec_status);
        executeCommand(exec_status,r_args);

        for(int i = 0; i < MAX_ARGS; i++)
        {
            l_args[i] = NULL;
            m_args[i] = NULL;
            r_args[i] = NULL;
        }

    }

    return 0;

}

bool checkForPipe(const char *string)
{
    return strchr(string,'|') != NULL;
}

bool checkForRedirect(const char *string)
{
    return strchr(string,'>') != NULL;
}

void tokenizeInput(char *string,int *status)
{

    // No pipes or redirects given by user
    if(!pipey && !redirect)
    {
        char main_str[1024];
        strcpy(main_str,string);

        //initialize argument array
        createArguments(main_str,l_array);

        *status = 1;

    }

    //A single pipe given by user
    else if(pipey && !redirect)
    {
        char main_str[1024];
        char pipe_str[1024];
        strcpy(main_str,string);


        char *token = strchr(main_str,'|');
        *token = '\0';
        token++;
        while(*token == ' ')
        {
            token++;
        }

        strcpy(pipe_str,token);

        //initialize argument arrays
        createArguments(main_str,l_array);
        createArguments(pipe_str,r_array);

        *status = 2;

    }

    // A single redirect given by user
    else if(!pipey && redirect)
    {
        char main_str[1024];
        char pipe_str[1024];
        strcpy(main_str,string);

        char *token = strchr(main_str,'>');
        *token = '\0';
        token++;
        while(*token == ' ')
        {
            token++;
        }

        strcpy(pipe_str,token);

        //Initialize argument arrays
        createArguments(main_str,r_array);

        *status = 3;

    }
    else if(pipey && redirect)
    {
        // declare some strings
        char copy_str[MAX_BUF_SZ];
        char main_str[MAX_BUF_SZ];
        char pipe_str[MAX_BUF_SZ];
        char redirect_str[MAX_BUF_SZ];

        //make copy of the readonly string
        strcpy(copy_str,string);
        char *token = strtok(copy_str,"|>");

        //create the main string
        strcpy(main_str,copy_str);

        //create pipe string
        token = strtok(NULL,"|>");
        while(*token == ' ')
        {
            token++;
        }
        strcpy(pipe_str,token);

        //create redirect string
        token = strtok(NULL,"|>");
        while(*token == ' ')
        {
            token++;
        }
        strcpy(redirect_str,m_array);
        createArguments(redirect_str,r_array);

        *status = 4;

    }
}

void createArguments(char *string,char **arg_array)
{
    char *token;
    char copy_str[MAX_BUF_SZ];
    strcpy(copy_str,string);

    int i = 0;
    for(token = strtok(copy_str," \n"),i = 0; token; token = strtok(NULL," \n" ),++i)
    {
        arg_array[i] = token;
    }

    
}

void executeCommand(int status,char **r_array)
{
    int fd[2];
    pid_t cpid_1;
    pid_t cpid_2;

    // No Pipes or Redirects
    if(status == 1)
    {

        cpid_1 = fork();

        if(cpid_1 < 0)
        {
            printf("Failed to fork");
            exit(EXIT_FAILURE);  //Error forking
        }
        if(cpid_1 == 0)
        {
            if(execvp(l_array[0],l_array) == -1)
            {
                printf("Failed to execute command");
                exit(EXIT_FAILURE);
            }
        }
        wait(NULL);
    }
    else if(status == 2)
    {

        if(pipe(fd) == -1)
        {
            printf("Failed to pipe");
            exit(EXIT_FAILURE);     // Failed to create pipe
        }
        cpid_1 = fork();
        
        if(cpid_1 < 0)
        {
            printf("Failed to fork");
            exit(EXIT_FAILURE);     //Failed to fork
        }

        if(cpid_1 == 0)
        {
            dup2(fd[1],STDOUT_FILENO);
            close(fd[0]);
            close(fd[1]);
            execvp(l_array[0],l_array);
        }

        cpid_2 = fork();
        if(cpid_2 < 0)
        {
            printf("Failed to fork");
            exit(EXIT_FAILURE);        // Failed to fork
        }

        if(cpid_2 == 0)
        {
            dup2(fd[0],STDIN_FILENO);
            close(fd[0]);
            close(fd[1]);
            execvp(r_array[0],r_array);
        }

    }
        close(fd[0]);
        close(fd[1]);

        waitpid(cpid_1,NULL,0);
        waitpid(cpid_2,0);

}

解决方法

tokenizeInput() 中,您将 *status 设置为 14 之间可能的整数值。但在 executeCommand() 中,您只处理 status12 的情况。 “管道 + 重定向”的情况是 status=4 而您没有在 executeCommand() 中处理这种情况。因此,您在 waitpid() 中徘徊 - 没有分叉。