Para leer del descriptor de archivo 6 puedo usar <&6
o </dev/fd/6
(aka /proc/self/fd/6
). Por lo general, ambos funcionan igual de bien. Sin embargo, si ese descriptor de archivo es un socket, suceden cosas extrañas. Por ejemplo:
$ 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
Aquí ls
muestra que el descriptor está realmente presente. Pero acceder a los datos no es posible de esta manera. Si uso cat <&6
en su lugar, todo vuelve a funcionar bien.
¿Cuál es la diferencia entre ambas formas de acceder al descriptor de archivo?
¿Hay una buena manera de acceder a un descriptor si el número se da en una variable? ( </dev/fd/$fd
funcionaría, pero <&$fd
no funciona)
(La situación anterior se puede observar en Linux, pero no en OpenBSD. Parece que ese descriptor de archivo es un dispositivo de caracteres normal allí).
fuente
Respuestas:
Es así porque la lectura de
/dev/fd/
entradas que representan sockets no está implementada en Linux. Puede encontrar una buena crítica sobre el razonamiento aquí. Entonces puede llamarstat
al enlace, y es por eso que lo vels
, pero el acceso se prohíbe deliberadamente.Ahora para la segunda parte, ¿por qué
bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
funciona? Esto se debe a que el socket se lee utilizando el socket / archivo API, no el/proc
sistema de archivos. Esto es lo que he observado que sucede:bash
la instancia que se ejecuta en su terminal crea un socket con fd 6.bash
corre y llamadup2(6, 0)
, para conectar su socket comocat
'sstdin
.dup2
llamada no falla, el gato leestdin
.Puedes reproducirlo y observarlo con:
Si se pregunta por qué el
bash
proceso secundario tiene acceso a fd 6, los descriptores de archivos sobrevivenfork
y si no están marcados para cerrarseexec
, tampoco se cierran allí.fuente
Para responder a su pregunta directa, " ¿cuál es la diferencia ?":
Cuando redirige desde
<&6
, el shell utiliza unadup2()
llamada al sistema para duplicar el descriptor de archivo. Cuando (intente) redirigir desde</dev/fd/6
, utilizaráopen()
.El núcleo no es compatible
open()
con sockets en/dev/fd
; están presentes en el directorio solo para información dedecoración.fuente