Was ist der Unterschied zwischen & 6 und / dev / fd / 6?

11

Zum Lesen aus dem Dateideskriptor 6 kann ich <&6oder </dev/fd/6(aka /proc/self/fd/6) verwenden. Normalerweise funktionieren beide gleich gut. Wenn dieser Dateideskriptor jedoch ein Socket ist, passieren seltsame Dinge. Beispielsweise:

$ 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

Hier lszeigt sich, dass der Deskriptor tatsächlich vorhanden ist. Ein Zugriff auf die Daten ist auf diese Weise jedoch nicht möglich. Wenn ich cat <&6stattdessen benutze, funktioniert alles wieder gut.

Was ist der Unterschied zwischen beiden Arten des Zugriffs auf den Dateideskriptor?

Gibt es eine gute Möglichkeit, auf einen Deskriptor zuzugreifen, wenn die Nummer in einer Variablen angegeben ist? ( </dev/fd/$fdwürde funktionieren, <&$fdtut es aber nicht.)

(Die obige Situation kann unter Linux beobachtet werden, aber nicht unter OpenBSD. - Der Dateideskriptor scheint dort ein normales Zeichengerät zu sein.)

michas
quelle
1
Ist dies eine doppelte unix.stackexchange.com/q/98958/38906
cuonglm
2
Vielen Dank. Es ist verwandt, aber nicht wirklich ein Duplikat.
Michas

Antworten:

5

/dev/fd/Dies liegt daran, dass das Lesen von Einträgen, die Sockets darstellen, unter Linux nicht implementiert ist. Eine gute Beschreibung der Argumentation finden Sie hier. Sie können also statauf den Link lszugreifen , und deshalb sehen Sie ihn mit , aber der Zugriff ist absichtlich nicht zulässig.

Nun zum zweiten Teil - warum funktioniert das bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345? Dies liegt daran, dass der Socket von der Socket / Datei-API und nicht vom /procDateisystem gelesen wird . Folgendes habe ich beobachtet:

  1. bash Die in Ihrem Terminal ausgeführte Instanz erstellt einen Socket mit fd 6.
  2. Kind bashläuft und ruft an dup2(6, 0), um Ihren Socket als cat's anzuschließen stdin.
  3. Wenn der dup2Anruf nicht fehlgeschlagen ist, liest die Katze aus stdin.

Sie können es reproduzieren und beobachten mit:

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

Wenn Sie sich fragen, warum der bashuntergeordnete Prozess Zugriff auf fd 6 hat - Dateideskriptoren überleben fork, und wenn sie nicht zum Schließen markiert sind exec, werden sie dort auch nicht geschlossen.

TNW
quelle
3

Um Ihre direkte Frage zu beantworten: " Was ist der Unterschied ?":

Wenn Sie von umleiten <&6, verwendet die Shell einen dup2()Systemaufruf, um den Dateideskriptor zu duplizieren. Wenn Sie (versuchen) umzuleiten </dev/fd/6, wird es verwendet open().

Der Kernel unterstützt open()Sockets in nicht /dev/fd. sie sind in dem Verzeichnis für Dekoration nur Informationen.

Toby Speight
quelle