管道导致无限输出

时间:2013-02-08 22:27:21

标签: c posix pipe

当我只是管道ls -l |与此类似,程序只是无限地从ls -l中吐出结果。任何人都可以看到什么是错的? 假设您只需要查看main函数。不过,这将编译。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>


#define COMMAND_LINE_LENGTH 256
#define HISTORY_LENGTH 10
#define TOKEN_MAX 50
#define DIRECTORY_LENGTH 5
#define DIRECTORY_PREFIX "/bin/"

struct prog_def
{
    //Binary location
    char *bin;

    //Is this program expecting a pipe?
    int expecting_pipe;

    //Arguments
    char *args[TOKEN_MAX + 1];

    pid_t pid;

} prog_def;

int get_prog_defs(const char* buf, struct prog_def prog_defs[])
{
    char *line = malloc(strlen(buf) + 1);

    int prog_count = 0;
    char* token;

    strcpy(line, buf);
    line[strlen(buf)] = 0;

    while(1)
    {
        int arg_count = 0;

        //The first time through we have to pass the line
        token = strtok(line, " ");

        //Each subsequent call we have to pass NULL
        //http://www.cplusplus.com/reference/cstring/strtok/
        line = NULL;

        //Start building the binary location string
        prog_defs[prog_count].bin = (char*)malloc(strlen(token) + DIRECTORY_LENGTH + 1);

        //Concatenate the directory prefix and command name
        strcat(prog_defs[prog_count].bin, DIRECTORY_PREFIX);
        strcat(prog_defs[prog_count].bin, token);

        //The first argument execvp will expect is the binary location itself
        //Redundant but if I wasn't too lazy to read the doc then I'd know why
        prog_defs[prog_count].args[arg_count++] = prog_defs[prog_count].bin;

        while(1)
        {
            prog_defs[prog_count].expecting_pipe = 0;

            //Check next token for end, pipe, IO redirection, or argument
            token = strtok(NULL, " ");

            //If we've consumed all tokens
            if (token == NULL)
                break;

            //Pipe
            if (strcmp(token, "|") == 0)
            {
                prog_defs[prog_count - 1].expecting_pipe = 1;
                break;
            }

            //Regular argument
            prog_defs[prog_count].args[arg_count++] = token;
        }

        ++prog_count;

        if (token == NULL) break;
    }

    return prog_count;
}


int main(int argc, char** argv)
{

    char command[COMMAND_LINE_LENGTH] = {0};

    //Generic loop counter
    int x = 0;

    while(1)
    {
        printf(">");

        //Get the command
        gets(command);

        struct prog_def prog_defs[TOKEN_MAX];
        int prog_count = get_prog_defs(command, prog_defs);

        //Keep the previous out fd for the in of the subsequent process
        int prev_out_fd = open("/dev/null", O_RDONLY);

        for (x = 0; x < prog_count; ++x)
        {
            //Create a pipe for both processes to share
            int pipefd[2];

            if (x != prog_count -1)
            {
                pipe(pipefd);
            }

            prog_defs[x].pid = fork();

            if(prog_defs[x].pid == 0)
            {
                dup2(prev_out_fd, STDIN_FILENO);
                close(pipefd[1]);

                if(x != prog_count - 1)
                {
                    dup2(pipefd[1], STDOUT_FILENO);
                    close(pipefd[0]);
                    close(pipefd[1]);
                }


                execvp(prog_defs[x].bin, prog_defs[x].args);
            prev_out_fd = pipefd[0];
            close(pipefd[1]);
            }

        close(prev_out_fd);

            prev_out_fd = pipefd[0];
            close(pipefd[1]);

        }

        printf("\n");

        for (x = 0; x < prog_count; ++x)
        {
            waitpid(prog_defs[x].pid, NULL, 0);
        }

    }
}

1 个答案:

答案 0 :(得分:1)

你调用malloc为字符串获取一些内存,这将是未初始化的,因此包含随机垃圾。然后调用strcat,它将尝试将另一个字符串附加到随机垃圾中,几乎肯定会在malloc空间的末尾运行,导致随机混乱的行​​为和崩溃。

在递增prog_defs[prog_count - 1]之前你也使用prog_count,所以第一次通过循环,(当prog_count == 0时)这将在数组开始之前写入,这也会导致随机混乱的行​​为和崩溃。