dup2 错误的文件描述符

Posted

技术标签:

【中文标题】dup2 错误的文件描述符【英文标题】:dup2 bad file descriptor 【发布时间】:2015-11-30 23:15:57 【问题描述】:

我正在尝试在我的 shell 中实现管道。现在它可以处理正常的命令,如 ls、who、date 等。

通过大量阅读并进入其他堆栈溢出帖子以检查管道应该如何工作,我想出了这段代码,我将向你们演示。该函数基本上接受一个应该处理的命令。

void
runCommand(Command *cmd)

    char **pl = cmd->pgm->pgmlist;
    int status;
    Pgm *p = cmd->pgm;

    //Count the number of pipes and create the right number of filedescriptors
    int numPipes = countPipes(cmd->pgm);
    int pipefds[2*numPipes];

    //Pipe the file descriptors here and check if there was an error.
    for(int i = 0; i < (numPipes); i++)
        if(pipe(pipefds + i*2) < 0) 
            perror("couldn't pipe");
            exit(EXIT_FAILURE);
        
    

    pid_t pid, wpid;


    int fdr;
    int fd;

    int j = 0;
    while(p != NULL) 

        pid = fork();

        if (pid == 0) 
            // Child process
            if (cmd->bakground == 1) // Check if it should be running in the background, if so, assign a new PID
            
                setpgid(pid, 0);
            

            // Check if RSTDOUT is on or not
            if(cmd->rstdout != NULL)

                fd = open(cmd->rstdout, O_WRONLY | O_CREAT | O_TRUNC , S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
                //fclose(fopen(cmd->rstdout, "w"));
                printf("in first\n");
                dup2(fd,1);
                close(fd);
            

            // Check if RSTIN is on or not
            if(cmd->rstdin != NULL) 

                fdr = open(cmd->rstdin, O_RDONLY);
                printf("in second\n");
                dup2(fdr, 0);
                close(fdr);
            

            //if not last command
            if(p->next)
                printf("in third\n");
                if(dup2(pipefds[j + 1], 1) < 0)
                    perror("dup2");
                    exit(EXIT_FAILURE);
                
            

            //if not first command&& j!= 2*numPipes
            if(j != 0 )

                printf("in fourth: %d\n", j);
                if(dup2(pipefds[j-2], 0) < 0)
                    perror(" dup2");///j-2 0 j+1 1
                    exit(EXIT_FAILURE);

                

            

            for(int i = 0; i < 2*numPipes; i++)
                    printf("in fifth\n");
                    close(pipefds[i]);
            

            j += 2;
            printf("%s\n",pl[0] );
            if (execvp(pl[0], pl) == -1) 
                perror("lsh");
            

            exit(EXIT_FAILURE);
        

        else if (pid < 0) 
            // Error forking
            perror("lsh");
         
        else if(cmd->bakground != 1) // check in the parent process if it was running in background, if so dont call for wait()
            // Parent process
            j+=2;

            pl = p->pgmlist;    
            p = p->next;
            for(int i = 0; i < 2 * numPipes; i++)
                printf("in sixth\n");
                close(pipefds[i]);
            

            int returnStatus;    
            waitpid(pid, &returnStatus, 0);  // Parent process waits here for child to terminate.

            if (returnStatus == 0)  // Verify child process terminated without error.  
            
               printf("The child process terminated normally.");    
            

            if (returnStatus == 1)      
            
               printf("The child process terminated with an error!.");    
            

         
        else
            printf("Child process with ID %d is running in background\n",pid );
    


普通命令仍然可以正常工作,但是当我尝试这样做时,我得到以下结果。

> ls | wc
>  dup2: Bad file descriptor

当我读到它时,我认为这意味着我只是接近早期,或者我处理我的文件描述符很糟糕。我试图修复它,但没有成功,我求助于你们,他们可能会看到一些我看不到的东西。如果您需要任何进一步的信息,请发表评论,我会尽力提供帮助。

******编辑 1******

我将 printf 添加到我使用的每个 dup2 或 close 中,将它们命名为 first、second、third 等,只是为了确切知道我在哪个 dup 或 close 中得到错误。这是我运行命令时的结果:

> ls | wc
in sixth
in sixth
in third
in sixth
in sixth
in fourth: 2
 dup2: Bad file descriptor

所以知道我们至少知道它失败的地方。

******编辑2******

我还添加了我们正在写入、读取或关闭的文件描述符:

In parent closing fd: 0
In parent closing fd: 1
in child third writing to fd: 1
In parent closing fd: 0
In parent closing fd: 1
in child fourth reading from fd: 0
 dup2: Bad file descriptor

【问题讨论】:

gcc -Wall -Werror -g -o myprog &amp;&amp; gdb --args myprog 您忘记添加 gcc myprog,您希望我添加输出中给出的错误吗? @JonathonReinhart 我忘记了myprog.c,抱歉。但是不,我希望你修复编译中的所有错误。我怀疑你的程序可能会在你这样做时工作。这就是我们编译语言的原因——在运行前检测编程问题。 我遇到的每一个错误都是“fork 等的隐式声明。我看到我没有实现 fork 或所有其他功能错误的方式?@JonathonReinhart 假设是Linux,你可以在strace -f -o /path/to/output/file ...下运行,看看系统调用层发生了什么。 【参考方案1】:

我认为你的 dup2 问题就在这里:

if(cmd->rstdin != NULL) 

                fdr = open(cmd->rstdin, O_RDONLY);
                dup2(fd, 0);
                close(fdr);
            

您正在打开“fdr”,但随后在 dup2 中使用了“fd”。 “fd”未打开或已在先前的 if 中关闭。此外,在这两个条件中,您都不会检查 dup2 的返回值。

【讨论】:

刚刚在 dup2 中把它改成了 fdr 但还是不行。此外,该部分与管道无关。如果我使用这些命令 ls text.txt,那部分必须做

以上是关于dup2 错误的文件描述符的主要内容,如果未能解决你的问题,请参考以下文章

dup/dup2

linux之dup和dup2函数解析

Linux dup dup2函数理解

dup/dup2输出重定向

dup和dup2函数

文件IO详解(十四)---dup函数和dup2函数详解