Для чтения из файлового дескриптора 6 я могу использовать <&6
или </dev/fd/6
(иначе /proc/self/fd/6
). Обычно оба работают одинаково хорошо. Однако если этот дескриптор файла оказывается сокетом, происходят странные вещи. Например:
$ 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
Здесь ls
показано, дескриптор действительно присутствует. Но получить доступ к данным таким образом невозможно. Если я использую cat <&6
вместо этого все снова работает хорошо.
В чем разница между обоими способами доступа к дескриптору файла?
Есть ли хороший способ получить доступ к дескриптору, если число указано в переменной? ( </dev/fd/$fd
будет работать, но <&$fd
не работает.)
(Вышеуказанная ситуация может наблюдаться в Linux, но не в OpenBSD. - Кажется, дескриптор файла является обычным символическим устройством там.)
linux
bash
socket
file-descriptors
Михась
источник
источник
Ответы:
Это так, потому что чтение из
/dev/fd/
записей, представляющих сокеты, не реализовано в Linux. Вы можете найти довольно хорошую рецензию здесь. Таким образом, вы можете позвонитьstat
по ссылке, и именно поэтому вы видите егоls
, но доступ намеренно запрещен.Теперь о второй части - почему
bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
работает? Это потому, что сокет читается с использованием API сокета / файла, а не/proc
файловой системы. Вот что я наблюдал за происходящим:bash
экземпляр, работающий в вашем терминале, создает сокет с fd 6.bash
бегает и звонитdup2(6, 0)
, чтобы присоединить вашу розетку какcat
иstdin
.dup2
звонок не удался, кошка читаетstdin
.Вы можете воспроизвести и наблюдать это с:
Если вам интересно, почему
bash
дочерний процесс имеет доступ к fd 6 - дескрипторы файлов сохраняютсяfork
, и если они не помечены для закрытияexec
, они также не закрываются там.источник
Чтобы ответить на ваш прямой вопрос «в чем разница ?»:
Когда вы перенаправляете с
<&6
, оболочка используетdup2()
системный вызов для дублирования дескриптора файла. Когда вы (попытка) перенаправить с</dev/fd/6
, он будет использоватьopen()
.Ядро не поддерживает
open()
сокеты в/dev/fd
; они присутствуют в каталоге только дляоформленияинформации.источник