Posso cat /dev
, posso ls /dev
, non posso less /dev
. Perché cat
mi consente cat
questa directory ma non altre directory?
Posso cat /dev
, posso ls /dev
, non posso less /dev
. Perché cat
mi consente cat
questa directory ma non altre directory?
Risposte:
Storicamente (fino a V7 UNIX, o intorno al 1979) la read
chiamata di sistema ha funzionato sia su file che su directory. read
su una directory restituirebbe una struttura dati semplice che un programma utente analizzerebbe per ottenere le voci della directory. In effetti, lo ls
strumento V7 ha fatto esattamente questo: read
su 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 readdir
veniva 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 read
su 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é readdir
ora è 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 readdir
come 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 devfs
filesystem alla base del /dev
mountpoint 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 READDIR
se si tenta di leggere /dev
(la lettura dei file in /dev
è gestita da una funzione separata - devfsspec_read
). Quindi, se un programma chiama la read
chiamata 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.
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 devfs
filesystem 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.
/etc
sì, quindi l'ho usato come punto di riferimento.
mount
o /sbin/mount
per vedere cosa sta attualmente montato dove.
/dev
tratta di un file system virtuale che utilizza il devfs
driver mentre /etc
fa parte del /
file system che utilizza il apfs
driver. Quindi il motivo cat
leggerà l'uno e non l'altro è una differenza tra i driver apfs
e devfs
.
neofetch
per tua informazione :) i.imgur.com/3azpnDt.png