有时我看到一些奇怪的用法 dup2()
功能。比如说,它甚至不检查返回值。
if ((sock= accept(sockfd, (struct sockaddr *)&s_addr, &namelen)) == -1){
syslog(LOG_ERR, "in accept: %m");
exit(3);
}
dup2(sock, 0);
close(sockfd);
sock = 0;
它甚至不检查返回值。它到底对这样的参数做了什么?这个 man dup2
说,如果 newfd (second argument of dup2) was previously open, it is silently closed before being reused.
但是0是stdin,为什么我们还要这样做呢?
这实际上是一个相当常见的范式,用来配置一个程序以socket作为标准输入来操作。
它本身可能看起来毫无意义--为什么不直接在任何socket描述符上操作呢?- 但在实践中,它的后面几乎总是跟着一个 fork()
操作,运行一些期望从标准输入读取的子进程。
噗 - 现在它可以和socket一起工作了。
很可能你会看到stdout以类似的方式进行操作。
编辑:一个超级简单的例子是一个网络服务,它在你接受TCP连接后为你提供一个shell。
...
if ((sock= accept(sockfd, (struct sockaddr *)&s_addr, &namelen)) == -1){
syslog(LOG_ERR, "in accept: %m");
exit(3);
}
dup2(sock, 0); // stdin
dup2(sock, 1); // stdout
dup2(sock, 2); // stderr
close(sock);
system("/bin/sh"); // terrible security
所以现在当你连接到它的时候--也许是用客户端的telnet--你就有了一个看起来像传统的stdinouterr的shell,所有的shell都连接到socket上。
重点是你看到这个主要是在一些 子程序 必须执行,其中它假定文件描述符012是以某种方式设置的。
注意:这是个糟糕的想法,而且 高度 不安全,只有在恶意软件中才能看到这种真实的情况。 我犹豫要不要在这里加入这个例子,但它是如此清晰的说明,我认为值得。