Apa perbedaan antara & 6 dan / dev / fd / 6?

11

Untuk membaca dari file deskriptor 6 saya dapat menggunakan <&6atau </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 lsmenunjukkan deskriptor memang ada. Tetapi mengakses data tidak dimungkinkan dengan cara ini. Jika saya gunakan cat <&6sebagai 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/$fdakan bekerja, tetapi <&$fdtidak.)

(Situasi di atas dapat diamati di linux, tetapi tidak di OpenBSD. - Sepertinya deskriptor file adalah perangkat karakter biasa di sana.)

michas
sumber
1
Apakah ini duplikat unix.stackexchange.com/q/98958/38906
cuonglm
2
Terima kasih. Ini terkait tetapi tidak benar-benar duplikat.
michas

Jawaban:

5

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 memanggil stattautan, dan itulah mengapa Anda melihatnya ls, tetapi akses sengaja tidak diizinkan.

Sekarang untuk bagian kedua - mengapa itu bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345berhasil? Itu karena socket dibaca dari menggunakan socket / file API, bukan /procfilesystem. Inilah yang saya amati terjadi:

  1. bash Misalnya berjalan di terminal Anda membuat socket dengan fd 6.
  2. Anak bashberlari dan menelepon dup2(6, 0), untuk memasang soket Anda sebagai catmiliknya stdin.
  3. Jika dup2panggilan tidak gagal, kucing membaca dari stdin.

Anda dapat mereproduksi dan mengamatinya dengan:

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

Jika Anda bertanya-tanya mengapa bashproses anak memiliki akses ke deskriptor 6 file bertahan fork, dan jika mereka tidak ditandai untuk ditutup exec, mereka tidak bisa ditutup di sana juga.

TNW
sumber
3

Untuk menjawab pertanyaan langsung Anda, " apa bedanya ?":

Saat Anda mengalihkan dari <&6, shell menggunakan dup2()system call untuk menduplikasi file descriptor. Saat Anda (berusaha) mengalihkan </dev/fd/6, itu akan digunakan open().

Kernel tidak mendukung open()pada soket di /dev/fd; mereka hadir di direktori hanya untuk informasi dekorasi .

Toby Speight
sumber