&6和/ dev / fd / 6有什么区别?


11

要读取文件描述符6,我可以使用<&6</dev/fd/6(aka /proc/self/fd/6)。通常两者都可以很好地工作。但是,如果该文件描述符恰好是套接字,则会发生奇怪的事情。例如:

$ bash -c 'ls -l /dev/fd/6;cat /dev/fd/6' 6</dev/tcp/localhost/12345
lrwx------ 1 michas michas 64 Jan 10 19:50 /dev/fd/6 -> socket:[315010]
cat: /dev/fd/6: No such device or address

这里ls显示描述符确实存在。但是用这种方式不可能访问数据。如果我cat <&6改用其他方法,一切都会再次正常。

两种访问文件描述符的方式有什么区别?

如果数字在变量中给出,是否有访问描述符的好方法?(</dev/fd/$fd可以,但<&$fd不能。)

(以上情况在Linux上可以观察到,但在OpenBSD上则不能观察到。-似乎文件描述符在那里是常规字符设备。)



2
谢谢。它是相关的,但实际上不是重复的。
michas

Answers:


5

之所以这样,是因为/dev/fd/在Linux上未实现从代表套接字的条目读取。您可以在此处找到有关推理的相当不错的文章。因此,您可以调用stat该链接,这就是为什么您使用看到它的原因ls,但是故意禁止访问。

现在第二部分-为什么bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345有效?那是因为套接字是使用套接字/文件API而不是/proc文件系统从中读取的。这是我观察到的情况:

  1. bash 在终端中运行的实例将使用fd 6创建套接字。
  2. 儿童bash运行,并呼吁dup2(6, 0),为了您的插座连接作为catstdin
  3. 如果dup2通话没有失败,则cat从中读取stdin

您可以使用以下方法重现并观察它:

netcat -lp 12345    # in another terminal session (GNU netcat)
strace -f -e trace=open,read,write,dup2 bash -c 'ls -l /dev/fd/6; cat <&6' \
 6</dev/tcp/localhost/12345

如果您想知道bash子进程为什么可以访问fd 6文件描述符fork,并且如果未将它们标记为“关闭” exec,那么它们也不会在此处关闭。


3

要回答您的直接问题,“有什么区别?”:

当您从重定向时<&6,shell使用dup2()系统调用来复制文件描述符。当您(尝试)从重定向时</dev/fd/6,它将使用open()

内核不支持open()in中的套接字/dev/fd;它们仅在装饰目录中提供。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.