Comment les fichiers «/ dev» Linux sont-ils créés?

112

Il existe des fichiers spéciaux sous Linux qui ne sont pas vraiment des fichiers.

Les exemples les plus remarquables et les plus clairs de ceux-ci sont dans le devdossier, "fichiers" comme:

  • /dev/null - Ignore tout ce que vous écrivez dans le fichier
  • /dev/random - Affiche des données aléatoires à la place du contenu d'un fichier
  • /dev/tcp - Envoie toutes les données que vous écrivez dans ce fichier sur le réseau

Tout d’abord, quel est le nom de ces types de "fichiers" qui sont vraiment une sorte de script ou de binaire déguisé?

Deuxièmement, comment sont-ils créés? Ces fichiers sont-ils intégrés au système au niveau du noyau ou existe-t-il un moyen de créer un "fichier magique" vous-même (qu'en est-il de a /dev/rickroll)?

IQAndreas
la source
1
Je ne savais pas comment baliser cette question, surtout que je ne connaissais pas le nom de ce que je cherchais. N'hésitez pas à éditer dans les balises pertinentes.
IQAndreas
15
En passant, il s’agit d’un élément fondamental de la conception de systèmes d’exploitation unix et similaires: (presque) tout est un fichier, ou peut ressembler à un fichier.
cas
5
Voir aussi: mknod (2) man 2 mknod
RobertL
4
Ce sont des "nœuds de périphérique". Cependant, ceux que vous avez mentionnés - contrairement à ceux associés aux disques, clavier, souris, cartes son et autres périphériques - sont dits "pseudo-périphériques" car ils ne sont pas de "vrais" périphériques et n'existent que dans le noyau. Il est possible d'en créer de nouveaux en écrivant un pilote de périphérique approprié et en l'ajoutant au noyau (par exemple, un pseudo-périphérique permettant de surveiller certaines activités sur l'ordinateur). Avant le répertoire / dev existant sur le disque, il s’agit aujourd’hui d’un système de fichiers virtuel (de type devfs) créé par le noyau.
Baard Kopperud
10
Tous les fichiers, même les "vrais" fichiers, sont des artefacts logiciels. Le logiciel derrière chaque périphérique, fichier, socket, fichier spécial, ou quelque chose à inventer un tableau des fonctions pour gérer open(), read(), close(), etc. Après cela, il est au logiciel
waltinator

Réponses:

101

/dev/zeroest un exemple de "fichier spécial", en particulier de "nœud de périphérique". Normalement , ceux - ci sont créées par le processus d'installation de distribution, mais vous pouvez tout à fait les créer vous - même si vous voulez.

Si vous posez des questions lssur /dev/zero:

# ls -l /dev/zero
crw-rw-rw- 1 root root 1, 5  Nov 5 09:34 /dev/zero

Le "c" au début vous indique qu'il s'agit d'un "périphérique de caractère"; l'autre type est "périphérique de bloc" (imprimé par ls"b"). En gros, les périphériques à accès aléatoire tels que les disques durs ont tendance à être des périphériques bloqués, tandis que les éléments séquentiels tels que les lecteurs de bande ou votre carte son ont tendance à être des périphériques à caractères.

La partie "1, 5" est le "numéro de périphérique majeur" et le "numéro de périphérique mineur".

Avec ces informations, nous pouvons utiliser la mknodcommande pour créer notre propre nœud de périphérique:

# mknod foobar c 1 5

Cela crée un nouveau fichier nommé foobar, dans le dossier actuel, qui fait exactement la même chose que /dev/zero. (Vous pouvez bien sûr définir des autorisations différentes si vous le souhaitez.) Tout ce "fichier" contient en réalité les trois éléments ci-dessus - type de périphérique, numéro majeur, nombre mineur. Vous pouvez également lsrechercher les codes d’autres périphériques et les recréer. Lorsque vous vous ennuyez, utilisez simplement rmpour supprimer les nœuds de périphérique que vous venez de créer.

Fondamentalement, le numéro majeur indique au noyau Linux avec quel pilote de périphérique parler, et le numéro mineur indique au pilote de périphérique le périphérique dont vous parlez. (Par exemple, vous avez probablement un contrôleur SATA, mais peut-être plusieurs disques durs branchés dessus.)

Si vous voulez inventer de nouveaux périphériques qui font quelque chose de nouveau ... eh bien, vous devrez éditer le code source du noyau Linux et compiler votre propre noyau personnalisé. Alors ne faisons pas ça! :-) Mais vous pouvez ajouter des fichiers de périphérique qui dupliquent ceux que vous avez déjà très bien. Un système automatisé comme udev surveille simplement les événements de périphérique et appelle mknod/ rmpour vous automatiquement. Rien de plus magique que ça.

Il existe encore d' autres types de fichiers spéciaux:

  • Linux considère un répertoire comme un type spécial de fichier. (Habituellement, vous ne pouvez pas ouvrir directement un répertoire, mais si vous le pouviez, vous découvririez qu'il s'agit d'un fichier normal contenant des données dans un format spécial et indiquant au noyau où trouver tous les fichiers de ce répertoire.)

  • Un lien symbolique est un fichier spécial. (Mais un lien dur ne l'est pas.) Vous pouvez créer des liens symboliques à l'aide de la ln -scommande. (Recherchez la page de manuel.)

  • Il existe également un élément appelé "tube nommé" ou "FIFO" (file d'attente premier entré, premier sorti). Vous pouvez en créer un avec mkfifo. Une FIFO est un fichier magique qui peut être ouvert par deux programmes à la fois - une lecture, une écriture. Lorsque cela se produit, cela fonctionne comme un tuyau shell normal. Mais vous pouvez démarrer chaque programme séparément ...

Un fichier qui n'est en aucun cas "spécial" s'appelle un "fichier normal". Vous verrez parfois cette mention dans la documentation Unix. C'est ce que ça signifie; un fichier qui n'est pas un nœud de périphérique ou un lien symbolique ou autre. Juste un fichier de tous les jours sans propriétés magiques.

MathematicalOrchid
la source
4
Il existe également un autre type de fichier spécial, un socket de domaine Unix lié au système de fichiers.
Brian Bi
8
Si vous voulez jouer avec mknod, lancez cat /proc/devicespour voir les numéros majeurs pour tous les pilotes. Ce qui nous amène à un autre type de fichier spécial, le /procsystème de fichiers ( cette réponse en parle).
Ugoren
8
D'autres bureaux ont inventé leurs propres fichiers spéciaux, par exemple Solaris avait des portes .
Kevin
6
Nitpick mineur: vous n'avez pas besoin de recompiler le noyau pour écrire un nouveau périphérique caractère / bloc :) crashcourse.ca/introduction-linux-kernel-programming/… Sinon, c'est une très bonne réponse, +1!
Commandant Coriandre Salamandre
1
@MathematicalOrchid: il manque une étape (ou du moins ne dit implicitement) que ces fichiers spéciaux ne sont pas du tout des scripts shell ou des binaires déguisés (comme le suggère la question), mais plutôt une interface permettant d'accéder aux fonctionnalités présentes. dans le noyau OS.
Rêveur
34

La plupart des /deventrées sont des inodes de périphérique en mode bloc ou des inodes de périphérique en caractères. Wikipedia a beaucoup de détails à ce sujet, que je ne vais pas répéter.

Mais /dev/tcpce qui est mentionné dans votre question n’est expliqué par aucune des réponses existantes. /dev/tcpet /dev/udpsont différents de la plupart des autres /deventrées. Les périphériques de bloc et de caractère sont mises en œuvre par le noyau, mais /dev/tcpet /dev/udpsont mises en œuvre en mode utilisateur.

Le shell bash est un programme qui a une implémentation de /dev/tcpet /dev/udp(copié à partir de ksh93). Lorsque vous essayez d'ouvrir un chemin sous ceux avec des opérateurs de redirection bash, il ne réalisera pas un openappel système ordinaire . Au lieu de cela, bash créera un socket TCP et le connectera au port spécifié.

Cela est implémenté en mode utilisateur et seulement dans certains programmes, comme le montre l'exemple suivant, qui montre la différence entre laisser bashet catessayer d'ouvrir/dev/tcp/::1/22

$ cat /dev/tcp/::1/22
cat: /dev/tcp/::1/22: No such file or directory
$ cat < /dev/tcp/::1/22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.3

Une différence ksh93est que bashseules les connexions TCP avec des opérateurs de redirection seront effectuées, pas dans les autres endroits où il peut ouvrir des fichiers tels que le sourceou ..

Kasperd
la source
De plus, GNU awk a gawkdes cas similaires /inet{,4,6}/{tcp,udp}/$port/$remote/$rport, depuis environ 2010 (je ne me souviens pas exactement et je ne trouve pas de notes de publication).
dave_thompson_085
6
OMI, une meilleure façon de préciser le point /dev/tcpest que ce n'est pas un fichier. Il n'y a jamais un fichier appelé ceci. La syntaxe utilisée par Bash pour ouvrir des sockets utilise la chaîne /dev/tcp/addresscomme un nom de fichier, mais l'appeler un "fichier implémenté dans l'espace utilisateur" sonne simplement bizarre. Intéressant qui kshaccroche ces noms de fichiers pour tout, pas seulement pour les redirections. C'est plus proche de "implémenter un fichier".
Peter Cordes
@PeterCordes Je pense que UWIN les configure en tant que fichiers réels. et je pense que 3dfs fait la même chose. Rappelez-vous, bashcopiez seulement ce comportement, mais il provient ailleurs.
mikeserv
19

Outre les nœuds de périphérique expliqués dans d'autres réponses (créés avec mknod (2) ou fournis par certains devfs ), Linux possède d'autres fichiers "magiques" fournis par des systèmes de fichiers virtuels spéciaux , en particulier dans /proc/(voir proc (5) , en savoir plus sur procfs ) et in /sys/(lisez à propos de sysfs ).

Ces pseudo-fichiers (qui apparaissent, par exemple, dans stat (2) , sous forme de fichiers ordinaires et non de périphériques) constituent une vue virtuelle fournie par le noyau; en particulier, la lecture de /proc/(par exemple avec cat /proc/$$/maps, ou ouvert (2) -ment /proc/self/statusdans votre programme) n'impliquent généralement pas d' E / S physiques à partir du disque ou d'un réseau, est donc assez rapide.

Pour créer une pseudo-fichier supplémentaire , /proc/vous devez généralement écrire votre propre module de noyau et le charger (voir par exemple ce ).

Basile Starynkevitch
la source
3
Autant que je sache, les informations sur l'extension / proc sont obsolètes. Bien que techniquement possible, / proc (ou plutôt procfs) ne devrait contenir des informations que sur les processus en cours. Tous les autres pseudo-fichiers, y compris ceux qui contiennent des informations d’exécution ou des options de configuration pour le noyau, doivent être placés dans / sys (sysfs). Pour des raisons de compatibilité, il existe encore des pseudo-fichiers non liés au processus dans / proc (par exemple, meminfo, cpuinfo), mais les nouveaux pseudo-fichiers doivent aller dans sysfs.
Rêveur
13

Ils sont appelés nœuds de périphériques et sont créés manuellement mknodou automatiquement par udev. Ce sont généralement des interfaces de type fichier vers des périphériques de type caractères ou blocs avec des pilotes dans le noyau - par exemple, les disques sont des périphériques de type bloc, les ports série et les ports série, etc. sont des périphériques de type caractère.

Il existe également d'autres types de fichiers "spéciaux", notamment les canaux nommés, les fifos et les sockets.

cas
la source
9

Comme d'autres utilisateurs l'ont déjà expliqué en détail, les fichiers spéciaux nécessitent un code pour les sauvegarder. Cependant, personne ne semble avoir mentionné que Linux fournit plusieurs façons d'écrire ce code dans l'espace utilisateur:

A. FUSE (système de fichiers dans USErspace) vous permet d’écrire quelque chose comme /procsans risque de planter le noyau et de le faire dans une langue / exécution de votre choix, telle que Go , Node.js , Perl , PHP , Python , Ruby , Rust , etc. etc .

Il présente également l’avantage que les systèmes de fichiers FUSE peuvent être montés sans, sudocar ils sont exécutés en tant qu’utilisateur effectuant le montage.

Voici quelques exemples d'éléments écrits par les utilisateurs de FUSE:

  • mp3fs (Visualisez vos fichiers FLAC sous forme de fichiers MP3 qui sont créés à la volée lorsque vous les copiez / cliquez-glissez-les sur votre lecteur MP3)
  • PyTagsFS (Affichez vos médias dans une arborescence de dossiers virtuels construite à partir des balises de métadonnées)
  • fuse-zip (Monter des fichiers Zip en tant que dossiers)
  • FuseISO (Monter des ISO sans autorisations root)
  • iFUSE (Mount iDevices)
  • FuseDAV ( partages Mount WebDAV)
  • fuse-exfat (Monter des systèmes de fichiers au format exFAT)
  • ntfs-3g ( le pilote Linux NTFS)

B. Si vous souhaitez créer un périphérique d’entrée virtuel, comme un clavier, une souris, une manette de jeu, etc. (par exemple, écrire un pilote d’espace utilisateur pour un périphérique USB avec lequel vous parlez libusb), vous pouvez entrer .

Les liaisons pour cela sont plus difficiles à trouver, mais je sais qu’elles existent pour Go (clavier uniquement), Python et Ruby (2) .

Voici des exemples d'utilisation réelle dans le monde réel:

  • G15Daemon (pilote Linux pour l'écran LCD et les touches de jeu sur les claviers de jeu Logitech G15)
  • ds4drv (pilote pour contrôleurs Sony DualShock 4)
  • xboxdrv (Pilote de contrôleur XBox 360 alternatif et équivalent de Linux à x360ce pour des jeux aussi mal conçus que Runner2: la légende future du rythme Alien peuvent penser qu’ils parlent à un vrai contrôleur XBox alors qu’ils ne le sont pas)
  • Les anciens pilotes Wiimote, tels que cwiid, qui étaient nécessaires avant que quelqu'un écrive enfin un pilote Wiimote du noyau afin que la prise en charge soit disponible par défaut.

C. Pour les périphériques à caractères génériques, il existe CUSE (périphériques à caractères dans USErspace). C'est beaucoup moins populaire cependant.

Le seul utilisateur de l'API Cuse que je suis personnellement au courant est le même programme qui a incité sa création: osspd , qui met en œuvre /dev/dsp, /dev/adspet /dev/mixer(l'API audio OSS) dans l' espace utilisateur afin qu'ils puissent être acheminés par PulseAudio ou dmix.

La seule liaison CUSE que j'ai pu trouver est Cusepy , qui n'a pas été mise à jour depuis 2010.

D. Vous n’avez peut-être pas besoin d’un nouveau fichier spécial.

Par exemple, vous pouvez ouvrir une communication brute avec n’importe quel périphérique USB à l’aide de libusb (liste des liaisons sur la page), puis communiquer avec d’autres programmes via un autre mécanisme (sockets TCP / UDP, lecture / écriture de fichiers stdin / stdout ou normaux sur disque). , etc.).

ssokolow
la source
1
cusepy n’a peut-être pas été mis à jour depuis un certain temps (en fait, il n’a jamais été mis à jour; il n’ya qu’un commit;), mais je viens d’écrire un périphérique de caractères utilisant cusepy il ya quelques semaines, mais je peux confirmer qu’il fonctionne toujours bien. Il manquait quelques fonctions liées à la mise en œuvre poll, mais étant donné que cusepy utilise ctypes et les liaisons sont générées automatiquement basées sur les fichiers d' en- tête C, la fixation des fonctions manquantes est juste une question d'ajouter le nom de la fonction désirée à la liste des fonctions exportées dans le setup.py.
Aleksi Torhamo
1
Sshfs est un autre exemple intéressant d'utilisation de FUSE . Il vous permet de parcourir le système de fichiers distant comme s'il était local à l'aide d'une connexion SSH située en dessous.
Mr. Deathless
@ Mr.Deathless Ouais. En fait, je l'utilise et je voulais en parler, mais j'ai oublié.
ssokolow
6

Le livre Linux Device Drivers (hautement recommandé) explique cela en détail et vous a même demandé de créer un module de noyau à titre d'exemple. Cependant, en résumé, chaque pilote de périphérique possède des fonctions spécifiques qui sont appelées lors de l'ouverture, de la fermeture d'un fichier. , lu, écrit, etc. Les fichiers "spéciaux" font simplement quelque chose de spécial dans ces fonctions, au lieu d’accéder au matériel de stockage sur un disque.

Par exemple, la fonction write /dev/nullne fait rien, ignorant les octets. La fonction de lecture pour /dev/randomrenvoie un nombre aléatoire.

Karl Bielefeldt
la source
1

mount -t devtmpfs

Il est également intéressant de constater que, dans les systèmes modernes, il /devs’agit généralement d’un système de fichiers pouvant être monté où vous le souhaitez. Ubuntu 16.04:

mkdir d
sudo mount -t devtmpfs none d
head -c 10 d/random
sudo umount d

Ceci est activé par CONFIG_DEVTMPFS=yet permet au noyau lui-même de créer et de détruire les fichiers de périphérique selon les besoins.

CONFIG_DEVTMPFS_MOUNT=y

Cette option rend devtmpfs sur le noyau pour le montage automatique /dev.

drivers/base/Kconfig documents:

config DEVTMPFS_MOUNT
    bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
    depends on DEVTMPFS
    help
      This will instruct the kernel to automatically mount the
      devtmpfs filesystem at /dev, directly after the kernel has
      mounted the root filesystem. The behavior can be overridden
      with the commandline parameter: devtmpfs.mount=0|1.
      This option does not affect initramfs based booting, here
      the devtmpfs filesystem always needs to be mounted manually
      after the rootfs is mounted.
      With this option enabled, it allows to bring up a system in
      rescue mode with init=/bin/sh, even when the /dev directory
      on the rootfs is completely empty.

file_operations

Enfin, vous devez créer votre propre module de noyau de périphérique de caractères pour voir exactement ce qui se passe.

Voici un exemple minimal d’exécution: Comprendre les fichiers de périphériques de caractères (ou de caractères spéciaux)

L’étape la plus importante est la configuration de la file_operationsstructure, par exemple:

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
    .open = open,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

qui contient les pointeurs de fonction appelés pour chaque appel système lié à un fichier.

Il devient alors évident que vous substituez ces appels système liés aux fichiers pour faire ce que vous voulez, et voici comment le noyau implémente des périphériques tels que /dev/zero.

Créer des /deventrées à automatiquement sansmknod

Le mystère final concerne la manière dont le noyau crée automatiquement des /deventrées.

Le mécanisme peut être observé en créant un module de noyau qui le fait vous-même, comme indiqué à l' adresse : https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module- code-of-a-linux-kernel-module / 45531867 # 45531867 et se réduit à un device_createappel.

Ciro Santilli 改造 心 心 心
la source
Dans OpenBSD, il existe un script MAKEDEV qui simplifie un peu cette tâche ( voir man.openbsd.org/MAKEDEV.8). Vous ne savez pas pourquoi Linux ne l’a pas, sauf que c’est beaucoup plus compliqué. Peut-être que certaines parties pourraient être adaptées. Vous pouvez dire MKNOD tty par exemple et il gère les détails.
Alan Corey