Are STDIN_FILENO and STDOUT_FILENO read only in c?

cpuer picture cpuer · Jun 1, 2011 · Viewed 10k times · Source
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 tells me that dup2() makes newfd be the copy of oldfd, closing newfd first if necessary.:

int dup2(int oldfd, int newfd);

But aren't STDIN_FILENO and STDOUT_FILENO read only?

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>

Or dup2 didn't change newfd at all?

Answer

Donal Fellows picture Donal Fellows · Jun 1, 2011

The constants themselves (on POSIX, STDIN_FILENO is 0 and STDOUT_FILENO is 1) are indeed read-only, but the file descriptors they characterize may be closed and something else opened in their place; they're just ordinary file descriptors (usually with a flag set so that they stay open on an execve() system call).

The thing that is changing is the table of file descriptors for the process that resides inside the OS kernel. See that syscall instruction? That's really important here; that's the trap out of your process into the OS.