Standar shell POSIX mengatakan di situs ini
http://pubs.opengroup.org/onlinepubs/9699919799/
tentang bagaimana shell digunakan PATH
untuk mencari file yang dapat dieksekusi:
"Daftar harus dicari dari awal hingga akhir, menerapkan nama file untuk setiap awalan, sampai file yang dapat dieksekusi dengan nama yang ditentukan dan izin eksekusi yang sesuai ditemukan."
Nah, ini bukan bagaimana ini tampaknya bekerja dalam implementasi POSIX nyata:
man which
mengatakan:
"Mengembalikan nama path file (atau tautan) yang akan dieksekusi di lingkungan saat ini, seandainya argumennya diberikan sebagai perintah dalam shell yang benar-benar sesuai POSIX. Ia melakukan ini dengan mencari PATH untuk file yang dapat dieksekusi yang cocok dengan nama-nama argumen. Itu tidak mengikuti tautan simbolis. "
OK, mari kita lihat situasi ini:
$ pwd
/home/mark
$ echo $PATH
/home/mark/bin:
...
$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar
OK, di sini ada tautan simbolik PATH
dengan nama yang benar, dan dilaporkan ls
dapat dieksekusi.
which
tidak melihatnya sama sekali, tetapi hanya tertarik pada apa yang ditunjukkannya.
Terlepas dari kenyataan bahwa keduanya man which
secara eksplisit mengatakan bahwa itu tidak mengikuti tautan simbolik (dan memang kita melihatnya tidak, karena which foobar
tidak mencetak foobar1
), dan juga dokumentasi shell POSIX yang dikutip di atas, tidak pernah menyebutkan symlink berikut dalam PATH
algoritma.
Jadi, apakah which
kerang yang ada salah, atau apakah saya tidak memahami dokumentasinya?
UNTUK MEMPERJELAS:
Saya tahu dan bisa menjelaskan perilaku yang ada. Pertanyaan saya bukanlah "bagaimana cara kerjanya?". Itu saya tahu.
Pertanyaan saya adalah tentang dokumentasi: di mana kesalahan saya dalam mengikuti dokumentasi yang saya kutip. Atau apakah dokumentasinya salah?
MOTIVASI: Mengapa saya peduli?
Ya, saya pelaksana. Pelaksana yang berbeda memiliki persyaratan yang berbeda pula. Bagi saya, persyaratannya adalah bahwa kata dari standar POSIX saat ini HARUS diikuti secara TEPAT (atau, lebih tepatnya, yang terbaik, karena, standarnya sendiri agak buggy). Seperti itu adalah firman Tuhan.
Sekarang, kata-kata standarnya cukup jelas - symlink berikut tidak disebutkan, di mana di banyak tempat lain, disebutkan di mana itu perlu dilakukan. Jadi dalam hal ini, jangan.
Namun, saya selalu mengecek bagaimana dash
dan bash
berperilaku, hanya untuk memastikan. Sekarang tentu saja, ada sedikit masalah di sini juga, dash
meskipun itu disebut sebagai POSIX, memiliki banyak bug kecil yang sesuai dengan POSIX. bash
, Saya belum menemukan bug dengan POSIX, tapi ... bash sebenarnya bukan POSIX, itu lebih dari itu.
Jadi begitulah. Itu sebabnya saya peduli.
sumber
$PATH
dapat berisi symlink. Cobawhich sh
.$PATH
tidak memiliki symlink.lstat(2)
), mengikuti mereka biasanya tidak dinyatakan. Misalnya, deskripsiopen(2)
hanya menyebutkan symlink ketika berbicara tentang perilakuO_CREAT | O_EXCL
. Tidak perlu menyatakan bahwa file target akan dibuka.Jawaban:
Izin symlink itu sendiri tidak relevan. Anda bahkan tidak dapat mengubahnya jika Anda mencobanya.
Yang penting adalah izin dari file yang mendasarinya.
Anda boleh memiliki direktori di PATH Anda termasuk symlink ke executable. Bahkan, kemungkinan banyak executable di PATH Anda adalah symlink. Sebagai contoh, pada sistem seperti debian / ubuntu:
Dokumentasi
Dari
man chmod
:Contoh
Shell memiliki tes
-x
,, untuk menentukan apakah suatu file dapat dieksekusi. Mari kita coba itu:Jadi, seperti yang Anda temukan
which
, shell tidak menganggap softlink dapat dieksekusi kecuali file yang mendasarinya dapat dieksekusi.Bagaimana cara kerjanya
Pada sistem Debian,
which
adalah skrip shell. Bagian kode yang relevan adalah:Seperti yang Anda lihat, ini menggunakan
-x
tes untuk menentukan apakah file dapat dieksekusi.POSIX menentukan
-x
tes sebagai berikut:Jadi, POSIX cek apa pathname resolve ke. Dengan kata lain, ia menerima symlink.
Fungsi POSIX exec
Fungsi POSIX exec mengikuti symlinks. Panjang lebar POSIX berlangsung untuk menentukan kondisi kesalahan yang mungkin dilaporkan jika symlink melingkar atau terlalu dalam, seperti:
sumber
which
adalah skrip shell. Jadi, sepertinya hanya menggunakan-x
tes yang saya tunjukkan. Menurut POSIX,-x
menguji apakah file "diselesaikan" ke file executable. Jika Anda melihat sesuatu yang berbeda, di mana Anda melihat?which
bekerja, atau apakah itu-x
atau sesuatu yang lain. Saya tertarik untuk mengetahui di mana saya tidak mengikuti dengan benar dokumentasi yang saya kutip.exec
fungsi berikut symlink. Itu tampaknya membuat cukup jelas bahwa file symlink dapat dieksekusi di bawah POSIX.man which
yang mengatakan "Itu tidak mengkanoniskan nama jalur." Itu tidak berarti tidak mengikuti tautan. Itu hanya berarti, seperti yang Anda amati, bahwa itu tidak "mengkanoniskan" nama-nama itu.Dalam hal ini symlink diikuti secara transparan, tanpa mengkanoniskan jalur terakhir. Dengan kata lain,
which
tidak peduli apakah/home/mark/bin
itu symlink atau tidak. Yang penting adalah apakah file itu/home/mark/bin/foobar
ada atau tidak. Tidak perlu meratakan symlink secara manual di sepanjang jalur - OS dapat melakukannya sendiri.Dan memang, ketika
which
ditanya tentang informasi file/home/mark/bin/foobar
, OS pemberitahuan/home/mark/bin
menjadi symlink, mengikutinya, dan berhasil menemukanfoobar
di direktori target.Ini adalah perilaku default kecuali jika program menggunakan
open(…, O_NOFOLLOW)
ataufstatat(…, AT_SYMLINK_NOFOLLOW)
untuk mengakses file.[komentar bergabung]
Meskipun Anda mengatakan bahwa shell utilitas melakukannya atas dasar kasus per kasus, tidak sama dengan syscalls kernel: semua panggilan terkait berkas lakukan mengikuti symlink secara default, kecuali "nofollow" bendera diberikan. (Bahkan lstat mengikuti symlink di semua komponen jalur kecuali yang terakhir.)
Ketika spesifikasi tidak secara eksplisit menyebutkan apa yang harus dilakukan dengan symlink, itu menyiratkan perilaku default yang akan digunakan. Yaitu, shell yang mengikuti algoritme lintasan yang lebih baru menyelesaikan symlink secara manual juga tidak secara eksplisit memilih keluar dari OS melakukan hal yang sama. (Itu hanya menyatukan setiap komponen $ PATH dengan nama yang dapat dieksekusi.)
Ketika halaman manual mana (1) mengatakan tidak mengikuti symlink, itu bisa berarti beberapa hal, tetapi versi GNU coreutils menyatakannya seperti ini:
Itu jauh lebih sempit dalam ruang lingkup - itu hanya berarti
which
tidak akan mencoba secara manual mengkanonik semua jalur untuk menghilangkan duplikat, tetapi itu tidak menyiratkan bahwa alat akan memilih keluar dari symlink berikut oleh OS pada umumnya. Misalnya, jika/bin
merupakan symlink ke/usr/bin
, menjalankanwhich -a sh
akan mengembalikan keduanya/bin/sh
dan/usr/bin/sh
.sumber
which
Halaman manual GNU menyatakannya secara berbeda: "Yang akan menganggap dua direktori yang sama berbeda ketika salah satu dari mereka berisi path dengan tautan simbolik."execve("/home/mark/bin/foobar", …)
, semua symlink akan diikuti.execve
argumen, sebenarnya, dalam implementasi saya ituexecl()
, hal yang sama. Silakan jika Anda memasukkan ini dalam jawaban Anda, saya akan menerimanya.Shell sesuai dengan dokumentasinya karena mengikuti aturan untuk resolusi pathname.
which
sesuai dengan dokumentasinya. Keduanya melakukan hal yang sedikit berbeda.Output dari
which
adalah nama file path dan, bukan path ke apa yang ditunjuk symlink. Ini dijabarkan dalam halaman manual.Ketika sebuah perintah dieksekusi, tautannya "diikuti" sesuai Bagian 4.13 Resolusi Pathname di dalamnya . Klausa yang relevan untuk mengeksekusi file adalah:
sumber