Je peux cat /dev
, je peux ls /dev
, je ne peux pas less /dev
. Pourquoi cat
me laisser cat
ce répertoire mais pas d'autres répertoires?
Je peux cat /dev
, je peux ls /dev
, je ne peux pas less /dev
. Pourquoi cat
me laisser cat
ce répertoire mais pas d'autres répertoires?
Réponses:
Historiquement (jusqu’à VIX UNIX ou autour de 1979), l’ read
appel système fonctionnait à la fois pour les fichiers et les répertoires. read
sur un répertoire renverrait une simple structure de données qu'un programme utilisateur analyserait pour obtenir les entrées du répertoire. En effet, l' ls
outil V7 a fait exactement cela - read
sur un répertoire, analyser la structure de données résultante, sortie dans un format de liste structurée.
À mesure que les systèmes de fichiers se complexifiaient, cette structure de données "simple" devenait de plus en plus compliquée, au point qu'une readdir
fonction de bibliothèque a été ajoutée pour aider les programmes à analyser la sortie de read(directory)
. Différents systèmes et systèmes de fichiers pouvaient avoir différents formats sur disque, ce qui devenait compliqué.
Lorsque Sun a introduit le système de fichiers réseau (Network File System ou NFS), ils ont voulu supprimer complètement la structure de répertoires sur disque. Au lieu de faire de leur read(directory)
retour une représentation du répertoire indépendante de la plate-forme, ils ont ajouté un nouvel appel système getdirents
- et ont interdit read
les répertoires montés sur le réseau. Cet appel système a été rapidement adapté pour fonctionner sur tous les répertoires de différentes versions d'UNIX, ce qui en fait le moyen par défaut d'obtenir le contenu des répertoires. (Histoire extraite de https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )
Parce que readdir
c’est maintenant le moyen par défaut de lire les répertoires, il read(directory)
n’est généralement pas implémenté (renvoyer -EISDIR) sur la plupart des systèmes d’exploitation modernes (QNX, par exemple, est une exception notable qui s’implémente en readdir
tant que read(directory)
). Cependant, avec la conception "système de fichiers virtuel" dans la plupart des noyaux modernes, il appartient au système de fichiers individuel de savoir si la lecture d'un répertoire fonctionne ou non.
Et en effet, sur macOS, le devfs
système de fichiers sous-jacent au point de /dev
montage supporte réellement la lecture ( 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);
Cela appelle explicitement READDIR
si vous essayez de lire /dev
(la lecture de fichiers sous /dev
est gérée par une fonction séparée - devfsspec_read
). Donc, si un programme appelle l' read
appel système /dev
, il réussira et obtiendra une liste de répertoires!
C’est effectivement une fonctionnalité qui a été conservée depuis les tout débuts d’UNIX et qui n’a pas été touchée depuis très longtemps. Une partie de moi pense que cela est conservé pour des raisons de compatibilité ascendante, mais cela pourrait tout aussi bien être le fait que personne ne se soucie assez de supprimer cette fonctionnalité car elle ne blesse pas vraiment.
Less est une visionneuse de fichiers texte, cat est un outil de copie de données arbitraires. Donc, less effectue sa propre vérification pour s'assurer que vous n'ouvrez pas quelque chose qui contient des quantités énormes de données ou se comporte de façon très étrange. Par contre, cat n'a aucune vérification de ce type - si le noyau vous permet d'ouvrir quelque chose (même s'il s'agit d'un tuyau, d'un périphérique ou de quelque chose de pire), cat le lira.
Alors, pourquoi le système d'exploitation permet-il à cat d'ouvrir des répertoires? Traditionnellement, dans les systèmes de type BSD, tous les répertoires pouvaient être lus sous forme de fichiers, et c’était ainsi que les programmes listaient un répertoire: en interprétant simplement les structures dirent stockées sur disque.
Plus tard, ces structures sur disque ont commencé à diverger du sens utilisé par le noyau: là où un répertoire était auparavant une liste linéaire, les systèmes de fichiers ultérieurs ont commencé à utiliser des hashtables, des B-trees, etc. Donc, la lecture directe des répertoires n’était plus simple: le noyau a développé des fonctions dédiées à cette fin. (Je ne sais pas si c'était la raison principale ou s'ils ont été ajoutés principalement pour d'autres raisons, telles que la mise en cache.)
Certains systèmes BSD continuent de vous permettre d'ouvrir tous les répertoires en lecture. Je ne sais pas s'ils vous donnent les données brutes du disque, ou s'ils renvoient une liste de dirents émulés, ou s'ils laissent le pilote du système de fichiers décider.
Donc, peut-être que macOS est l’un de ces systèmes d’exploitation où le noyau le permet, à condition que le système de fichiers fournisse les données. Et la différence est que /dev
c'est sur un devfs
système de fichiers qui a été écrit pour permettre cela dans les premiers jours, alors qu'il /
est sur un système de fichiers APFS qui a omis cette fonctionnalité car inutile dans les temps modernes.
Clause de non-responsabilité: Je n'ai pas encore effectué de recherche sur les BSD ou MacOS. Je ne fais que m'envoler.
/etc
que, alors j'ai utilisé cela comme point de repère.
mount
ou /sbin/mount
consultez ce qui est actuellement monté.
/dev
s'agit d'un système de fichiers virtuel utilisant le devfs
pilote, alors qu'il /etc
fait partie du /
système de fichiers utilisant le apfs
pilote. Donc, la raison cat
lira l’un et pas l’autre une différence entre les pilotes apfs
et devfs
.
neofetch
pour votre information :) i.imgur.com/3azpnDt.png