¿Cuál es la diferencia entre & 6 y / dev / fd / 6?

11

Para leer del descriptor de archivo 6 puedo usar <&6o </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í lsmuestra que el descriptor está realmente presente. Pero acceder a los datos no es posible de esta manera. Si uso cat <&6en 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/$fdfuncionaría, pero <&$fdno 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í).

michas
fuente
1
¿Es un archivo
cuonglm
2
Gracias. Está relacionado pero no es realmente un duplicado.
michas

Respuestas:

5

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 llamar statal enlace, y es por eso que lo ve ls, 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/12345funciona? Esto se debe a que el socket se lee utilizando el socket / archivo API, no el /procsistema de archivos. Esto es lo que he observado que sucede:

  1. bash la instancia que se ejecuta en su terminal crea un socket con fd 6.
  2. El niño bashcorre y llama dup2(6, 0), para conectar su socket como cat's stdin.
  3. Si la dup2llamada no falla, el gato lee stdin.

Puedes reproducirlo y observarlo con:

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

Si se pregunta por qué el bashproceso secundario tiene acceso a fd 6, los descriptores de archivos sobreviven forky si no están marcados para cerrarse exec, tampoco se cierran allí.

TNW
fuente
3

Para responder a su pregunta directa, " ¿cuál es la diferencia ?":

Cuando redirige desde <&6, el shell utiliza una dup2()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 de decoración .

Toby Speight
fuente