Are STDIN_FILENO and STDOUT_FILENO read only in c?

10,613

Solution 1

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.

Solution 2

This is the final part of daemonizing and involves redirecting stdout and stdin to /dev/null because they are not going to be used later.

Daemons normally write to log files, not to the standard output.

Citing this article:

Once it is running a daemon should not read from or write to the terminal from which it was launched. The simplest and most effective way to ensure this is to close the file descriptors corresponding to stdin, stdout and stderr. These should then be reopened, either to /dev/null, or if preferred to some other location. There are two reasons for not leaving them closed:

  • to prevent code that refers to these file descriptors from failing, and
  • to prevent the descriptors from being reused for some other purpose.
Share:
10,613
cpuer
Author by

cpuer

Updated on June 14, 2022

Comments

  • cpuer
    cpuer almost 2 years
    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?