STDIN_FILENO 和 STDOUT_FILENO 在 c 中是只读的吗?

发布于 2024-11-11 13:44:57 字数 1677 浏览 3 评论 0原文

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() 使 newfd 成为 oldfd 的副本,如有必要,首先关闭 newfd。

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

时光暖心i 2024-11-18 13:44:57

常量本身(在 POSIX 上,STDIN_FILENO0STDOUT_FILENO1)确实是只读的,但是它们所描述的文件描述符可能会被关闭,并在其位置上打开其他东西;它们只是普通的文件描述符(通常设置一个标志,以便它们在 execve() 系统调用时保持打开状态)。

正在改变的是驻留在操作系统内核中的进程的文件描述符表。看到那个syscall指令了吗?这在这里非常重要;这就是你的进程进入操作系统的陷阱。

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.

暗藏城府 2024-11-18 13:44:57

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

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

引用这篇文章

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

  • 防止引用这些文件描述符的代码失败,并且
  • 防止描述符被重复用于其他目的。

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.
ぇ气 2024-11-18 13:44:57

关闭 stdin 和 stdout 效果很好。尽管当您这样做时,您无法再读取它们,并且必须使用 dup() 描述符。

Closing stdin and stdout works perfectly fine. Although when you do this you cannot read from them anymore and have to use the dup()'d descriptors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文