Qual é a diferença entre & 6 e / dev / fd / 6?

11

Para ler do descritor de arquivo 6 eu posso usar <&6ou </dev/fd/6(aka /proc/self/fd/6). Geralmente ambos funcionam igualmente bem. No entanto, se esse descritor de arquivo for um soquete, coisas estranhas acontecem. Por exemplo:

$ 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

Aqui lsmostra que o descritor está realmente presente. Mas acessar os dados não é possível dessa maneira. Se eu usar, cat <&6tudo funcionará bem novamente.

Qual é a diferença entre as duas maneiras de acessar o descritor de arquivo?

Existe uma boa maneira de acessar um descritor se o número for fornecido em uma variável? ( </dev/fd/$fdfuncionaria, mas <&$fdnão funciona.)

(A situação acima pode ser observada no linux, mas não no OpenBSD. - Parece que o descritor de arquivo é um dispositivo de caractere comum lá.)

michas
fonte
1
É este um duplicado um unix.stackexchange.com/q/98958/38906
cuonglm
2
Obrigado. Está relacionado, mas não é realmente uma duplicata.
michas 12/01

Respostas:

5

É assim porque a leitura de /dev/fd/entradas que representam soquetes não é implementada no Linux. Você pode encontrar uma boa descrição sobre o raciocínio aqui. Você pode acessar stato link e é por isso que o vê ls, mas o acesso é deliberadamente proibido.

Agora, para a segunda parte - por que bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345funciona? Isso ocorre porque o socket é lido usando a API socket / file, não o /procsistema de arquivos. Isto é o que eu observei acontecendo:

  1. bash A instância em execução no seu terminal cria um soquete com o fd 6.
  2. Criança bashcorre e liga dup2(6, 0), a fim de conectar seu soquete como cat's stdin.
  3. Se a dup2chamada não falhar, o gato lê stdin.

Você pode reproduzir e observar com:

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

Se você está se perguntando por que o bashprocesso filho tem acesso aos descritores fd 6 - file fork, e se eles não estão marcados para fechar exec, eles também não são fechados.

TNW
fonte
3

Para responder sua pergunta direta, " qual é a diferença ?":

Quando você redireciona <&6, o shell usa uma dup2()chamada do sistema para duplicar o descritor de arquivo. Quando você (tenta) redirecionar </dev/fd/6, ele usará open().

O kernel não suporta open()soquetes /dev/fd; eles estão presentes no diretório apenas para informações de decoração .

Toby Speight
fonte