Quelle est la différence entre & 6 et / dev / fd / 6?

11

Pour lire à partir du descripteur de fichier 6, je peux utiliser <&6ou </dev/fd/6(aka /proc/self/fd/6). Habituellement, les deux fonctionnent aussi bien. Cependant, si ce descripteur de fichier se trouve être un socket, des choses étranges se produisent. Par exemple:

$ 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

Ici ls, le descripteur est bien présent. Mais l'accès aux données n'est pas possible de cette façon. Si j'utilise à la cat <&6place, tout fonctionne bien à nouveau.

Quelle est la différence entre les deux façons d'accéder au descripteur de fichier?

Existe-t-il un bon moyen d'accéder à un descripteur si le nombre est donné dans une variable? ( </dev/fd/$fdfonctionnerait, mais <&$fdne fonctionne pas.)

(La situation ci-dessus peut être observée sur Linux, mais pas sur OpenBSD. - On dirait que ce descripteur de fichier est un périphérique de caractères normal là-bas.)

michas
la source
1
Est-ce un doublon unix.stackexchange.com/q/98958/38906
cuonglm
2
Merci. C'est lié mais pas vraiment un doublon.
michas

Réponses:

5

C'est parce que la lecture des /dev/fd/entrées qui représentent des sockets n'est pas implémentée sous Linux. Vous pouvez trouver un assez bon résumé sur le raisonnement ici. Vous pouvez donc appeler statle lien, et c'est pourquoi vous le voyez ls, mais l'accès est délibérément interdit.

Maintenant pour la deuxième partie - pourquoi ça bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345marche? C'est parce que le socket est lu à l'aide de l'API socket / fichier, pas le /procsystème de fichiers. Voici ce que j'ai observé se produire:

  1. bash l'instance exécutée dans votre terminal crée une socket avec fd 6.
  2. L'enfant bashcourt et appelle dup2(6, 0), afin de fixer votre prise telle catquelle stdin.
  3. Si l' dup2appel n'a pas manqué, chat lit à partir stdin.

Vous pouvez le reproduire et l'observer avec:

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 vous vous demandez pourquoi le bashprocessus enfant a accès à fd 6 - les descripteurs de fichiers survivent fork, et s'ils ne sont pas marqués pour la fermeture exec, ils n'y sont pas fermés également.

TNW
la source
3

Pour répondre à votre question directe, " quelle est la différence ?":

Lorsque vous redirigez depuis <&6, le shell utilise un dup2()appel système pour dupliquer le descripteur de fichier. Lorsque vous (tentez de) rediriger depuis </dev/fd/6, il utilisera open().

Le noyau ne prend pas en charge open()les sockets dans /dev/fd; ils sont présents dans le répertoire pour la décoration d' information seulement.

Toby Speight
la source