Jaka jest różnica między & 6 i / dev / fd / 6?

11

Aby odczytać z deskryptora pliku 6, mogę użyć <&6lub </dev/fd/6(aka /proc/self/fd/6). Zwykle oba działają równie dobrze. Jednak jeśli deskryptorem pliku jest gniazdo, zdarzają się dziwne rzeczy. Na przykład:

$ 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

Tutaj lspokazuje, że deskryptor jest rzeczywiście obecny. Ale dostęp do danych nie jest w ten sposób możliwy. Jeśli użyję cat <&6zamiast tego wszystko znowu działa dobrze.

Jaka jest różnica między obu sposobami dostępu do deskryptora pliku?

Czy istnieje dobry sposób na dostęp do deskryptora, jeśli liczba jest podana w zmiennej? ( </dev/fd/$fddziałałoby, ale <&$fdnie działa.)

(Powyższą sytuację można zaobserwować na Linuksie, ale nie na OpenBSD. - Wygląda na to, że deskryptor pliku jest tam zwykłym urządzeniem znakowym.)

michas
źródło
1
Czy to zduplikowany plik unix.stackexchange.com/q/98958/38906
cuonglm
2
Dzięki. Jest powiązany, ale tak naprawdę nie jest duplikatem.
michas,

Odpowiedzi:

5

Jest tak, ponieważ czytanie z /dev/fd/pozycji reprezentujących gniazda nie jest zaimplementowane w systemie Linux. Tutaj możesz znaleźć całkiem dobry opis rozumowania. Możesz więc zadzwonić statna link i dlatego go widzisz ls, ale dostęp jest celowo zabroniony.

Teraz druga część - dlaczego bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345działa? To dlatego, że gniazdo jest odczytywane przy użyciu interfejsu API gniazda / pliku, a nie /procsystemu plików. Oto co się dzieje:

  1. bash instancja działająca w twoim terminalu tworzy gniazdo z fd 6.
  2. Dziecko bashbiegnie i połączeń dup2(6, 0), w celu podłączyć gniazdo jako cat„s stdin.
  3. Jeśli dup2połączenie się nie powiedzie, kot czyta z stdin.

Możesz go odtworzyć i obserwować za pomocą:

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

Jeśli zastanawiasz się, dlaczego bashproces potomny ma dostęp do fd 6 - deskryptory plików przetrwają fork, a jeśli nie są oznaczone do zamknięcia exec, również tam się nie zamykają.

TNW
źródło
3

Aby odpowiedzieć na bezpośrednie pytanie: „ jaka jest różnica ?”:

Podczas przekierowywania z <&6powłoki używana jest funkcja dup2()systemowa w celu zduplikowania deskryptora pliku. Kiedy przekierujesz (spróbujesz) przekierować </dev/fd/6, użyje open().

Jądro nie obsługuje open()gniazd /dev/fd; są one obecne w katalogu do dekoracji jedynie informacji.

Toby Speight
źródło