dup2 参数顺序混乱
dup2 paramater order confusion
我写了这个简单的程序:
#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 上的其他一些答案,它基本上是 fd 的标准输出。
这里的oldFD
fd
怎么样,这里的newFD
1
怎么样?如果 1
是 newFD
,为什么这个程序首先起作用?
此外,execlp
在我调用 dup2
后覆盖了 child 的地址 space。 dup2
如何连接到 execlp
以获得所需的结果。即我所做的 cat theFile.txt
我直接列出电流。
我可以在这里得到一些解释吗?
int dup2(int oldfd, int newfd);
...
The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused file descriptor for the new
descriptor.
...
The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.
当向控制台输出数据(例如文本)时,应用程序使用 stdout 流(也 stderr,但为了简单起见,让我们别说了)。 stdout 的 fileno 是 1 (最好使用常量而不是值,因为值可能会改变- 在 这种 情况下不太可能,但一般来说):
cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q048923791$ cat /usr/include/unistd.h | grep STDOUT
#define STDOUT_FILENO 1 /* Standard output. */
在您的子进程中,ls(通过 execlp)将其数据吐出到 stdout (文件编号 1)。 在此之前,调用dup2。目前的情况,before dup2 调用(为清楚起见,我将在引用 stdout 时使用定义的宏的fileno):
- 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和问题:
-
The exec() family of functions replaces the current process image
with a new process image. The functions described in this manual
page are front-ends for execve(2).
-
By default, file descriptors remain open across an execve().
...
POSIX.1 says that if file descriptors 0, 1, and 2 would
otherwise be closed after a successful execve(), and the process
would gain privilege because the set-user-ID or set-group_ID mode
bit was set on the executed file, then the system may open an
unspecified file for each of these file descriptors. As a general
principle, no portable program, whether privileged or not, can
assume that these three file descriptors will remain closed across
an execve().
文件描述符将从子进程传递到 ls。
这是您的代码 (code00.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;
}
我写了这个简单的程序:
#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 上的其他一些答案,它基本上是 fd 的标准输出。
这里的oldFD
fd
怎么样,这里的newFD
1
怎么样?如果 1
是 newFD
,为什么这个程序首先起作用?
此外,execlp
在我调用 dup2
后覆盖了 child 的地址 space。 dup2
如何连接到 execlp
以获得所需的结果。即我所做的 cat theFile.txt
我直接列出电流。
我可以在这里得到一些解释吗?
int dup2(int oldfd, int newfd);
...
The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused file descriptor for the new
descriptor.
...
The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.
当向控制台输出数据(例如文本)时,应用程序使用 stdout 流(也 stderr,但为了简单起见,让我们别说了)。 stdout 的 fileno 是 1 (最好使用常量而不是值,因为值可能会改变- 在 这种 情况下不太可能,但一般来说):
cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q048923791$ cat /usr/include/unistd.h | grep STDOUT #define STDOUT_FILENO 1 /* Standard output. */
在您的子进程中,ls(通过 execlp)将其数据吐出到 stdout (文件编号 1)。 在此之前,调用dup2。目前的情况,before dup2 调用(为清楚起见,我将在引用 stdout 时使用定义的宏的fileno):
- 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和问题:
-
The exec() family of functions replaces the current process image
with a new process image. The functions described in this manual
page are front-ends for execve(2). -
By default, file descriptors remain open across an execve().
...
POSIX.1 says that if file descriptors 0, 1, and 2 would
otherwise be closed after a successful execve(), and the process
would gain privilege because the set-user-ID or set-group_ID mode
bit was set on the executed file, then the system may open an
unspecified file for each of these file descriptors. As a general
principle, no portable program, whether privileged or not, can
assume that these three file descriptors will remain closed across
an execve().
文件描述符将从子进程传递到 ls。
这是您的代码 (code00.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;
}