Untuk membaca dari file deskriptor 6 saya dapat menggunakan <&6
atau </dev/fd/6
(alias /proc/self/fd/6
). Biasanya keduanya bekerja sama baiknya. Namun jika deskriptor file tersebut kebetulan berupa soket, hal-hal aneh terjadi. Sebagai contoh:
$ 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
Di sini ls
menunjukkan deskriptor memang ada. Tetapi mengakses data tidak dimungkinkan dengan cara ini. Jika saya gunakan cat <&6
sebagai gantinya semuanya bekerja dengan baik lagi.
Apa perbedaan antara kedua cara mengakses deskriptor file?
Apakah ada cara yang baik untuk mengakses deskriptor jika nomornya jika diberikan dalam variabel? ( </dev/fd/$fd
akan bekerja, tetapi <&$fd
tidak.)
(Situasi di atas dapat diamati di linux, tetapi tidak di OpenBSD. - Sepertinya deskriptor file adalah perangkat karakter biasa di sana.)
sumber
Jawaban:
Itu karena membaca dari
/dev/fd/
entri yang mewakili soket tidak diterapkan di Linux. Anda dapat menemukan artikel yang cukup bagus tentang alasan di sini. Jadi Anda dapat memanggilstat
tautan, dan itulah mengapa Anda melihatnyals
, tetapi akses sengaja tidak diizinkan.Sekarang untuk bagian kedua - mengapa itu
bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
berhasil? Itu karena socket dibaca dari menggunakan socket / file API, bukan/proc
filesystem. Inilah yang saya amati terjadi:bash
Misalnya berjalan di terminal Anda membuat socket dengan fd 6.bash
berlari dan menelepondup2(6, 0)
, untuk memasang soket Anda sebagaicat
miliknyastdin
.dup2
panggilan tidak gagal, kucing membaca daristdin
.Anda dapat mereproduksi dan mengamatinya dengan:
Jika Anda bertanya-tanya mengapa
bash
proses anak memiliki akses ke deskriptor 6 file bertahanfork
, dan jika mereka tidak ditandai untuk ditutupexec
, mereka tidak bisa ditutup di sana juga.sumber
Untuk menjawab pertanyaan langsung Anda, " apa bedanya ?":
Saat Anda mengalihkan dari
<&6
, shell menggunakandup2()
system call untuk menduplikasi file descriptor. Saat Anda (berusaha) mengalihkan</dev/fd/6
, itu akan digunakanopen()
.Kernel tidak mendukung
open()
pada soket di/dev/fd
; mereka hadir di direktori hanya untuk informasidekorasi.sumber