Perché posso cat / dev?


41

Posso cat /dev, posso ls /dev, non posso less /dev. Perché catmi consente catquesta directory ma non altre directory?

Immagine di questo comportamento in zsh.


@KamilMaciorowski, ecco l'output e neofetchper tua informazione :) i.imgur.com/3azpnDt.png
haboutnnah

Risposte:


43

Storicamente (fino a V7 UNIX, o intorno al 1979) la readchiamata di sistema ha funzionato sia su file che su directory. readsu una directory restituirebbe una struttura dati semplice che un programma utente analizzerebbe per ottenere le voci della directory. In effetti, lo lsstrumento V7 ha fatto esattamente questo: readsu una directory, analizza la struttura di dati risultante, emette in un formato elenco strutturato.

Man mano che i filesystem diventavano più complessi, questa "semplice" struttura di dati diventava più complicata, al punto in cui readdirveniva aggiunta una funzione di libreria per aiutare i programmi a analizzare l'output di read(directory). Diversi sistemi e filesystem potrebbero avere diversi formati su disco, il che stava diventando complicato.

Quando Sun ha introdotto Network File System (NFS), ha voluto estrarre completamente la struttura delle directory su disco. Invece di rendere il loro read(directory)ritorno una rappresentazione indipendente dalla piattaforma della directory, tuttavia, hanno aggiunto una nuova chiamata di sistema getdirents- e sono stati bannati readsu directory montate in rete. Questa chiamata di sistema è stata rapidamente adattata per funzionare su tutte le directory in varie versioni UNIX, rendendolo il modo predefinito per ottenere il contenuto delle directory. (Storia sottratta da https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Poiché readdirora è il modo predefinito di leggere le directory, di read(directory)solito non è implementato (restituendo -EISDIR) sulla maggior parte dei sistemi operativi moderni (QNX, ad esempio, è un'eccezione notevole che implementa readdircome read(directory)). Tuttavia, con il design del "filesystem virtuale" nella maggior parte dei kernel moderni, dipende dal singolo filesystem se la lettura di una directory funziona o meno.

E infatti, su macOS, il devfsfilesystem alla base del /devmountpoint supporta davvero la lettura ( 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);

Questo chiama esplicitamente READDIRse si tenta di leggere /dev(la lettura dei file in /devè gestita da una funzione separata - devfsspec_read). Quindi, se un programma chiama la readchiamata di sistema /dev, avrà successo e otterrà un elenco di directory!

Questa è effettivamente una funzionalità che è un blocco dai primissimi giorni di UNIX e che non è stata toccata da molto tempo. Una parte di me sospetta che questo sia stato mantenuto per qualche motivo di compatibilità all'indietro, ma potrebbe essere altrettanto facilmente il fatto che nessuno si preoccupa abbastanza di rimuovere la funzionalità poiché non sta davvero danneggiando nulla.


Probabilmente quest'ultimo, visto che è stato rimosso dalla maggior parte delle directory.
user253751

36

Meno è un visualizzatore di file di testo, cat è uno strumento per copiare dati arbitrari. Quindi meno esegue il proprio controllo per assicurarsi che non si stia aprendo qualcosa che avrà enormi quantità di dati o si comporterà in modo molto strano. D'altra parte, cat non ha alcun controllo del genere: se il kernel ti consente di aprire qualcosa (anche se è una pipe o un dispositivo o qualcosa di peggio), cat lo leggerà.

Quindi perché il sistema operativo consente a cat di aprire le directory? Tradizionalmente nei sistemi in stile BSD tutte le directory potevano essere lette come file, ed era così che i programmi avrebbero elencato una directory in primo luogo: semplicemente interpretando le strutture dirette memorizzate sul disco.

In seguito, quelle strutture su disco iniziarono a divergere dal dirent usato dal kernel: dove prima una directory era un elenco lineare, in seguito i filesystem iniziarono a usare hashtable, B-tree e così via. Quindi leggere le directory direttamente non era più semplice: il kernel ha sviluppato funzioni dedicate per questo. (Non sono sicuro se questo fosse il motivo principale o se siano stati aggiunti principalmente per altri motivi come la memorizzazione nella cache.)

Alcuni sistemi BSD continuano a consentire di aprire tutte le directory per la lettura; Non so se ti danno i dati grezzi dal disco, o se invece restituiscono un elenco diretto emulato, o se lasciano decidere al driver del filesystem.

Quindi forse macOS è uno di quei sistemi operativi in ​​cui il kernel lo consente finché il filesystem fornisce i dati. E la differenza è che /devè su un devfsfilesystem che è stato scritto per consentire questo nei primi tempi, mentre /è su un filesystem APFS che ha omesso questa funzione come non necessaria nei tempi moderni.

Disclaimer: in realtà non ho fatto ricerche su BSD o macOS. Lo sto solo alando.


Questo sembra avere senso. Ci sono altre sezioni di archiviazione che differiscono dal filesystem del sistema operativo standard? Ho pensato di /etcsì, quindi l'ho usato come punto di riferimento.
haboutnnah,

2
Al contrario, generalmente / etc è solo una cartella normale che contiene file regolari. Ci possono essere altri filesystem virtuali anche se - corsa mounto /sbin/mountper vedere cosa sta attualmente montato dove.
Grawity

Hai ragione! Vedi questo: i.imgur.com/pcVpo1o.png
haboutnnah

Questo è davvero pulito @grawity, i.imgur.com/8QuR0FK.png
haboutnnah,

6
@haboutnnah Il tuo screenshot conferma che si /devtratta di un file system virtuale che utilizza il devfsdriver mentre /etcfa parte del /file system che utilizza il apfsdriver. Quindi il motivo catleggerà l'uno e non l'altro è una differenza tra i driver apfse devfs.
Kasperd,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.