Aby odczytać z deskryptora pliku 6, mogę użyć <&6
lub </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 ls
pokazuje, że deskryptor jest rzeczywiście obecny. Ale dostęp do danych nie jest w ten sposób możliwy. Jeśli użyję cat <&6
zamiast 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/$fd
działałoby, ale <&$fd
nie 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.)
linux
bash
socket
file-descriptors
michas
źródło
źródło
Odpowiedzi:
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ćstat
na link i dlatego go widziszls
, ale dostęp jest celowo zabroniony.Teraz druga część - dlaczego
bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
działa? To dlatego, że gniazdo jest odczytywane przy użyciu interfejsu API gniazda / pliku, a nie/proc
systemu plików. Oto co się dzieje:bash
instancja działająca w twoim terminalu tworzy gniazdo z fd 6.bash
biegnie i połączeńdup2(6, 0)
, w celu podłączyć gniazdo jakocat
„sstdin
.dup2
połączenie się nie powiedzie, kot czyta zstdin
.Możesz go odtworzyć i obserwować za pomocą:
Jeśli zastanawiasz się, dlaczego
bash
proces potomny ma dostęp do fd 6 - deskryptory plików przetrwająfork
, a jeśli nie są oznaczone do zamknięciaexec
, również tam się nie zamykają.źródło
Aby odpowiedzieć na bezpośrednie pytanie: „ jaka jest różnica ?”:
Podczas przekierowywania z
<&6
powłoki używana jest funkcjadup2()
systemowa w celu zduplikowania deskryptora pliku. Kiedy przekierujesz (spróbujesz) przekierować</dev/fd/6
, użyjeopen()
.Jądro nie obsługuje
open()
gniazd/dev/fd
; są one obecne w katalogu dodekoracjijedynie informacji.źródło