web-dev-qa-db-fra.com

Comment sont créés les fichiers Linux "/ dev"?

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

Les exemples les plus notables et clairs de ceux-ci sont dans le dossier dev, "fichiers" comme:

  • /dev/null - Ignore tout ce que vous écrivez dans le fichier
  • /dev/random - Sort des données aléatoires au lieu 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 vous-même un "fichier magique" (que diriez-vous d'un /dev/rickroll)?

115
IQAndreas

/dev/zero est un exemple de "fichier spécial" - en particulier, un "nœud de périphérique". Normalement, ceux-ci sont créés par le processus d'installation de la distribution, mais vous pouvez totalement les créer vous-même si vous le souhaitez.

Si vous demandez ls à propos de /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ères"; l'autre type est "bloc périphérique" (imprimé par ls comme "b"). Très grosso modo, les périphériques à accès aléatoire comme les disques durs ont tendance à être des périphériques de type bloc, tandis que les éléments séquentiels comme les lecteurs de bande ou votre carte son sont généralement des périphériques de caractères.

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

Avec ces informations, nous pouvons utiliser la commande mknod 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 lui attribuer différentes autorisations si vous le souhaitez.) Tout ce "fichier" contient vraiment les trois éléments ci-dessus - type d'appareil, numéro majeur, numéro mineur. Vous pouvez utiliser ls pour rechercher les codes d'autres appareils et les recréer également. Lorsque vous vous ennuyez, utilisez simplement rm pour supprimer les nœuds de périphérique que vous venez de créer.

Fondamentalement, le nombre majeur indique au noyau Linux à quel pilote de périphérique parler, et le nombre mineur indique au pilote de périphérique de quel périphérique vous parlez. (Par exemple, vous avez probablement un contrôleur SATA, mais peut-être plusieurs disques durs y sont connectés.)

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 l'appareil et appelle automatiquement mknod/rm pour vous. Rien de plus magique que ça.

Il existe encore autre 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 trouveriez que c'est un fichier normal qui contient des données dans un format spécial et indique 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 en utilisant le ln -s commande. (Recherchez la page de manuel pour cela.)

  • Il y a aussi une chose appelée "pipe nommée" ou "FIFO" (file d'attente premier entré, premier sorti). Vous pouvez en créer un avec mkfifo. A 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 pipe Shell normal. Mais vous pouvez démarrer chaque programme séparément ...

Un fichier qui n'est en aucun cas "spécial" est appelé "fichier normal". Vous en verrez parfois la 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 quotidien normal sans propriétés magiques.

102

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

Mais /dev/tcp qui est mentionné dans votre question n'est expliqué par aucune des réponses existantes. /dev/tcp et /dev/udp sont différents de la plupart des autres /dev entrées. Les périphériques bloc et caractère sont implémentés par le noyau, mais /dev/tcp et /dev/udp sont implémentés en mode utilisateur.

Le shell bash est un programme qui a une implémentation de /dev/tcp et /dev/udp (copié de ksh93). Lorsque vous essayez d'ouvrir un chemin sous ceux avec des opérateurs de redirection bash, il n'exécutera pas un appel système open 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 uniquement dans certains programmes, comme le montre l'exemple suivant, qui montre la différence entre laisser bash et cat essayer 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 avec ksh93 est que bash ne fera que ces connexions TCP avec des opérateurs de redirection, pas aux autres endroits où il peut ouvrir des fichiers comme source ou . intégré.

34
kasperd

En plus des nœuds de périphériques expliqués dans d'autres réponses (créés avec mknod (2) ou fournis par certains devfs ), Linux a d'autres fichiers "magiques" fournis par special systèmes de fichiers virtuels , en particulier dans /proc/ (voir proc (5) , lire procfs ) et dans /sys/ (lire sur sysfs ).

Ces pseudo-fichiers (qui apparaissent de -e.g. à stat (2) - en tant que fichiers ordinaires, pas en tant que périphériques) sont une vue virtuelle fournie par le noyau; en particulier, la lecture de /proc/ (par exemple avec cat /proc/$$/maps, ou par open (2) - ing /proc/self/status dans votre programme) n'implique généralement pas d'E/S physiques à partir du disque ou du réseau, donc est assez rapide.

Pour créer un pseudo-fichier supplémentaire dans /proc/ vous devriez généralement écrire votre propre module du noya et le charger (voir par exemple this ).

19

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

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

13
cas

Comme d'autres utilisateurs l'ont déjà expliqué en détail, les fichiers spéciaux nécessitent du code pour les sauvegarder. Cependant, personne ne semble avoir mentionné que Linux propose 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 /proc sans risque de planter le noyau et faites-le dans la langue/runtime de votre choix, comme Go , Node.js , Perl , PHP , Python , Ruby , Rust , etc. .

Il présente également l'avantage que les systèmes de fichiers Fuse peuvent être montés sans Sudo car ils s'exécutent en tant qu'utilisateur effectuant le montage.

Voici quelques exemples de choses que les gens ont écrites en utilisant Fuse:

  • mp3fs (Affichez vos fichiers FLAC en tant que fichiers MP3 qui sont créés à la volée lorsque vous les copiez/cliquez-faites-les glisser vers votre lecteur MP3)
  • PyTagsFS (Affichez vos médias dans une arborescence de dossiers virtuels construits à partir des balises de métadonnées)
  • Fuse-Zip (Montez les fichiers Zip en tant que dossiers)
  • FuseISO (Montez les ISO sans autorisation root)
  • iFUSE (Monter les iDevices)
  • FuseDAV (Monter les partages 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, un joystick, etc. (par exemple pour écrire un pilote d'espace utilisateur pour une clé USB) appareil auquel vous parlez en utilisant libusb), il y a input .

Les liaisons sont plus difficiles à trouver, mais je sais qu'elles existent pour Aller (Clavier uniquement), Python et Ruby(2) .

Voici des exemples d'utilisation de données d'entrée réelles:

  • G15Daemon (pilote Linux pour le LCD et touches de jeu sur les claviers de jeu Logitech G15)
  • ds4drv (pilote pour les contrôleurs Sony DualShock 4)
  • xboxdrv (Pilote de contrôleur XBox 360 alternatif et Linux équivalent à x360ce des jeux si mal conçus comme Runner2: Future Legend of Rhythm Alien peut penser qu'ils sont parler à un vrai contrôleur XBox quand ils ne le sont pas)
  • Les anciens pilotes Wiimote comme cwiid qui étaient nécessaires avant que quelqu'un n'écrive finalement un pilote Wiimote noyau afin que le support soit disponible par défaut.

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

Le seul utilisateur de l'API CUSE que je connaisse personnellement est le même programme qui a provoqué sa création: osspd , qui implémente /dev/dsp, /dev/adsp, et /dev/mixer (l'API audio OSS) dans l'espace utilisateur afin qu'ils puissent être routés via 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 du tout besoin d'un nouveau fichier spécial.

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

10
ssokolow

Le livre Linux Device Drivers (hautement recommandé) explique cela en détail, et vous a même créé un module de noyau qui le fait à titre d'exemple, mais en un mot, chaque pilote de périphérique a des fonctions spécifiques qui sont appelées lorsqu'un fichier est ouvert, fermé, lu, écrit, etc. Les fichiers "spéciaux" font juste quelque chose de spécial à l'intérieur de ces fonctions, au lieu d'accéder au matériel de stockage sur un disque.

Par exemple, la fonction d'écriture pour /dev/null ne fait rien, ignorant les octets. La fonction de lecture pour /dev/random renvoie un nombre aléatoire.

6
Karl Bielefeldt

mount -t devtmpfs

Il est également intéressant de voir que dans les systèmes modernes, /dev est normalement un type de système de fichiers qui peut ê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=y, et 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 permet au noyau de monter automatiquement devtmpfs sur /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 exécutable minimal: Comprendre les fichiers de périphériques de caractères (ou de caractères spéciaux)

L'étape la plus importante consiste à configurer le file_operations struct, 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 des pointeurs de fonction qui sont appelés pour chaque appel système lié au fichier.

Il devient alors évident que vous remplacez ces appels système liés aux fichiers pour faire ce que vous voulez, et c'est ainsi que le noyau implémente des périphériques comme /dev/zero.

Créer /dev entrées automatiquement sans mknod

Le dernier mystère est de savoir comment le noyau crée automatiquement /dev entrées.

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