Mengapa saya bisa menjadi kucing?

41

Saya bisa cat /dev, saya bisa ls /dev, saya tidak bisa less /dev. Mengapa catsaya membiarkan catdirektori ini tetapi tidak ada direktori lain?

Gambar perilaku ini di zsh.

haboutnnah
sumber
@KamilMaciorowski, ini output dan neofetchinformasi Anda :) i.imgur.com/3azpnDt.png
haboutnnah

Jawaban:

43

Secara historis (hingga V7 UNIX, atau sekitar 1979) readpemanggilan sistem bekerja pada file dan direktori. readpada direktori akan mengembalikan struktur data sederhana yang akan diuraikan oleh program pengguna untuk mendapatkan entri direktori. Memang, lsalat V7 melakukan hal ini - readpada direktori, parsing struktur data yang dihasilkan, output dalam format daftar terstruktur.

Ketika filesystem menjadi lebih kompleks, struktur data "sederhana" ini menjadi lebih rumit, ke titik di mana readdirfungsi perpustakaan ditambahkan untuk membantu program mem-parsing output read(directory). Sistem dan sistem file yang berbeda mungkin memiliki format pada disk yang berbeda, yang semakin rumit.

Ketika Sun memperkenalkan Network File System (NFS), mereka ingin sepenuhnya menghilangkan struktur direktori on-disk. Alih-alih membuat mereka read(directory)menjadi representasi platform-independen dari direktori, namun, mereka menambahkan panggilan sistem baru - getdirents- dan dilarang readpada direktori yang dipasang di jaringan. Panggilan sistem ini dengan cepat diadaptasi untuk bekerja pada semua direktori dalam berbagai rasa UNIX, menjadikannya cara standar untuk mendapatkan isi direktori. (Sejarah disarikan dari https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Karena readdirsekarang merupakan cara standar untuk membaca direktori, read(directory)biasanya tidak diimplementasikan (kembali -EISDIR) pada kebanyakan OS modern (QNX, misalnya, adalah pengecualian yang diterapkan readdirsebagai read(directory)). Namun, dengan desain "sistem file virtual" di sebagian besar kernel modern, sebenarnya tergantung pada sistem file individual apakah membaca direktori berfungsi atau tidak.

Dan memang, pada macOS, sistem devfsfile yang mendasari /devmountpoint benar-benar mendukung pembacaan ( https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629 ) :

static int
devfs_read(struct vnop_read_args *ap)
{
        devnode_t * dn_p = VTODN(ap->a_vp);

    switch (ap->a_vp->v_type) {
      case VDIR: {
          dn_p->dn_access = 1;

          return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);

Ini secara eksplisit memanggil READDIRjika Anda mencoba membaca /dev(membaca file di bawah /devditangani oleh fungsi terpisah - devfsspec_read). Jadi, jika suatu program memanggil readsistem panggilan aktif /dev, itu akan berhasil dan mendapatkan daftar direktori!

Ini adalah fitur yang efektif yang merupakan peninggalan dari hari-hari awal UNIX, dan yang belum tersentuh dalam waktu yang sangat lama. Sebagian dari saya curiga bahwa ini sedang disimpan karena alasan kompatibilitas ke belakang, tetapi bisa dengan mudah menjadi kenyataan bahwa tidak ada yang cukup peduli untuk menghapus fitur karena tidak benar-benar menyakiti apa pun.

nneonneo
sumber
Mungkin yang terakhir, mengingat telah dihapus dari sebagian besar direktori.
user253751
36

Less adalah penampil file teks, cat adalah alat untuk menyalin data sewenang-wenang. Jadi, kurang melakukan pemeriksaan sendiri untuk memastikan Anda tidak membuka sesuatu yang akan memiliki data dalam jumlah besar atau berperilaku sangat aneh. Di sisi lain, cat tidak memiliki pemeriksaan seperti itu sama sekali - jika kernel memungkinkan Anda membuka sesuatu (bahkan jika itu pipa atau perangkat atau sesuatu yang lebih buruk), cat akan membacanya.

Jadi mengapa OS memungkinkan kucing untuk membuka direktori? Secara tradisional dalam sistem BSD-style, semua direktori dapat dibaca sebagai file, dan begitulah program akan membuat daftar direktori di tempat pertama: dengan hanya menafsirkan struktur dirent yang tersimpan pada disk.

Kemudian, struktur-struktur pada disk mulai menyimpang dari direktori yang digunakan oleh kernel: di mana sebelumnya direktori adalah daftar linear, sistem file kemudian mulai menggunakan hashtable, B-tree, dan sebagainya. Jadi membaca direktori secara langsung tidak mudah lagi - kernel mengembangkan fungsi khusus untuk ini. (Saya tidak yakin apakah itu alasan utama, atau apakah mereka terutama ditambahkan karena alasan lain seperti caching.)

Beberapa sistem BSD terus membiarkan Anda membuka semua direktori untuk dibaca; Saya tidak tahu apakah mereka memberi Anda data mentah dari disk, atau apakah mereka mengembalikan daftar direktori yang ditiru, atau apakah mereka membiarkan driver sistem file memutuskan.

Jadi mungkin macOS adalah salah satu dari sistem operasi di mana kernel memungkinkannya selama sistem file menyediakan data. Dan perbedaannya adalah /devpada devfssistem file yang ditulis untuk memungkinkan hal ini pada hari-hari awal, sementara /pada sistem file APFS yang menghilangkan fitur ini sebagai tidak perlu di zaman modern.

Penafian: Saya belum benar-benar melakukan penelitian tentang BSD atau macOS. Saya hanya mengayunkannya.

grawity
sumber
Ini sepertinya masuk akal. Apakah ada bagian penyimpanan lain yang berbeda dari sistem file OS standar? Saya berasumsi /etcakan, jadi saya menggunakan itu sebagai tolok ukur saya.
haboutnnah
2
Sebaliknya, umumnya / etc hanyalah folder biasa yang berisi file-file biasa. Ada mungkin menjadi filesystem virtual lainnya meskipun - run mountatau /sbin/mountuntuk melihat apa yang sedang dipasang di mana.
grawity
Kamu benar! Lihat ini: i.imgur.com/pcVpo1o.png
haboutnnah
Ini benar-benar rapi @grawity
haboutnnah
6
@haboutnnah Tangkapan layar Anda mengonfirmasi bahwa itu /devadalah sistem file virtual menggunakan devfsdriver sedangkan itu /etcadalah bagian dari /sistem file menggunakan apfsdriver. Jadi alasannya catakan membaca satu dan bukan yang lain adalah perbedaan antara apfsdan devfsdriver.
kasperd