Unix ติดตามไดเรกทอรีการทำงานของผู้ใช้อย่างไรเมื่อสำรวจระบบไฟล์?


29

สมมติว่าฉันล็อกอินเข้าสู่เชลล์บนระบบยูนิกซ์และเริ่มเคาะคำสั่ง ~ผมเริ่มเริ่มต้นในบ้านของผู้ใช้ของฉัน ฉันอาจมาจากที่นั่นลงไปยังไดเรกทอรีcdDocuments

คำสั่งเพื่อเปลี่ยนไดเรกทอรีการทำงานที่นี่เป็นเรื่องง่ายมากที่จะเข้าใจ: โหนดหลักมีรายการของโหนดลูกที่สามารถเข้าถึงได้และสันนิษฐานว่ามันใช้ตัวแปร (ที่เหมาะสม) ของการค้นหาเพื่อค้นหาการมีอยู่ของโหนดลูกที่มี ตั้งชื่อผู้ใช้ที่ป้อนและไดเรกทอรีการทำงานจะถูก "แก้ไข" เพื่อให้ตรงกับสิ่งนี้ - แก้ไขให้ฉันถ้าฉันผิดที่นั่น มันอาจจะง่ายกว่าที่เชลล์เพียงแค่ "ไร้เดียงสา" พยายามที่จะเข้าถึงไดเรกทอรีตรงตามความต้องการของผู้ใช้และเมื่อระบบไฟล์ส่งคืนข้อผิดพลาดบางประเภทเชลล์จะแสดงการตอบสนองตามลำดับ

สิ่งที่ฉันสนใจคือกระบวนการเดียวกันนั้นทำงานอย่างไรเมื่อฉันสำรวจไดเรกทอรีต่างๆเช่นไปที่พาเรนต์หรือพาเรนต์ของผู้ปกครอง

ด้วยตำแหน่งของฉัน "blind" ที่ไม่รู้ชื่อน่าจะเป็นDocumentsหนึ่งในหลาย ๆ ไดเรกทอรีในทรีระบบไฟล์ทั้งหมดด้วยชื่อนั้น Unix จะกำหนดได้อย่างไรว่าฉันควรจะวางไว้ที่ไหนต่อไป มันทำการอ้างอิงpwdและตรวจสอบว่า? ถ้าใช่จะpwdติดตามสถานะการนำทางในปัจจุบันอย่างไร


คำตอบ:


76

คำตอบอื่น ๆ คือ oversimplifications แต่ละคนนำเสนอเพียงบางส่วนของเรื่องและเป็นสิ่งที่ผิดในสองประเด็น

มีสองวิธีในการติดตามไดเรกทอรีทำงาน:

  • สำหรับทุกกระบวนการในโครงสร้างข้อมูลเคอร์เนลพื้นที่ซึ่งแสดงถึงกระบวนการนั้นเคอร์เนลจะเก็บ vnode สองรายการที่อ้างอิงถึง vnode ของไดเรกทอรีการทำงานและไดเรกทอรีรากสำหรับกระบวนการนั้น อ้างอิงอดีตมีการตั้งค่าโดยchdir()และระบบโทรหลังโดยfchdir() chroot()หนึ่งสามารถเห็นพวกเขาทางอ้อมใน/procระบบปฏิบัติการ Linux หรือผ่านfstatคำสั่งบน FreeBSD และไม่ชอบ:

    % fstat -p $$ | head -n 5
    USER CMD PID FD MOUNT INUM MODE SZ | DV R / W
    JdeBP zsh 92648 ข้อความ / 24958 -r-xr-xr-x 702360 r
    JdeBP zsh 92648 ctty / dev 148 crw - w ---- pts / 4 rw
    JdeBP zsh 92648 wd / usr / home / JdeBP 4 drwxr-xr-x 124 r
    JdeBP zsh 92648 root / 4 drwxr-xr-x 35 r
    % 

    เมื่อการจำแนกชื่อพา ธ ดำเนินการจะเริ่มต้นที่หนึ่งหรืออื่น ๆ ของ vnodes ที่อ้างอิงเหล่านั้นขึ้นอยู่กับว่าเส้นทางนั้นสัมพันธ์กันหรือสัมบูรณ์ (มีตระกูลของการ…at()เรียกของระบบที่อนุญาตให้การแก้ไขชื่อพา ธ เริ่มต้นที่ vnode ที่อ้างอิงโดยตัวอธิบายไฟล์ open (directory) เป็นตัวเลือกที่สาม)

    ใน microkernel Unices โครงสร้างข้อมูลอยู่ในพื้นที่แอปพลิเคชัน แต่หลักการของการเก็บการอ้างอิงแบบเปิดไปยังไดเรกทอรีเหล่านี้ยังคงเหมือนเดิม

  • ภายในภายในเปลือกหอยเช่นซี, Korn, Bourne Again, C และ Almquist เปลือกเปลือกนอกจากนี้ติดตามการทำงานของไดเรกทอรีการทำงานโดยใช้การจัดการสตริงของตัวแปรสตริงภายใน chdir()มันเป็นเช่นนี้เมื่อใดก็ตามที่มีสาเหตุการเรียกร้อง

    หากมีการเปลี่ยนแปลงชื่อพา ธ สัมพัทธ์ก็จะดำเนินการสตริงเพื่อผนวกชื่อนั้น หากมีการเปลี่ยนแปลงชื่อพา ธ สัมบูรณ์มันจะแทนที่สตริงด้วยชื่อใหม่ ในทั้งสองกรณีมันจะปรับสตริงเพื่อลบ.และ..ส่วนประกอบและไล่ล่าลิงก์สัญลักษณ์แทนที่พวกเขาด้วยชื่อที่เชื่อมโยงไปยัง ( นี่คือรหัสของเชลล์ Z สำหรับสิ่งนั้น)

    ชื่อในตัวแปรสตริงภายในมีการติดตามโดยตัวแปรเชลล์ชื่อPWD(หรือcwdใน C เชลล์) นี่คือการส่งออกตามอัตภาพเป็นตัวแปรสภาพแวดล้อม (ชื่อPWD) ไปยังโปรแกรมที่เกิดจากเปลือก

ทั้งสองวิธีในการติดตามสิ่งต่าง ๆ นั้นได้รับการเปิดเผยโดย-Pและ-Lตัวเลือกของคำสั่งในตัวcdและpwdเชลล์และโดยความแตกต่างระหว่างpwdคำสั่งในตัวของเชลล์และทั้ง/bin/pwdคำสั่งและคำสั่งในตัวpwdของสิ่งต่าง ๆ เช่น (ในหมู่อื่น ๆ ) VIM และ NeoVIM

% mkdir a; ln -sab 
% (cd b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / a
/ usr / home / JdeBP / b
% (cd b; pwd -P; / bin / pwd -P)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
% (cd b; pwd -L; / bin / pwd -L)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / b
% (cd -P b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
% (cd b; PWD = / hello / there / bin / pwd -L)
/ usr / home / JdeBP / a
% 

อย่างที่คุณเห็น: การได้รับไดเรกทอรีทำงาน "ลอจิก" เป็นเรื่องของการดูPWDตัวแปรเชลล์ (หรือตัวแปรสภาพแวดล้อมหากไม่มีโปรแกรมเชลล์) ในขณะที่การรับไดเรกทอรีทำงาน "ทางกายภาพ" เป็นเรื่องของการเรียกใช้getcwd()ฟังก์ชันไลบรารี

การทำงานของ/bin/pwdโปรแกรมเมื่อใช้-Lตัวเลือกนั้นค่อนข้างบอบบาง มันไม่สามารถไว้วางใจค่าของPWDตัวแปรสภาพแวดล้อมที่จะได้รับการถ่ายทอด ท้ายที่สุดมันไม่จำเป็นต้องถูกเรียกใช้โดยเชลล์และโปรแกรมการแทรกแซงอาจไม่ได้ใช้กลไกของเชลล์ในการทำให้PWDตัวแปรสภาพแวดล้อมติดตามชื่อของไดเรกทอรีทำงานเสมอ หรือบางคนอาจทำสิ่งที่ฉันทำไปที่นั่น

ดังนั้นสิ่งที่มันทำคือ (ตามมาตรฐาน POSIX บอกว่า) ตรวจสอบว่าชื่อที่กำหนดให้PWDผลลัพธ์เหมือนกับชื่อ.ตามที่สามารถเห็นได้ด้วยการติดตามการโทรของระบบ:

% ln -sac 
% (cd b; truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
สถิติ ("/ usr / home / JdeBP / b", { โหมด = drwxr-xr-x, inode = 120932, ขนาด = 2, blksize = 131072}) = 0 (0x0) 
สถิติ (".", {โหมด = drwxr-xr-x, inode = 120932, ขนาด = 2, blksize = 131072}) = 0 (0x0)
/ usr / home / JdeBP / b
% (cd b; PWD = / usr / local / etc truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
สถิติ ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, size = 158, blksize = 10240}) = 0 (0x0) 
สถิติ (".", {โหมด = drwxr-xr-x, inode = 120932, ขนาด = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / สวัสดี / มีมัด / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
สถิติ ("/ hello / there", 0x7fffffffe730) ERR # 2 'ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว' 
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / usr / home / JdeBP / c มัด / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / c ", {mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0) 
stat (". ", {mode = drwxr-xr-x, inode = 120932 , size = 2, blksize = 131072}) = 0 (0x0)
/ usr / home / JdeBP / C
%

อย่างที่คุณเห็น: มันจะเรียกgetcwd()ก็ต่อเมื่อมันตรวจจับไม่ตรงกัน และมันสามารถถูกหลอกได้โดยการตั้งค่าPWDเป็นสตริงที่แน่นอนชื่อไดเรกทอรีเดียวกัน แต่โดยเส้นทางที่แตกต่างกัน

getcwd()ฟังก์ชั่นห้องสมุดเป็นเรื่องในสิทธิของตนเอง แต่เพื่อprécis:

  • แต่เดิมมันเป็นฟังก์ชั่นห้องสมุดที่สร้างชื่อพา ธ จากไดเรกทอรีการทำงานกลับไปที่รูทโดยพยายามค้นหาไดเรกทอรีทำงานใน..ไดเรกทอรีซ้ำ ๆ มันหยุดเมื่อมันไปถึงลูปที่ซึ่ง..เหมือนกับไดเร็กทอรีการทำงานหรือเมื่อมีข้อผิดพลาดพยายามเปิด..ขึ้นถัดไป นี่จะเป็นการเรียกใช้ระบบจำนวนมากภายใต้ฝาครอบ
  • ทุกวันนี้สถานการณ์มีความซับซ้อนขึ้นเล็กน้อย บน FreeBSD เช่น (นี้เป็นจริงสำหรับระบบปฏิบัติการอื่น ๆ เช่นกัน) ก็คือการเรียกระบบจริงอย่างที่คุณเห็นในการติดตามเรียกระบบที่กำหนดไว้ก่อนหน้านี้ การสำรวจเส้นทางทั้งหมดจากไดเรกทอรีการทำงาน vnode จนถึงรูทนั้นทำได้ในการเรียกใช้ระบบครั้งเดียวซึ่งใช้ประโยชน์จากสิ่งต่าง ๆ เช่นการเข้าถึงรหัสแคชของโหมดเคอร์เนลโดยตรงไปยังแคชรายการไดเรกทอรีเพื่อทำการค้นหาส่วนประกอบของชื่อพา ธ ได้อย่างมีประสิทธิภาพมากขึ้น

    อย่างไรก็ตามโปรดทราบว่าแม้ใน FreeBSD และระบบปฏิบัติการอื่น ๆ เคอร์เนลจะไม่ติดตามไดเรกทอรีการทำงานด้วยสตริง

การนำทางไปยัง..อีกเรื่องหนึ่งในสิทธิ์ของตนเอง ข้อกำหนดเบื้องต้นอื่น: แม้ว่าไดเรกทอรีตามอัตภาพ (แม้ว่าจะเป็นที่กล่าวถึงแล้ว แต่ก็ไม่จำเป็นต้องใช้) มีเนื้อหาจริง..ในโครงสร้างข้อมูลไดเรกทอรีบนดิสก์เคอร์เนลจะติดตามไดเรกทอรีหลักของแต่ละไดเรกทอรี vnode เองและสามารถนำทางไปยัง..vnode ของใด ๆ ไดเรกทอรีทำงาน สิ่งนี้ค่อนข้างซับซ้อนโดยจุดเมานท์และการเปลี่ยนกลไกรูทซึ่งอยู่นอกเหนือขอบเขตของคำตอบนี้

นอกเหนือ

ที่จริงแล้ว Windows NT ทำสิ่งที่คล้ายกัน มีไดเร็กทอรีการทำงานเดียวต่อกระบวนการที่กำหนดโดยการSetCurrentDirectory()เรียก API และติดตามต่อกระบวนการโดยเคอร์เนลผ่านตัวจัดการไฟล์ที่เปิด (ภายใน) ไปยังไดเรกทอรีนั้น และมีชุดของตัวแปรสภาพแวดล้อมที่โปรแกรม Win32 (ไม่ใช่แค่ตัวแปลคำสั่ง แต่โปรแกรม Win32 ทั้งหมด ) ใช้เพื่อติดตามชื่อของไดเรกทอรีทำงานหลายอัน (หนึ่งไดรฟ์ต่อไดรฟ์) ผนวกหรือเขียนทับพวกเขาเมื่อใดก็ตามที่พวกเขาเปลี่ยนไดเรกทอรี

โดยทั่วไปไม่เหมือนกับกรณีที่มีระบบปฏิบัติการ Unix และ Linux โปรแกรม Win32 จะไม่แสดงตัวแปรสภาพแวดล้อมเหล่านี้ให้กับผู้ใช้ บางครั้งเราสามารถเห็นพวกมันในระบบย่อยคล้าย Unix ที่ทำงานบน Windows NT รวมถึงโดยใช้คำสั่งของล่ามSETคำสั่งด้วยวิธีการเฉพาะ

อ่านเพิ่มเติม


1
นี่เป็นสิ่งที่เกินความคาดหมาย ขอบคุณและขอขอบคุณเป็นพิเศษสำหรับการอ่านเพิ่มเติม!
ReactingToAngularVues

doc.cat-v.org/plan_9/4th_edition/papers/lexnamesพูดคุยเกี่ยวกับบางส่วนของปัญหาที่มี..ในบริบทของแผน 9 ที่
icarus

@JdeBP: บางทีฉันหายไปบางอย่าง คุณพูดว่า“ ภายใน, ภายใน…, bash, …และ…, เชลล์ยังติดตามไดเรกทอรีทำงานโดยใช้การจัดการสตริงของตัวแปรสตริงภายใน …, มันจะปรับสตริงเพื่อลบ.และ..ส่วนประกอบและเพื่อไล่ลิงก์สัญลักษณ์แทนพวกมันด้วยชื่อ …ชื่อในตัวแปรสตริงภายในถูกติดตามโดยตัวแปรเชลล์ชื่อPWD…” (เพิ่มการเน้น) … (ต่อ)
G-Man พูดว่า 'Reinstate Monica'

(ต่อ) ... แต่ตัวอย่างของคุณแสดงPWD= …/bหลังcd bคำสั่งแม้ว่าbจะเป็นลิงก์สัญลักษณ์ไปa- ดังนั้นเชลล์จะไม่“ ไล่ล่า” a -> bลิงค์ คุณแปลผิดหรือฉันอ่านผิด?
G-Man กล่าวว่า 'Reinstate Monica'

ฉันแค่คัดสรรจุดด้านข้างแล้วชี้ไปที่รหัสเพื่อดูรายละเอียด ดูคู่มือเชลล์ต่างๆสำหรับเวลาและวิธีที่พวกเขาตัดสินใจไล่ล่าลิงก์สัญลักษณ์หรือไม่ Z เชลล์เรียกตัวเลือกเชลล์อย่างสะดวกว่าเป็นส่วนหนึ่งของสูตรการตัดสินใจ, CHASE_LINKS.
JdeBP

1

เคอร์เนลไม่ได้ติดตามไดเรกทอรีหรือชื่อไฟล์ ไฟล์หรือไดเรกทอรีถูกแสดงในเคอร์เนลโดยคู่ inode / อุปกรณ์ การเรียกของระบบเช่นchdir(), open()ฯลฯ ใช้พา ธ เป็นพารามิเตอร์ซึ่งสามารถเป็นแบบสัมบูรณ์ (เช่น/etc/passwd) หรือสัมพันธ์กับไดเรกทอรีปัจจุบัน (ตัวอย่าง: Documents, ..) เมื่อกระบวนการดำเนินchdir("Documents")การค้นหาจะทำDocumentsในไดเรกทอรีการทำงานปัจจุบันและไดเรกทอรีการทำงานของกระบวนการมีการปรับปรุงเพื่ออ้างถึงไดเรกทอรีนี้ จากมุมมองของเคอร์เนลไม่มีอะไรพิเศษในชื่อ ".. " มันเป็นเพียงข้อตกลงในระบบไฟล์ที่..อ้างถึงไดเรกทอรีหลัก

getcwd()ฟังก์ชั่นไม่ได้เป็นสายระบบ แต่ฟังก์ชั่นห้องสมุดที่มีการทำงานทางขึ้นไปยังไดเรกทอรีรากบันทึกชื่อของส่วนประกอบเส้นทางในทาง


0

ที่น่าสนใจประเพณีcd ..นั้นง่ายกว่าpwdมาก ๆ ไดเร็กทอรีที่..มีชื่อถูกวางไว้อย่างชัดเจนในระบบไฟล์ ระบบติดตามอุปกรณ์ / inode ของไดเรกทอรีปัจจุบันดังนั้นcd ..หรือมากกว่านั้นการเรียกระบบchdir("..")เพียงแค่สร้างชื่อ ".. " ในไฟล์ที่เป็นของ inode ของไดเรกทอรีปัจจุบันและเปลี่ยนอุปกรณ์ / inode ของไดเรกทอรีปัจจุบันเป็น พบค่าที่นั่น

pwd(แม่นยำยิ่งขึ้น/bin/pwd) ติดตาม..ลิงค์อย่างต่อเนื่องและอ่านไดเรกทอรีที่เกี่ยวข้องจนกว่าจะหา inode ที่มาจากนั้นรวบรวมรายชื่อเหล่านั้นในสิ่งที่ตรงกันข้ามจนกว่าจะถึงไดเรกทอรีราก (สะดุดตาไม่ได้มี..รายการ)

ตอนนี้เป็นพฤติกรรมพื้นฐานระดับต่ำดั้งเดิม คำสั่งเชลล์ที่เกิดขึ้นจริงpwdแทนที่จะพึ่งพาเทคนิคที่หลากหลายในการแคชชื่อพา ธ ปัจจุบัน แต่ที่แกนกลางมันเป็นเพียงไอโหนดที่เป็นที่รู้จักกันจริง นั่นหมายความว่าเมื่อใช้ symlink สำหรับการนำทางไดเรกทอรีชื่อไดเรกทอรีงานปัจจุบันของเชลล์ปัจจุบันและระบบ/bin/pwdอาจเบี่ยงเบนไป

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