Bagaimana cara Unix melacak direktori kerja pengguna saat menavigasi sistem file?

29

Katakanlah saya masuk ke shell pada sistem unix dan mulai mengetuk perintah. Saya awalnya mulai di direktori home pengguna saya ~. Saya mungkin dari sana cdke direktori Documents.

Perintah untuk mengubah direktori kerja di sini sangat sederhana secara intuitif untuk dipahami: simpul induk memiliki daftar simpul anak yang dapat diakses, dan mungkin ia menggunakan varian (yang dioptimalkan) dari pencarian untuk menemukan keberadaan simpul anak dengan beri nama pengguna yang dimasukkan, dan direktori kerja kemudian "diubah" untuk mencocokkan ini - koreksi saya jika saya salah di sana. Bahkan mungkin lebih sederhana bahwa shell cukup "naif" mencoba untuk mencoba mengakses direktori persis seperti yang diinginkan pengguna dan ketika sistem file mengembalikan beberapa jenis kesalahan, shell menampilkan respons yang sesuai.

Apa yang saya tertarik adalah bagaimana proses yang sama bekerja ketika saya menavigasi direktori, yaitu ke orang tua, atau orang tua orang tua.

Mengingat lokasi saya yang tidak diketahui, mungkin "buta" Documents, salah satu dari banyak direktori di seluruh pohon sistem file dengan nama itu, bagaimana cara Unix menentukan di mana saya harus ditempatkan selanjutnya? Apakah itu merujuk pwddan memeriksanya? Jika ya, bagaimana pwdmelacak kondisi navigasi saat ini?

ReactingToAngularVues
sumber
1
Lihat juga Rekursi tautan simbolik - apa yang membuatnya "diatur ulang"? di mana banyak hal itu dijelaskan
Stéphane Chazelas

Jawaban:

76

Jawaban lainnya adalah penyederhanaan yang berlebihan, masing-masing hanya menyajikan sebagian dari cerita, dan salah dalam beberapa hal.

Ada dua cara direktori kerja dilacak:

  • Untuk setiap proses, dalam struktur data ruang-kernel yang mewakili proses itu, kernel menyimpan dua referensi vnode ke vnodes direktori kerja dan direktori root untuk proses itu. Referensi sebelumnya diatur oleh chdir()dan fchdir()panggilan sistem, yang terakhir oleh chroot(). Orang dapat melihatnya secara tidak langsung di /procsistem operasi Linux atau melalui fstatperintah di FreeBSD dan sejenisnya:

    % fstat -p $$ | head -n 5
    MODE PENGGUNA CMD PID FD MOUNT INUM SZ | DV R / W
    JdeBP zsh 92648 teks / 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
    % 

    Ketika resolusi pathname beroperasi, itu dimulai pada satu atau yang lain dari vnodes yang dirujuk, sesuai dengan apakah path relatif atau absolut. (Ada keluarga …at()panggilan sistem yang memungkinkan resolusi pathname dimulai pada vnode yang dirujuk oleh deskriptor file open (direktori) sebagai opsi ketiga.)

    Dalam microkernel Unices, struktur datanya ada di ruang aplikasi, tetapi prinsip memegang referensi terbuka untuk direktori ini tetap sama.

  • Secara internal, di dalam shell seperti Z, Korn, Bourne Again, C, dan shell Almquist, shell juga melacak direktori kerja menggunakan manipulasi string dari variabel string internal. Ini melakukan ini setiap kali ada alasan untuk menelepon chdir().

    Jika seseorang mengubah nama path relatif, ia memanipulasi string untuk menambahkan nama itu. Jika seseorang mengubah nama path absolut, itu menggantikan string dengan nama baru. Dalam kedua kasus, itu menyesuaikan string untuk menghapus .dan ..komponen dan untuk mengejar tautan simbolik menggantikannya dengan nama tertaut mereka. ( Berikut adalah kode shell Z untuk itu , misalnya.)

    Nama dalam variabel string internal dilacak oleh variabel shell bernama PWD(atau cwddalam shell C). Ini secara konvensional diekspor sebagai variabel lingkungan (bernama PWD) ke program yang dihasilkan oleh shell.

Dua metode pelacakan hal ini diungkapkan oleh opsi -Pdan -Lke cddan pwdperintah built-in shell, dan oleh perbedaan antara pwdperintah built-in shell dan baik /bin/pwdperintah dan perintah built-in pwddari hal-hal seperti (antara lain) VIM dan 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
% 

Seperti yang Anda lihat: mendapatkan direktori kerja "logis" adalah masalah melihat PWDvariabel shell (atau variabel lingkungan jika seseorang bukan program shell); sedangkan memperoleh direktori kerja "fisik" adalah masalah memanggil getcwd()fungsi perpustakaan.

Pengoperasian /bin/pwdprogram ketika -Lopsi digunakan agak halus. Itu tidak bisa mempercayai nilai PWDvariabel lingkungan yang telah diwarisi. Lagi pula, itu tidak perlu dipanggil oleh shell dan program intervensi mungkin tidak menerapkan mekanisme shell membuat PWDvariabel lingkungan selalu melacak nama direktori kerja. Atau seseorang dapat melakukan apa yang saya lakukan di sana.

Jadi yang dilakukannya adalah (seperti standar POSIX mengatakan) memeriksa bahwa nama yang diberikan PWDmenghasilkan hal yang sama dengan nama ., seperti yang dapat dilihat dengan jejak panggilan sistem:

% ln -sac 
% (cd b; truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / b", { 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 / b
% (cd b; PWD = / usr / local / etc truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, size = 158, blksize = 10240}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / halo / ada truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ hello / there", 0x7fffffffe730) ERR # 2 'Tidak ada file atau direktori' 
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / usr / home / JdeBP / c truss / 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
%

Seperti yang Anda lihat: itu hanya memanggil getcwd()jika mendeteksi ketidakcocokan; dan itu bisa dibodohi dengan menetapkan PWDke string yang memang menamai direktori yang sama, tetapi dengan rute yang berbeda.

Fungsi getcwd()perpustakaan adalah subjek dalam dirinya sendiri. Tetapi untuk précis:

  • Awalnya itu murni fungsi perpustakaan, yang membangun pathname dari direktori kerja kembali ke root dengan berulang kali mencoba mencari direktori kerja di ..direktori. Itu berhenti ketika mencapai satu lingkaran di mana ..sama dengan direktori kerjanya atau ketika ada kesalahan mencoba untuk membuka berikutnya ... Ini akan menjadi banyak panggilan sistem di bawah selimut.
  • Saat ini situasinya sedikit lebih kompleks. Pada FreeBSD, misalnya (ini berlaku untuk sistem operasi lain juga), itu adalah panggilan sistem yang benar, seperti yang Anda lihat di jejak panggilan sistem yang diberikan sebelumnya. Semua traversal dari direktori kerja vnode hingga root dilakukan dalam satu system call, yang mengambil keuntungan dari hal-hal seperti akses langsung kode mode kernel ke cache entri direktori untuk melakukan pencarian komponen pathname jauh lebih efisien.

    Namun, perhatikan bahwa bahkan pada FreeBSD dan sistem operasi lainnya, kernel tidak melacak direktori yang berfungsi dengan sebuah string.

Menavigasi ke ..lagi adalah subjek dalam dirinya sendiri. Précis lain: Walaupun direktori secara konvensional (walaupun, seperti yang sudah disinggung, ini tidak diperlukan) mengandung aktual ..dalam struktur data direktori pada disk, kernel melacak direktori induk dari setiap direktori vnode itu sendiri dan dengan demikian dapat menavigasi ke ..vnode dari sembarang direktori kerja. Ini agak rumit oleh mountpoint dan mengubah mekanisme root, yang berada di luar cakupan jawaban ini.

Ke samping

Windows NT sebenarnya melakukan hal serupa. Ada satu direktori kerja per proses, yang ditetapkan oleh SetCurrentDirectory()panggilan API dan dilacak per proses oleh kernel melalui sebuah pegangan file terbuka (internal) ke direktori itu; dan ada satu set variabel lingkungan yang digunakan oleh program Win32 (bukan hanya penerjemah perintah, tetapi semua program Win32) untuk melacak nama beberapa direktori kerja (satu per drive), menambahkan atau menimpa mereka setiap kali mereka mengubah direktori.

Secara konvensional, tidak seperti halnya dengan sistem operasi Unix dan Linux, program Win32 tidak menampilkan variabel lingkungan ini kepada pengguna. Seseorang kadang-kadang dapat melihatnya dalam subsistem mirip Unix yang berjalan pada Windows NT, juga, dengan menggunakan perintah interpreter SETperintah dengan cara tertentu.

Bacaan lebih lanjut

JdeBP
sumber
1
Ini jauh lebih dari yang pernah saya duga. Terima kasih, dan terima kasih ekstra untuk bacaan lebih lanjut!
ReactingToAngularVues
doc.cat-v.org/plan_9/4th_edition/papers/lexnames berbicara tentang beberapa masalah ..dalam konteks Plan9,
icarus
@ JdeBP: Mungkin saya melewatkan sesuatu. Anda mengatakan, "Secara internal, di dalam ..., bash, ... dan ..., shell juga melacak direktori kerja menggunakan manipulasi string dari variabel string internal. ..., ia menyesuaikan string untuk dihapus .dan ..komponen dan untuk mengejar tautan simbolik menggantikannya dengan nama tertaut mereka. ... Nama dalam variabel string internal dilacak oleh variabel shell bernama PWD... "(penekanan ditambahkan). ... (Lanjutan)
G-Man Mengatakan 'Reinstate Monica'
(Lanjutkan) ... Tapi contoh Anda menunjukkan PWD= …/bsetelah cd bperintah, meskipun bmerupakan tautan simbolis ke a- jadi shell tidak “memburu” a -> btautan. Apakah Anda salah menyatakan, atau apakah saya salah membaca?
G-Man Mengatakan 'Reinstate Monica'
Saya hanya menutupi titik sisi, dan mengarahkan Anda ke kode untuk detail. Lihat berbagai manual kerang untuk kapan dan bagaimana mereka memutuskan untuk mengejar tautan simbolis atau tidak. Shell Z dengan mudah memanggil opsi shellnya yang merupakan salah satu bagian dari formula keputusan CHASE_LINKS,.
JdeBP
1

Kernel tidak melacak direktori atau nama file; file atau direktori diwakili dalam kernel oleh pasangan inode / perangkat. Sistem panggilan seperti chdir(), open(), dll mengambil jalan sebagai parameter, yang dapat absolut (misalnya /etc/passwd), atau relatif ke direktori saat ini (contoh: Documents, ..). Ketika proses dijalankan chdir("Documents"), pencarian dilakukan Documentsdi dalam direktori kerja saat ini, dan direktori kerja proses diperbarui untuk merujuk ke direktori ini. Dari perspektif kernel, tidak ada yang istimewa dalam nama "..", itu hanya sebuah konvensi dalam sistem file yang ..merujuk ke direktori induk.

The getcwd()fungsi bukan panggilan sistem, tetapi fungsi perpustakaan yang harus bekerja jalan sampai ke direktori root, merekam nama-nama komponen jalur di jalan.

Johan Myréen
sumber
0

Menariknya, secara tradisional cd ..jauh lebih sederhana daripada pwd. Direktori bernama ..ditempatkan secara eksplisit ke dalam sistem file. Sistem melacak perangkat / inode dari direktori saat ini, jadi cd ..atau lebih tepatnya panggilan sistem chdir("..")hanya memerlukan mencari nama ".." dalam file milik inode direktori saat ini dan mengubah perangkat direktori saat ini / inode ke nilai ditemukan di sana.

pwd(lebih akurat /bin/pwd) mengikuti ..tautan secara berturut-turut dan membaca direktori masing-masing hingga menemukan inode dari mana asalnya, menyusun daftar nama-nama itu secara terbalik hingga mencapai direktori root (terutama tidak mengandung ..entri).

Sekarang ini adalah perilaku dasar tingkat rendah asli. Perintah shell yang sebenarnya pwdbukan mengandalkan berbagai teknik caching nama jalur saat ini. Tetapi pada intinya, hanya inode-nya saja yang benar-benar diketahui. Itu menyiratkan bahwa sekali symlink digunakan untuk menavigasi direktori, pengertian nama direktori kerja saat ini dari shell saat ini dan sistem /bin/pwdmungkin berbeda.


sumber