分叉进程写入已关闭的文件描述符stderr

时间:2015-09-25 06:18:41

标签: sockets unix exec fork file-descriptor

我遇到了一个我希望帮助理解的场景。示例代码如下。

fclose(stdin);
fclose(stdout);
fclose(stderr);
int sockets[2];
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
int socketA = sockets[0];
int socketB = sockets[1];
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
int socketC = sockets[0];
int socketD = sockets[1];
assert(socketA == 0);
assert(socketB == 1);
assert(socketC == 2);
assert(socketD == 3);
unblock_socket(socketA);
unblock_socket(socketB);
unblock_socket(socketC);
unblock_socket(socketD);
unsigned char buffer = 0;
assert(::recv(socketA, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketC, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketB, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketD, &buffer, sizeof(buffer), 0) == -1);
pid_t pid = fork();
if (pid == -1)
    assertfalse;
else if (pid > 0)
{
    int status = 0;
    waitpid(pid, &status, 0);
}
else
{
    assert(execv("/usr/sbin/chown", nullptr) == 0) // Prints "usage: chown [-fhv] [-R [-H | -L | -P]]..." to stderr
    _exit(EXIT_FAILURE);
}
assert(::recv(socketA, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketC, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketB, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketD, &buffer, sizeof(buffer), 0) == -1); // Assertion failed!. Reading from socket D we see "usage: chown [-fhv] [-R [-H | -L | -P]]..."

我已经关闭了stderr(文件描述符2)并随后打开了套接字C,它接受了现在可用的文件描述符2.然而,chown仍然似乎设法将其错误输出写入文件描述符2.应该chown没有实现stderr被关闭并且文件描述符2重新分配,因此不写入它?

由于

2 个答案:

答案 0 :(得分:0)

这完全符合预期。

关闭stderr,然后调用socketpair()。 SocketC == 2(即现在的stderr)。

chown()继承了这些文件描述符,因此当它写入stderr时,它真正写入SocketC,父级从SocketD读取。

答案 1 :(得分:0)

已解决 - 我应该将stdin / stdout / stderr重定向到/ dev / null,这样就不会重新分配文件描述符0-2。这是一个守护进程应用程序。

但是我仍然发现奇怪的chown是打印到文件描述符2.在我看来,使用

打印
dprintf(STDOUT_FILEERR, "usage: chown [-fhv] [-R [-H | -L | -P]]...");

或者

const char error[] = "usage: chown [-fhv] [-R [-H | -L | -P]]...";
write(STDOUT_FILENO, error, sizeof(error) - 1);

而不是

fprintf(stderr, "usage: chown [-fhv] [-R [-H | -L | -P]]...");

或类似的东西......就像在第一个例子中dprintf写入socketC(文件描述符2)而导致问题但在第二个例子中fprintf实现了stderr FILE *对象被关闭而不进行写入。

非常感谢任何进一步的见解。