อะไรคือความแตกต่างระหว่าง & 6 กับ / dev / fd / 6?


11

หากต้องการอ่านจาก file descriptor 6 ฉันสามารถใช้<&6หรือ</dev/fd/6(aka /proc/self/fd/6) โดยปกติแล้วทั้งสองทำงานได้ดีเท่า ๆ กัน อย่างไรก็ตามหากไฟล์ descriptor นั้นเป็นซ็อกเก็ตสิ่งแปลก ๆ ก็เกิดขึ้น ตัวอย่างเช่น:

$ 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แสดงให้เห็นถึง descriptor มีอยู่จริง แต่การเข้าถึงข้อมูลเป็นไปไม่ได้ด้วยวิธีนี้ ถ้าฉันใช้cat <&6แทนทุกอย่างทำงานได้ดีอีกครั้ง

อะไรคือความแตกต่างระหว่างทั้งสองวิธีในการเข้าถึงไฟล์ descriptor?

มีวิธีที่ดีในการเข้าถึง descriptor ถ้าจำนวนถ้ากำหนดในตัวแปรหรือไม่? (ใช้</dev/fd/$fdงานได้ แต่ใช้<&$fdไม่ได้)

(สถานการณ์ดังกล่าวสามารถสังเกตได้บน linux แต่ไม่ใช่ใน OpenBSD - ดูเหมือนว่าตัวอธิบายไฟล์นั้นเป็นอุปกรณ์ตัวอักษรปกติที่นั่น)


1
นี่เป็นรายการเดียวที่ซ้ำซ้อนunix.stackexchange.com/q/98958/38906 หรือไม่
cuonglm

2
ขอบคุณ มันเกี่ยวข้อง แต่ไม่ซ้ำกันจริงๆ
michas

คำตอบ:


5

มันเป็นเช่นนั้นเพราะการอ่านจาก/dev/fd/รายการที่แสดงถึงซ็อกเก็ตไม่ได้ถูกนำมาใช้บน Linux คุณสามารถหาเหตุผลได้ดีที่นี่ ดังนั้นคุณสามารถโทรstatไปที่ลิงก์และนั่นคือสาเหตุที่คุณเห็นด้วยlsแต่การเข้าถึงนั้นไม่ได้รับอนุญาตอย่างจงใจ

ตอนนี้สำหรับส่วนที่สอง - ทำไมจึงใช้bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345งานได้ นั่นเป็นเพราะซ็อกเก็ตถูกอ่านจากการใช้ socket / file API ไม่ใช่/procระบบไฟล์ นี่คือสิ่งที่ฉันสังเกตเห็นเกิดขึ้น:

  1. bash อินสแตนซ์ที่ทำงานใน terminal ของคุณสร้างซ็อกเก็ตด้วย fd 6
  2. เด็กbashวิ่งและโทรdup2(6, 0)ในการสั่งซื้อที่จะแนบซ็อกเก็ตของคุณเป็น'scatstdin
  3. ถ้าโทรไม่ได้ล้มเหลวแมวอ่านจากdup2stdin

คุณสามารถทำซ้ำและสังเกตได้ด้วย:

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

หากคุณสงสัยว่าเพราะเหตุใดbashกระบวนการของเด็กจึงสามารถเข้าถึง fd 6 - ตัวอธิบายไฟล์เอาตัวรอดได้forkและหากพวกเขาไม่ได้ถูกทำเครื่องหมายเพื่อปิดexecพวกเขาก็จะไม่ถูกปิดเช่นกัน


3

หากต้องการตอบคำถามโดยตรงของคุณ " อะไรคือความแตกต่าง ":

เมื่อคุณเปลี่ยนเส้นทาง<&6เชลล์ใช้การdup2()เรียกของระบบเพื่อทำซ้ำ descriptor ไฟล์ เมื่อคุณ (พยายาม) การเปลี่ยนเส้นทางจากนั้นก็จะใช้</dev/fd/6open()

เคอร์เนลไม่รองรับopen()ซ็อกเก็/dev/fdต มันมีอยู่ในไดเรกทอรีสำหรับข้อมูลการตกแต่งเท่านั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.