我写了这个简单的程序:
#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
如何?如果1
为newFD
,为什么这个程序首先起作用?
此外,execlp
在我致电dup2
后会覆盖孩子的地址空间。 dup2
如何与execlp
相关联,以便获得所需的结果。即我所做的cat theFile.txt
我得到了当前直接列出的内容。
我可以在这里得到一些解释吗?
答案 0 :(得分:1)
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
来电:
dup2(fd, STDOUT_FILENO)
(就像现在一样):关闭当前STDOUT_FILENO
并将fd
复制到STDOUT_FILENO
。现状:
fd
:指向自定义文件STDOUT_FILENO
:指向自定义文件 dup2(STDOUT_FILENO, fd)
:关闭当前fd
并将STDOUT_FILENO
复制到fd
。现状:
fd
:指向 stdout STDOUT_FILENO
:指向 stdout 如图所示,对于#1。,当数据输出到 stdout 时,它实际上将转到自定义文件(而不是#2) 。即使使用fd
,也会转到 stdout 。
关于 2 nd 问题:
exec ()函数系列替换当前的过程图像
使用新的过程映像。本手册中描述的功能
页面是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;
}