fd = open("/dev/null", O_RDWR);
if (fd == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"open(\"/dev/null\") failed");
return NGX_ERROR;
}
if (dup2(fd, STDIN_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
return NGX_ERROR;
}
if (dup2(fd, STDOUT_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
return NGX_ERROR;
}
if (fd > STDERR_FILENO) {
if (close(fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
return NGX_ERROR;
}
}
man
告诉我dup2() makes newfd be the copy of oldfd, closing newfd first if necessary.
:
int dup2(int oldfd, int newfd);
但不是STDIN_FILENO
和STDOUT_FILENO
只读吗?
Dump of assembler code for function dup2:
0x00000037aa4c6ac0 <dup2+0>: mov $0x21,%eax
0x00000037aa4c6ac5 <dup2+5>: syscall
0x00000037aa4c6ac7 <dup2+7>: cmp $0xfffffffffffff001,%rax
0x00000037aa4c6acd <dup2+13>: jae 0x37aa4c6ad0 <dup2+16>
0x00000037aa4c6acf <dup2+15>: retq
0x00000037aa4c6ad0 <dup2+16>: mov 0x28a4d1(%rip),%rcx # 0x37aa750fa8 <free+3356736>
0x00000037aa4c6ad7 <dup2+23>: xor %edx,%edx
0x00000037aa4c6ad9 <dup2+25>: sub %rax,%rdx
0x00000037aa4c6adc <dup2+28>: mov %edx,%fs:(%rcx)
0x00000037aa4c6adf <dup2+31>: or $0xffffffffffffffff,%rax
0x00000037aa4c6ae3 <dup2+35>: jmp 0x37aa4c6acf <dup2+15>
或dup2
根本没有改变newfd
?
答案 0 :(得分:3)
这是守护进程的最后一部分,涉及将stdout
和stdin
重定向到/dev/null
,因为它们不会在以后使用。
守护进程通常写入日志文件,而不是标准输出。
引用this article:
一旦它运行,守护进程就不应该读取或写入启动它的终端。确保这一点的最简单和最有效的方法是关闭与stdin,stdout和stderr相对应的文件描述符。然后应将这些重新打开,或者/ dev / null,或者首选其他位置。不让他们关闭有两个原因:
- 以防止引用这些文件描述符的代码失败,并且
- 以防止描述符被重用于其他目的。
答案 1 :(得分:3)
常量本身(在POSIX上,STDIN_FILENO
是0
而STDOUT_FILENO
是1
)确实是只读的,但它们表征的文件描述符可能是关闭的,在他们的地方打开了别的东西;它们只是普通的文件描述符(通常设置了一个标志,以便它们在execve()
系统调用时保持打开状态。)
正在改变的是驻留在OS内核中的进程的文件描述符表。看到syscall
指令?这在这里非常重要;这是你进入操作系统的过程中的陷阱。
答案 2 :(得分:0)
关闭stdin和stdout非常合适。虽然当你这样做时,你不能再读取它们,并且必须使用dup()'d描述符。