dup2 paramater命令混乱

时间:2018-02-22 09:29:42

标签: c linux system-calls dup2

我写了这个简单的程序:

#include<stdio.h>
#include<unistd.h>
#include <fcntl.h> 
#include <stdlib.h>
int main(){
    int fd = open("theFile.txt", O_CREAT | O_RDWR, 0666);
    if(fd<0){
     printf("coudlnt open File descriptor \n"); 
    }   
    pid_t pid = fork();
    if(pid==0){
        dup2(int oldFD, int newFD);
    dup2(fd,1);
        execlp("/bin/ls","ls","-l", NULL);      
    }
    return 0;
}

我想要的是,将ls - l的输出重定向到名为“theFile.txt”的文件。代码按我的预期工作。让我感到困惑的是dup2参数的顺序。我认为正确的顺序应为dup2(1, fd) - 将fd视为newFD,将1视为oldFD。但是当我将它用作dup2(fd,1)时,代码可以工作,根据SO上的其他答案,它基本上是stdout到fd。

此处oldFD fd如何?newFD 1如何?如果1newFD,为什么这个程序首先起作用?

此外,execlp在我致电dup2后会覆盖孩子的地址空间。 dup2如何与execlp相关联,以便获得所需的结果。即我所做的cat theFile.txt我得到了当前直接列出的内容。

我可以在这里得到一些解释吗?

1 个答案:

答案 0 :(得分:1)

根据[man7]: DUP(2)

  

int dup2 int oldfd int newfd );

  ...

   dup ()系统调用会创建文件描述符 oldfd 的副本,
  使用编号最小的未使用文件描述符用于新的   描述。

  ...

   dup2 ()系统调用执行与 dup ()相同的任务,但相反,   使用编号最小的未使用文件描述符,它使用文件
   newfd 中指定的描述符编号。如果文件描述符 newfd
  以前是开放的,在重新使用之前它会默默关闭。

将数据(例如文本)输出到控制台时,应用程序使用 stdout 流(也是 stderr ,但为了简单起见,让我们把它留下来)。 stdout fileno 1 (最好使用常量而不是值,因为值可能会发生变化 - 这不太可能案例,但总的来说):

cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q048923791$ cat /usr/include/unistd.h | grep STDOUT
#define STDOUT_FILENO   1   /* Standard output.  */

在您的子流程中,ls(通过execlp)将其数据吐出到 stdout (fileno 1 )。 之前,即dup2次来电。当前情况,之前 dup2调用(为清楚起见,我将在引用 stdout fileno <时使用定义的宏/ em>的):

  • fd:指向自定义文件(之前打开过)
  • STDOUT_FILENO:指向 stdout

dup2来电:

  1. dup2(fd, STDOUT_FILENO)(就像现在一样):关闭当前STDOUT_FILENO并将fd复制到STDOUT_FILENO。现状:

    • fd:指向自定义文件
    • STDOUT_FILENO:指向自定义文件
  2. dup2(STDOUT_FILENO, fd):关闭当前fd并将STDOUT_FILENO复制到fd。现状:

    • fd:指向 stdout
    • STDOUT_FILENO:指向 stdout
  3. 如图所示,对于#1。,当数据输出到 stdout 时,它实际上将转到自定义文件(而不是#2) 。即使使用fd,也会转到 stdout

    关于 2 nd 问题:

    • [man7]: EXEC(3)

        

      exec ()函数系列替换当前的过程图像
        使用新的过程映像。本手册中描述的功能
        页面是execve(2)的前端。

    • [man7]: EXECVE(2)

        

      默认情况下,文件描述符在 execve ()中保持打开状态。

        ...

        POSIX.1表示如果文件描述符0,1和2将为
        否则在成功 execve ()之后关闭,并且流程为   将获得权限,因为set-user-ID或set-group_ID模式为   在执行的文件上设置了位,然后系统可以打开一个   每个文件描述符的未指定文件。作为一般的   原则,没有便携式程序,无论是否有特权,都可以   假设这三个文件描述符将保持关闭    execve ()。

    文件描述符将从子进程传递到ls


    这是您的代码( code.c )的改进版本(仅次要更改):

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    
    
    int main() {
        int ret = 0, fd = open("thefile.txt", O_CREAT | O_RDWR, 0666);
        if (fd < 0) {
            printf("Coudln't open file: %d\n", errno);
            ret = 1;
        }
        pid_t pid = fork();
        if (pid == 0) {
            // dup2(int oldFD, int newFD);
            if (dup2(fd, STDOUT_FILENO) < 0) {
                printf("Couldn't redirect stdout: %d\n", errno);
                ret = 2;
            }
            execlp("/bin/ls", "ls", "-l", NULL);
        } else if (pid < 0) {
            printf("Couldn't spawn child process: %d\n", errno);
            ret = 3;
        }
        return ret;
    }