2011-06-01 22 views
2
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.STDIN_FILENO和STDOUT_FILENO是否只读取c?

int dup2(int oldfd, int newfd); 

但不STDIN_FILENOSTDOUT_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

回答

2

常量本身(对POSIX,STDIN_FILENO0STDOUT_FILENO1)确实是只读的,但它们表征文件描述符可以被关闭,一些在他们的地方人打开;它们只是普通的文件描述符(通常设置了一个标志,以便它们在系统调用中保持打开状态execve())。

正在改变的事情是驻留在OS内核内的进程的文件描述符表。看到syscall指令?这在这里非常重要。这是您的流程进入操作系统的陷阱。

+0

@Donal Fellows,'close(fd)'前的最后一个条件'if(fd> STDERR_FILENO)'是什么意思? – cpuer 2011-06-01 08:02:32

+0

@cpuer:如果它不是stdin,stdout和stderr中的一个,它将测试(并关闭)文件描述符。 POSIX系统的'STDERR_FILENO'为'2',所有其他的FD都是比它小的“小”整数。 – 2011-06-01 08:04:11

+0

@Donal Fellows,但有必要吗? 'fd = open(“/ dev/null”,O_RDWR);'here'fd'永远不会是stdin,stdout和stderr中的一个,对吗? – cpuer 2011-06-01 08:05:50

3

这是守护进程的最后一部分,涉及将stdoutstdin重定向到/dev/null,因为它们不会在以后使用。

守护进程通常写入日志文件,而不是写入标准输出。

援引this article

一旦运行一个守护进程不应该读取或写入到它推出的终端。确保这一点最简单和最有效的方法是关闭与stdin,stdout和stderr相对应的文件描述符。然后这些应该重新打开,或者/ dev/null,或者如果偏好某个其他位置。有两个原因没有离开他们关闭:

  • ,以防止将这些文件描述符从失败的代码,并
  • 防止描述符被重用用于其他目的。
+0

@Blagovest Buyukliev,但有什么意义,即使他们仍然很愿意stdin/stdout,我们看不到它,对不对? – cpuer 2011-06-01 07:59:47

+0

@cpuer:如果他们写入他们的旧标准输出,他们可能会阻止。如果他们从他们的标准输入读取,他们_将阻止,因为该过程不是前台进程。 – 2011-06-01 08:07:46

+0

写入'/ dev/null'是无操作,写入'stdout'涉及更多的工作并可能阻塞(尽管输出可能因为进程已从终端分离而不可见)。 – 2011-06-01 08:10:06

0

关闭stdin和stdout工作得很好。虽然当你这样做时,你不能再读取它们,并且必须使用dup()的描述符。

+0

如果写入已关闭的fd,会发生什么情况? – cpuer 2011-06-01 08:25:28

+0

如果关闭STDOUT_FILENO,则使用写入(STDOUT_FILENO,...)或printf()不会产生任何输出。 – cmende 2011-06-03 08:52:19

相关问题