Périphériques

Linux, comme la plupart des systèmes d’exploitation, interagit avec les périphériques matériels via des composants logiciels modulaires appelés pilotes de périphériques. Un pilote masque les particularités des protocoles de communication utilisés par un dispositif matériel au système d’exploitation et lui permet d’interagir avec le périphérique par le biais d’une interface standardisée.

Sous Linux, les pilotes de périphériques font partie du noyau et peuvent être intégrés de façon statique à celui-ci ou chargés à la demande sous forme de modules. Les pilotes de périphériques s’exécutent comme s’ils faisaient partie du noyau et ne sont pas accessibles directement aux processus utilisateur. Cependant, Linux propose un mécanisme à ces processus pour communiquer avec un pilote − et par là même avec le dispositif matériel − via des objets semblables aux fichiers. Ces objets apparaissent dans le système de fichiers et des applications peuvent les ouvrir, les lire et y écrire pratiquement comme s’il s’agissait de fichiers normaux. Vos programmes peuvent donc communiquer avec des dispositifs matériels via des objets semblables aux fichiers soit en utilisant les opérations d’E/S de bas niveau de Linux (consultez l’Appendice B, « E/S de Bas Niveau »), soit les opérations de la bibliothèque d’E/S standard du C.

Linux fournit également plusieurs objets semblables à des fichiers qui communiquent directement avec le noyau plutôt qu’avec des pilotes de périphériques. Ils ne sont pas liés à des dispositifs matériels; au lieu de cela, ils fournissent différents types de comportements spécialisés qui peuvent être utiles aux applications et aux programmes systèmes.

Soyez prudent lorsque vous accédez aux périphériques !
Les techniques présentées dans ce chapitre fournissent un accès direct aux pilotes de périphériques s’exécutant au sein du noyau Linux, et à travers eux aux dispositifs matériels connectés au système. Utilisez ces techniques avec prudence car une mauvaise manipulation peut altérer ou endommager le système GNU/Linux.
Lisez notamment le cadre « Danger des Périphériques Blocs ».

Types de périphériques

Les fichiers de périphériques ne sont pas des fichiers ordinaires − ils ne représentent pas des zones de données au sein d’un système de fichiers sur disque. Au lieu de cela, les données lues ou écrites sur un fichier de périphérique sont transmises au pilote de périphérique correspondant et, par son intermédiaire, au matériel sous-jacent. Les fichiers de périphériques se divisent en deux types:

  • Un périphérique caractère représente un dispositif matériel qui lit ou écrit en série un flux d’octets. Les ports série et parallèle, les lecteurs de cassettes, les terminaux et les cartes son sont des exemples de périphériques caractères.
  • Un périphérique bloc représente un dispositif matériel qui lit ou écrit des données sous forme de blocs de taille fixe. Contrairement aux périphériques caractère, un périphérique bloc fournit un accès direct aux données stockées sur le périphérique. Un lecteur de disque est un exemple de périphérique bloc.

Les programmes traditionnels n’utiliseront jamais de périphériques blocs. Bien qu’un lecteur de disque soit représenté comme un périphérique matériel, le contenu de chaque partition contient habituellement un système de fichiers monté sur l’arborescence racine de GNU/Linux. Seul le code du noyau qui implémente le système de fichiers a besoin d’accéder au périphérique bloc directement; les programmes d’application accèdent au contenu du disque via des fichiers et des répertoires normaux.

Néanmoins, les applications utilisent quelquefois les périphériques caractère. Nous traiterons de plusieurs d’entre eux dans les sections suivantes.

Dangers des périphériques de type bloc
Les périphériques bloc offrent un accès direct aux données du lecteur de disque. Bien que la plupart des systèmes GNU/Linux soient configurés pour interdire aux processus non root d’accéder directement à ces périphériques, un processus root peut causer des dommages sévères en changeant le contenu du disque. En écrivant sur un périphérique bloc correspondant à un disque, un programme peut modifier ou détruire les informations de contrôle du système de fichier et même la table des partitions d’un disque et son secteur de démarrage, rendant ainsi le lecteur, ou même tout le système, inutilisable. Accédez toujours à ces périphériques avec la plus grande prudence.

Numéros de périphérique

Linux identifie les périphériques au moyen de deux nombres: le numéro de périphérique majeur et le numéro de périphérique mineur. Le numéro de périphérique majeur indique à quel pilote correspond le périphérique. Les correspondances entre les numéros de périphérique majeurs et les pilotes sont fixes et définies dans les sources du noyau Linux. Notez qu’un même numéro de périphérique majeur peut correspondre à deux pilotes différents, l’un étant un périphérique caractère et l’autre un périphérique bloc. Les numéros de périphérique mineurs permettent de distinguer plusieurs périphériques ou composants contrôlés par le même pilote.

Par exemple, le périphérique de numéro majeur~3 correspond au contrôleur IDE primaire du système. Un contrôleur IDE peut être connecté à deux périphériques (lecteur de disque, cassette ou CD-ROM); le périphérique « maître » a le numéro mineur~0 et le périphérique « esclave » a le numéro mineur~64. les partitions du périphérique maître (s’il supporte les partitions) ont les numéros 1, 2, 3, etc. Les partitions du périphérique esclave sont représentées par les numéros de périphérique mineurs 65, 66, 67, etc.

Les numéros de périphérique majeurs sont répertoriés dans la documentation des sources du noyau Linux. Sur beaucoup de distributions GNU/Linux, ils sont décrits dans le fichier /usr/src/linux/Documentation/devices.txt. Le fichier spécial /proc/devices dresse la liste des numéros de périphérique majeurs correspondant aux pilotes de périphériques actuellement chargés dans le noyau (consultez le Chapitre 7, « le Système de Fichiers /proc » pour plus d’informations sur les entrées du système de fichiers /proc).

Fichiers de périphériques

Un fichier de périphérique ressemble beaucoup à un fichier classique. Vous pouvez le déplacer en utilisant la commande mv et le supprimer avec rm. Si vous essayez de copier un périphérique en utilisant cp, par contre, vous lirez des octets à partir de celui-ci (s’il le supporte) et les écrirez vers un fichier de destination. Si vous essayez d’écraser un fichier de périphérique, vous écrirez des octets vers le périphérique concerné.

Vous pouvez créer un fichier de périphérique en utilisant la commande mknod (saisissez man~1~mknod pour obtenir la page de manuel) ou l’appel système mknod (man~2~mknod pour la page de manuel). Créer un fichier de périphérique n’implique pas automatiquement que le pilote ou le dispositif matériel soit présent ou disponible; le fichier de périphérique est en quelque sort un portail pour communiquer avec le pilote, s’il est présent. Seul les processus superutilisateur peuvent créer des périphériques bloc et caractère via la commande ou l’appel système mknod.

Pour créer un périphérique en utilisant la commande mknod, spécifiez le chemin du fichier le représentant comme premier argument de la ligne de commande. Pour le second argument, passez b pour un périphérique bloc ou c pour un périphérique caractère. Fournissez les numéros de périphérique majeur et mineur en troisième et quatrième argument, respectivement. Par exemple, la commande suivante crée un fichier de périphérique caractère appelé lp0 dans le répertoire courant. Ce périphérique a le numéro de périphérique majeur 6 et le numéro mineur 0. Ces nombres correspondent au premier port parallèle sur le système Linux.

% mknod ./lp0 c 6 0

Souvenez-vous que seuls les processus du superutilisateur peuvent créer des périphériques bloc ou caractère, vous devez donc être connecté en tant que root pour invoquer cette commande avec succès.

La commande ls affiche les fichiers de périphérique d’une façon particulière. Si vous l’appelez avec les options -l ou -o, le premier caractère de chaque ligne indique le type du fichier. Rappelons que - (un tiret) indique un fichier classique, alors que d indique un répertoire.

De même, b désigne un périphérique bloc et c un périphérique caractère. Pour ces deux derniers, ls affiche les numéros de périphérique majeur et mineur là où se trouve habituellement la taille pour les fichiers ordinaires. Par exemple, nous pouvons afficher le périphérique caractère que nous venons juste de créer:

% ls -l lp0
crw-r−−-  1 root root 6, 0 Mar 7 17:03 lp0

Dans un programme, vous pouvez déterminer si un fichier est un périphérique bloc ou caractère et donc obtenir ses numéros de périphérique via stat. Consultez la Section B.2, « stat », de l’Appendice B, pour plus d’informations.

Pour supprimer le fichier, utilisez rm. Cela ne supprime pas le périphérique ou son pilote; mais simplement le fichier de périphérique du système de fichiers.

% rm ./lp0

Le répertoire /dev

Par convention, un système GNU/Linux inclut un répertoire /dev contenant tous les fichiers de périphériques caractère ou bloc des périphériques détectés. Les entrées de /dev ont des noms standardisés correspondant aux numéros de périphérique majeur et mineur.

Par exemple, le périphérique maître connecté au contrôleur IDE primaire, qui dispose des numéros de périphérique majeur et mineur~3 et~0, a le nom standard /dev/hda. Si ce périphérique gère les partitions, la première, qui dispose du numéro de périphérique mineur~1, a le nom standard /dev/hda1. Vous pouvez le vérifier sur votre propre système:

% ls -l /dev/hda /dev/hda1
brw-rw−−    1 root     disk 3, 0 May 5 1998 /dev/hda
brw-rw−−    1 root     disk 3, 1 May 5 1998 /dev/hda1

De même, /dev contient une entrée pour le périphérique caractère qu’est le port parallèle que nous avons utilisé précédemment:

% ls -l /dev/lp0
crw-rw−−    1 root daemon 6, 0 May 5 1998 /dev/lp0

Dans la plupart des cas, vous ne devriez pas utiliser mknod pour créer vos propres fichiers de périphérique. Utilisez plutôt les entrées de /dev. Les programmes ne disposant pas des privilèges superutilisateur n’ont pas d’autre choix que de les utiliser puisqu’ils ne peuvent pas créer leurs propres entrées. Typiquement, seuls les administrateurs système et les développeurs utilisant des périphériques spécifiques ont besoin de créer leurs propres fichiers de périphérique. La plupart des distributions GNU/Linux proposent des utilitaires d’aide à la création de fichiers de périphérique standard avec les noms corrects.

Accéder à des périphériques en ouvrant des fichiers

Comment utiliser ces périphériques? Dans le cas de périphériques caractère, cela peut être relativement simple: ouvrez le périphérique comme s’il s’agissait d’un fichier classique et lisez ou écrivez-y. Vous pouvez même utiliser des commandes conçues pour les fichiers traditionnels, comme cat ou la syntaxe de redirection de votre shell pour envoyer ou lire des données à partir du périphérique.

Par exemple, si vous disposez d’une imprimante connectée sur le premier port parallèle de votre ordinateur, vous pouvez imprimer des fichiers en les envoyant directement sur /dev/lp01). Pour imprimer le contenu de document.txt, invoquez la commande suivante:

% cat document.txt > /dev/lp0

Vous devez disposer des permissions en écriture sur le fichier de périphérique pour que la commande n’échoue pas; sur beaucoup de systèmes GNU/Linux, les permissions sont définies de telle façon que seul root et le démon d’impression système (lpd) puissent écrire dans ce fichier. De plus, ce qui sort de votre imprimante dépend de la façon dont elle interprète les données que vous lui envoyez. Certaines imprimantes imprimeront les fichiers texte plats que vous leur enverrez2), d’autres non. Les imprimantes PostScript interpréteront et imprimeront les fichiers PostScript que vous leur envoyez.

Dans un programme, envoyer des données à un périphérique est aussi simple. Par exemple, cet extrait de code utilise des fonctions d’E/S standard de bas niveau pour envoyer le contenu d’un tampon vers /dev/lp0.

int fd = open ("/dev/lp0", O_WRONLY);
write (fd, buffer, buffer_length);
close (fd);

Périphériques matériels

Quelques périphériques bloc standards sont listés dans le Tableau !!peribloc!!. Les numéros mineurs des périphériques similaires suivent un motif classique (par exemple, la seconde partition du premier périphérique SCSI est /dev/sda2). Il est parfois utile de savoir à quel périphérique correspondent les noms de périphériques lorsque l’on observe les systèmes de fichiers montés dans /proc/mounts (consultez la Section 7.5, « Lecteurs et Systèmes de Fichiers », du Chapitre 7, pour en savoir plus).

Listing partiel des périphériques bloc courants}

Périphérique Nom N° majeur N° mineur
Premier lecteur de disquettes /dev/fd0 2 0
Second lecteur de disquette /dev/fd1 2 1
Contrôleur IDE primaire, maîtres /dev/hda 3 0
Contrôleur IDE primaire, maître, première partition /dev/hda1 3 1
Contrôleur IDE primaire, esclave /dev/hdb 3 64
Contrôleur IDE primaire, esclave, première partition /dev/hdb1 3 65
Premier lecteur SCSI /dev/sda 8 0
Premier lecteur SCSI, première partition /dev/sda1 8 1
Second disque SCSI /dev/sdb 8 16
Second disque SCSI, première partition /dev/sdb1 8 17
Premier lecteur CD-ROM SCSI /dev/scd0 11 0
Second lecteur CD-ROM SCSI /dev/scd1 11 1

Le tableau !!pericar!! liste quelques périphériques caractère courants.

Listing partiel des périphériques caractère courants

Périphérique Nom N° majeur N° mineur}
Port parallèle 0 /dev/fd0 ou /dev/par0 6 0
Port parallèle 1 /dev/lp1 ou /dev/par1 6 1
Premier port série /dev/ttyS0 4 64
Second port série /dev/ttyS1 4 65
Lecteur de cassettes IDE /dev/ht0 37 0
Premier lecteur de cassettes SCSI /dev/st0 9 0
Second lecteur de cassettes SCSI /dev/st1 9 1
Console système /dev/console 5 1
Premier terminal virtuel /dev/tty1 4 1
Second terminal virtuel /dev/tty2 4 2
Terminal du processus courant /dev/tty 5 0
Carte son /dev/audio 14 4

Vous pouvez accéder à certains composants matériels via plus d’un périphérique caractère; souvent, des périphériques caractère distincts ont une sémantique différente. Par exemple, lorsque vous utilisez le lecteur de cassettes IDE /dev/ht0, Linux rembobine automatiquement la cassette lorsque vous fermez le descripteur de fichier. Vous pouvez utiliser /dev/nht0 pour accéder au même lecteur de cassettes, la seule différence est que Linux ne rembobine pas la cassette lors de la fermeture. Vous pourriez rencontrer des programmes utilisant /dev/cua0 et des dispositifs similaires; il s’agit d’anciennes interfaces vers les ports série comme /dev/ttyS0.

De temps à autre, vous pourriez avoir besoin d’écrire des données directement sur des périphériques caractère − par exemple:

  • Un programme terminal peut accéder à un modem directement par le biais d’un port série. Les données écrites ou lues à partir de ces périphériques sont transmises par le modem à un ordinateur distant.
  • Un programme de sauvegarde sur cassette peut écrire directement des données sur le périphérique de lecture de cassettes. Ce programme peut implémenter son propre format de compression et de vérification d’erreur.
  • Un programme peut écrire directement sur le premier terminal virtuel3) en écrivant sur /dev/tty1.
  • Les fenêtres de terminal s’exécutant sous un environnement graphique ou les sessions distantes ne sont pas associées à des terminaux virtuels mais à des pseudos-terminaux. Consultez la Section 6.6, « PTY », pour plus d’informations.
  • Parfois, un programme peut avoir besoin d’accéder au terminal auquel il est associé.
    Par exemple, votre application peut avoir besoin de demander un mot de passe à l’utilisateur. Pour des raisons de sécurité, vous ne voulez pas tenir compte des redirections d’entrée et de sortie standards et toujours lire le mot de passe à partir du terminal, peut importe la façon dont l’utilisateur appelle votre programme. Une façon de le faire est d’ouvrir /dev/tty, qui correspond toujours au terminal associé au processus effectuant l’ouverture. Écrivez l’invite de mot de passe sur ce périphérique et lisez le mot de passe. En ignorant l’entrée et la sortie standards, vous évitez que l’utilisateur n’alimente votre programme avec un mot de passe stocké dans un fichier avec une syntaxe comme celle-ci:
    % programme_sur < mon-motdepasse.txt
    Si vous avez besoin d’un mécanisme d’authentification dans votre programme, vous devriez vous tourner vers le dispositif PAM de GNU/Linux. Consultez la Section 10.5, « Authentification des Utilisateurs », du Chapitre 10, « Sécurité », pour plus d’informations.
  • Un programme peut diffuser des sons via la carte son du système en envoyant des données audio vers /dev/audio. Notez que les données audio doivent être au format Sun (fichiers portant habituellement l’extension .au).
    Par exemple, beaucoup de distributions GNU/Linux fournissent le fichier son classique /usr/share/sndconfig/sample.au. Si votre système dispose de ce fichier, essayez de le jouer grâce à la commande suivante:
    % cat /usr/share/sndconfig/sample.au > /dev/audio
    Si vous devez utiliser des sons dans votre programme, cependant, vous devriez utiliser l’un des multiples bibliothèques et services de gestion de sons disponibles pour GNU/Linux. L’environnement de bureau Gnome utilise l’Enlightenment Sound Daemon (EsounD), disponible sur http://www.tux.org/~ricdude/EsounD.html. KDE utilise aRts, disponible sur http://space.twc.de/~stefan/kde/arts-mcop-doc/. Si vous utilisez l’un de ces systèmes de son au lieu d’écrire directement sur /dev/audio, votre programme pourra être utilisé plus facilement avec d’autres programmes utilisant la carte son de l’ordinateur.

Périphériques spéciaux

Linux fournit également divers périphériques caractère ne correspondant à aucun périphérique matériel. Ces fichiers ont tous le numéro de périphérique majeur~1, qui est associé à la mémoire du noyau Linux et non à un pilote de périphérique.

/dev/null

Le fichier /dev/null, le périphérique nul, est très pratique. Il a deux utilisations; vous êtes probablement familiers avec la première:

  • Linux ignore toute donnée écrite vers /dev/null. Une astuce souvent utilisée est de spécifier /dev/null en tant que fichier de sortie lorsque l’on ne veut pas de sortie. Par exemple, pour lancer une commande et ignorer son affichage standard (sans l’afficher ni l’envoyer vers un fichier), redirigez la sortie standard vers /dev/null:
    % commande_bavarde > /dev/null
  • Lire depuis /dev/null renvoie toujours une fin de fichier. Par exemple, si vous ouvrez un descripteur de fichier correspondant à /dev/null en utilisant open puis essayez d’appeler read sur ce descripteur, aucun octet ne sera lu et read renverra 0. Si vous copiez /dev/null vers un autre fichier, la destination sera un fichier de taille nulle:
    % cp /dev/null fichier_vide
    % ls -l fichier_vide
    -rw-rw−− 1 samuel samuel 0 Mar 8 00:27 fichier_vide

/dev/zero

Le fichier de périphérique /dev/zero se comporte comme s’il contenait une infinité d’octets à~0. Quelle que soit la quantité de données que vous essayez de lire à partir de /dev/zero, Linux générera suffisamment d’octets nuls.

Pour illustrer cela, exécutons le programme de capture en hexadécimal présenté dans le Listing B.4, « Lecture de Données », de l’Appendice B. Ce programme affiche le contenu d’un fichier au format hexadécimal.

% ./hexdump /dev/zero
0x000000 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x000020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...

Appuyez sur Ctrl+C une fois convaincu qu’il continuera indéfiniment.

Mettre /dev/zero en correspondance avec la mémoire est une technique d’allocation avancée. Reportez-vous à la Section 5.3.5, « Autres Utilisations de nmap », du Chapitre !!IPC!!, « Communication Interprocessus » pour plus d’informations, et consultez l’encadré « Obtenir de la Mémoire Alignée sur des Pages », de la Section 8.9, « mprotect : Définir des Permissions Mémoire », du Chapitre 8, « Appels Système Linux », pour un exemple.

/dev/full

Le fichier /dev/full se comporte comme s’il se trouvait sur un système de fichiers ne comportant plus d’espace libre. Une écriture vers /dev/full échoue et positionne errno à ENOSPC, qui indique que le lecteur de destination est plein.

Par exemple, vous pouvez tenter d’écrire sur /dev/full en utilisant la commande cp:

% cp /etc/fstab /dev/full
cp: écriture de `/dev/full': Aucun espace disponible sur le périphérique

Le fichier /dev/full est essentiellement utile pour tester la façon dont se comporte votre programme s’il tombe à court d’espace disque lors de l’écriture d’un fichier.

Dispositifs de génération de nombres aléatoires

Les périphériques spéciaux /dev/random et /dev/urandom donnent accès au dispositif de génération de nombres aléatoires intégré au noyau Linux.

La plupart des fonctions logicielles chargées de générer des nombres aléatoires, comme la fonction rand de la bibliothèque standard du~C, génèrent en fait des nombres pseudo-aléatoires. Bien que ces nombres aient certaines propriétés des nombres aléatoires, ils sont reproductibles: si vous relancez une série avec la même valeur d’initialisation, vous obtiendrez la même séquence de nombres pseudo-aléatoires à chaque fois. Cet inconvénient est inévitable car les ordinateurs sont intrinsèquement déterministes et prévisibles. Pour certaines applications, cependant, ce comportement n’est pas souhaitable; par exemple, il peut être possible de casser un algorithme de chiffrement si l’on connaît la séquence de nombres aléatoires qu’il utilise.

L’obtention de nombres aléatoires plus stricts au sein de programmes informatiques nécessite une source externe d’événements aléatoires. Le noyau Linux utilise une source d’événements aléatoires particulièrement bonne: vous! En mesurant les écarts temporels entre vos actions, comme l’appui sur les touches et les mouvements de la souris, Linux est capable de générer un flux de nombres aléatoires de grande qualité impossible à prédire. Vous pouvez accéder à ce flux en lisant les fichiers /dev/random et /dev/urandom. Les données que vous obtenez sont issues d’un flux d’octets généré aléatoirement.

La différence entre les deux périphériques n’est visible que lorsque Linux a épuisé son stock de nombres aléatoires. Si vous essayez de lire un nombre important d’octets à partir de /dev/random mais ne générez aucune action (vous n’utilisez pas le clavier, ne bougez pas la souris ni n’effectuez aucune autre action de ce type), Linux bloque l’opération de lecture. La génération ne reprendra que lorsque vous effectuerez des actions.

Par exemple, essayez d’afficher le contenu de /dev/random en utilisant la commande od4). Chaque ligne affiche~16 nombres aléatoires.

% od -t x1 /dev/random
0000000 2c 9c 7a db 2e 79 3d 65 36 c2 e3 1b 52 75 1e 1a
0000020 d3 6d 1e a7 91 05 2d 4d c3 a6 de 54 29 f4 46 04
0000040 b3 b0 8d 94 21 57 f3 90 61 dd 26 ac 94 c3 b9 3a
0000060 05 a3 02 cb 22 0a bc c9 45 dd a6 59 40 22 53 d4

Le nombre de lignes affichées varie − il peut y en avoir très peu − mais la sortie se mettra en pause dès que Linux épuisera son stock de nombres aléatoires. Essayez maintenant de déplacer votre souris ou de saisir quelque chose au clavier et vérifiez que de nouveaux nombres aléatoires apparaissent. Pour en obtenir encore plus, vous pouvez laisser votre chat marcher sur le clavier.

Une lecture à partir de /dev/urandom, en revanche, ne bloque jamais. Si Linux tombe à court de nombre aléatoires, il utilise un algorithme de chiffrement pour générer des octets pseudo-aléatoires à partir de la dernière séquence d’octets aléatoires. Bien que ces octets soient suffisamment aléatoires pour la plupart des utilisations, ils ne satisfont pas autant de tests que ceux obtenus à partir de /dev/random.

Par exemple, si vous invoquez la commande suivante, les octets aléatoires défileront en continu, jusqu’à ce que vous tuiez le programme avec Ctrl+C:

% od -t x1 /dev/urandom
0000000 62 71 d6 3e af dd de 62 c0 42 78 bd 29 9c 69 49
0000020 26 3b 95 bc b9 6c 15 16 38 fd 7e 34 f0 ba ce c3
0000040 95 31 e5 2c 8d 8a dd f4 c4 3b 9b 44 2f 20 d1 54
...

Utiliser des nombres aléatoires provenant de /dev/random dans un programme est une chose assez facile. Le listing !!randomnumber!! présente une fonction qui génère un nombre aléatoire en utilisant les octets lus à partir de /dev/random. Souvenez-vous que la lecture est bloquée jusqu’à ce qu’il y ait suffisamment d’événements aléatoires pour la satisfaire; vous pouvez utiliser /dev/urandom à la place si vous accordez plus de priorité à la rapidité d’exécution et que vous pouvez vous contenter de nombres aléatoires d’une qualité moindre.

Listing (random_number.c) Fonction générant un nombre aléatoire à partir de /dev/random

#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
/* Renvoie un entier aléatoire entre MIN et MAX inclus. La source utilisée
   est /dev/random. */
int random_number (int min, int max)
{
  /* Stocke un descripteur de fichier pointant vers /dev/random dans une
     variable static. De cette façon, nous n'avons pas besoin d'ouvrir le
     fichier à chaque fois que la fonction est appelée. */
  static int dev_random_fd = -1;
  char* next_random_byte;
  int bytes_to_read;
  unsigned random_value;
  /* S'assure que MAX est plus grand que MIN.  */
  assert (max > min);
  /* S'il s'agit du premier appel de la fonction, ouvre un descripteur
     de fichier pointant vers /dev/random. */
  if (dev_random_fd == -1) {
    dev_random_fd = open ("/dev/random", O_RDONLY);
    assert (dev_random_fd != -1);
  }
  /* Lit suffisamment d'octets aléatoires pour remplir un entier. */
  next_random_byte = (char*) &random_value;
  bytes_to_read = sizeof (random_value);
  /* Boucle jusqu'à ce que l'on ait assez d'octets. Comme /dev/random
     est généré à partir d'actions de l'utilisateur, la lecture peut bloquer
     et ne renvoyer qu'un seul octet à la fois. */
  do {
    int bytes_read;
    bytes_read = read (dev_random_fd, next_random_byte, bytes_to_read);
    bytes_to_read -= bytes_read;
    next_random_byte += bytes_read;
  } while (bytes_to_read > 0);
  /* Calcule un nombre aléatoire dans l'intervalle demandé.  */
  return min + (random_value % (max - min + 1));
}

Périphériques loopback

Un périphérique loopback vous permet de simuler un périphérique bloc en utilisant un fichier disque ordinaire. Imaginez un lecteur de disque pour lequel les données sont écrites et lues à partir d’un fichier appelé image-disque plutôt que depuis les pistes et secteurs d’un disque physique réel ou d’une des partition d’un disque (bien sûr, le fichier image-disque doit se situer sur un disque physique, qui doit être plus grand que le disque simulé). Un périphérique loopback vous permet d’utiliser un fichier de cette façon.

Les périphériques loopback s’appellent /dev/loop0, /dev/loop1, etc. Chacun peut être utilisé pour simuler un périphérique bloc distinct. Notez que seul le superutilisateur peut paramétrer un périphérique loopback.

Un tel périphérique peut être utilisé de la même façon que n’importe quel autre périphérique bloc. En particulier, vous pouvez placer un système de fichiers sur le périphérique puis monter ce système de fichiers comme s’il résidait sur un disque ou une partition classique. Un tel système de fichiers, qui réside entièrement au sein d’un fichier sur disque ordinaire, est appelé système de fichiers virtuel.

Pour construire un système de fichiers et le monter à partir d’un périphérique loopback, suivez ces étapes:

  1. Créez un fichier vide qui contiendra le système de fichiers virtuel. La taille du fichier sera la taille du périphérique loopback une fois monté.
    Une façon pratique de construire un fichier d’une taille prédéterminée est d’utiliser la commande dd. Elle copie des blocs (de 512~octets chacun, par défaut) d’un fichier vers un autre. Le fichier /dev/zero convient parfaitement pour être utilisé comme source d’octets nuls.
    Pour construire un fichier de 10Mo appelé image-disque, utilisez la commande suivante:
    % dd if=/dev/zero of=/tmp/image-disque count=20480
    20480+0 enregistrements lus.
    20480+0 enregistrements écrits.
    % ls -l /tmp/image-disque
    -rw-rw−− 1 root root 10485760 Mar 8 01:56 /tmp/image-disque
  2. Le fichier que vous venez de créer est rempli avec des octets à 0. Avant de le monter, vous devez y placer un système de fichiers. Cette opération initialise diverses structures de contrôle nécessaires à l’organisation et au stockage de fichiers et crée le répertoire racine.
    Vous pouvez placer n’importe quel type de système de fichiers sur votre image disque. Pour créer un système de fichiers ext3 (le type le plus courant pour les disques Linux), utilisez la commande mke2fs. Comme elle est habituellement exécutée sur des périphériques bloc, et non pas des fichiers ordinaires, elle demande une confirmation:
    /sbin/mke2fs -q -j /tmp/image-disque
    /tmp/image-disque n’est pas un périphérique spécial à bloc.
    Procéder malgré tout? (y pour oui, n pour non) y

    L’option -q supprime les informations récapitulatives sur le système de fichiers nouvellement créé. Supprimez-la si vous êtes curieux.
    Désormais image-disque contient un nouveau système de fichiers comme s’il s’agissait d’un disque de 10 Mo tout neuf.
  3. Montez le système de fichiers en utilisant un périphérique loopback. Pour cela, utilisez la commande mount en spécifiant le fichier de l’image disque comme périphérique à monter. Passez également l’option de montage loop=périphérique-loopback, en utilisant l’option -o pour indiquer à mount quel périphérique loopback utiliser.
    Par exemple, pour monter notre système de fichiers image-disque, utilisez ces commandes. Souvenez-vous, seul le superutilisateur peut utiliser un périphérique loopback. La première commande crée un répertoire, /tmp/virtual-fs, que nous allons utiliser comme point de montage pour le système de fichiers virtuel.
    % mkdir /tmp/virtual-fs
    % mount -o loop=/dev/loop0 /tmp/image-disque /tmp/virtual-fs

    Désormais, l’image disque est montée comme s’il s’agissait d’un disque de 10Mo ordinaire.
    % df -h /tmp/virtual-fs
    Sys. De fich. Tail. Occ. Disp. %Occ. Monté sur
    /tmp/image-disque 9.7M 13k 9.2M 0% /tmp/virtual-fs

    Vous pouvez l’utiliser comme n’importe quel autre disque:
    % cd /tmp/virtual-fs
    % echo “Coucou !” > test.txt
    % ls -l
    total 13
    drwxr-xr-x 2 root root 12288 Mar 8 02:00 lost+found
    -rw-rw−− 1 root root 14 Mar 8 02:12 test.txt
    % cat test.txt
    Coucou !

    Notez que lost+found est un répertoire automatiquement créé par mke2fs5).
    Lorsque vous en avez fini, démontez le système de fichiers virtuel.
    % cd /tmp
    % umount /tmp/virtual-fs

    Vous pouvez supprimer image-disque si vous le désirez ou vous pouvez le monter plus tard pour accéder aux fichiers du système de fichiers virtuel. Vous pouvez également le copier sur un autre ordinateur où vous pourrez le monter − le système de fichiers que vous avez créé sera entièrement intact.

Au lieu de créer un système de fichiers à partir de rien, vous pouvez en copier un à partir d’un périphérique existant. Par exemple, vous pouvez créer l’image du contenu d’un CD-ROM simplement en le copiant à partir d’un lecteur de CD-ROM.

Si vous disposez d’un lecteur de CD-ROM IDE, utilisez le nom de périphérique correspondant, par exemple /dev/hda, décrit précédemment. Si vous disposez d’un lecteur CD-ROM SCSI, le nom de périphérique sera du type /dev/scd0. Le lien symbolique /dev/cdrom peut également exister sur votre système, il pointe alors vers le périphérique approprié. Consultez le fichier /etc/fstab pour déterminer quel périphérique correspond au lecteur de CD-ROM de votre ordinateur.

Copiez simplement le périphérique vers un fichier. Le résultat sera une image disque complète du système de fichiers du CD-ROM situé dans le lecteur − par exemple:

% cp /dev/cdrom /tmp/cdrom-image

Cette opération peut prendre plusieurs minutes selon le CD-ROM que vous copiez et la vitesse de votre lecteur. Le fichier image résultant sera relativement gros − il fera la même taille que le contenu du CD-ROM.

Vous pouvez maintenant monter cette image sans disposer du disque original. Par exemple, pour le monter sur /mnt/cdrom, utilisez cette commande:

% mount -o loop=/dev/loop0 /tmp/cdrom-image /mnt/cdrom

Comme l’image est située sur le disque dur, les temps d’accès seront bien inférieurs à ceux du disque CD-ROM original. Notez que la plupart des CD-ROM utilisent le système de fichiers ISO-9660.

PTY

Si vous exécutez la commande mount sans arguments de ligne de commande, ce qui liste les systèmes de fichiers montés sur votre système, vous remarquerez une ligne ressemblant à cela:

devpts on /dev/pts type devpts (rw,gid=5,mode=620)

Elle indique qu’un système de fichiers d’un type particulier, devpts, est monté sur /dev/pts. Ce système de fichiers, qui n’est pas associé avec un périphérique matériel, est un système de fichiers « magique » créé par le noyau Linux. Il est similaire au système de fichiers /proc; consultez le Chapitre 7 pour plus d’informations sur son fonctionnement.

Comme le répertoire /dev, /dev/pts contient des entrées correspondant à des périphériques. Mais contrairement à /dev, qui est un répertoire classique, /dev/pts est un répertoire spécial créé dynamiquement par le noyau Linux. Le contenu du répertoire varie avec le temps et reflète l’état du système.

Les fichiers de /dev/pts correspondent à des pseudo-terminaux (ou pseudo-TTY, ou PTY). Linux crée un PTY pour chaque nouvelle fenêtre de terminal que vous ouvrez et place l’entrée correspondante dans /dev/pts. Le périphérique PTY se comporte comme un terminal classique − il accepte des entrées depuis le clavier et affiche les sorties du programme lui correspondant. Les PTY sont numérotés et leur numéro correspond au nom du fichier correspondant dans /dev/pts.

Vous pouvez afficher le terminal associé à un processus grâce à la commande ps. Indiquez tty comme l’un des champ de format personnalisé avec l’option -o. Pour afficher l’identifiant de processus, le TTY et la ligne de commande de chaque processus partageant le même terminal, invoquez ps -o pid,tty,cmd.

Exemple d'utilisation des PTY

Par exemple, vous pouvez déterminer le PTY associé à une fenêtre de terminal donnée en invoquant cette commande au sein de la fenêtre:

% ps -o pid,tty,cmd
  PID TT       CMD
28832 pts/4    bash
29287 pts/4    ps -o pid,tty,cmd

La fenêtre où est lancée la commande s’exécute au sein du PTY~4.

Le PTY a un fichier correspondant dans /dev/pts:

% ls -l /dev/pts/4
crw−w−−    1 samuel tty 136, 4 Mar 8 02:56 /dev/pts/4

Notez qu’il s’agit d’un périphérique caractère et son propriétaire est celui du processus pour lequel il a été créé.

Vous pouvez lire ou écrire sur un périphérique PTY. Si vous lisez à partir de celui-ci, vous intercepterez les saisies clavier destinées au programme s’exécutant au sein du PTY. Si vous essayez d’y écrire, les données apparaîtront dans la fenêtre correspondante.

Essayez d’ouvrir un nouveau terminal et déterminez son PTY en invoquant ps -o pid,tty,cmd. Depuis une autre fenêtre, écrivez du texte sur ce périphérique. Par exemple, si le numéro de PTY du nouveau terminal est~7, invoquez cette commande depuis une autre fenêtre:

% echo "Hello, other window!" > /dev/pts/7

La sortie apparaît dans la fenêtre de terminal. Si vous la fermez, l’entrée numéro~7 de /dev/pts disparaît.

Si vous invoquez ps pour déterminer le TTY depuis un terminal virtuel en mode texte (appuyez sur Ctrl+Alt+F1 pour basculer vers le premier terminal virtuel, par exemple), vous remarquerez qu’il s’exécute au sein d’un périphérique de terminal ordinaire et non pas un PTY:

% ps -o pid,tty,cmd
  PID TT       CMD
29325 tty1     -bash
29353 tty1     ps -o pid,tty,cmd

ioctl

L’appel système ioctl est une interface destinée au contrôle de dispositifs matériels. Le premier argument de ioctl est un descripteur de fichier qui doit pointer sur le périphérique que vous voulez contrôler. Le second argument est un code de requête indiquant l’opération que vous souhaitez effectuer. Différents codes de requêtes sont disponibles pour chacun des périphériques. Selon le code, il peut y avoir des arguments supplémentaires servant à passer des données à ioctl.

La plupart des codes de requête disponibles pour les différents périphériques sont listés sur la page de manuel de ioctl_list. L’utilisation de ioctl nécessite généralement une connaissance approfondie du pilote de périphérique du matériel que vous souhaitez contrôler. Il s’agit d’un sujet qui dépasse le cadre de ce livre. Cependant, nous présentons un exemple vous donnant un aperçu de la façon dont ioctl est utilisé.

Listing (cdrom-eject.c) Éjecte un CD-ROM

#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
 
int main (int argc, char* argv[])
{
  /* Ouvre un descripteur de fichier vers le périphérique passé sur la ligne 	de commande. */
  int fd = open (argv[1], O_RDONLY);
  /* Éjecte le CD-ROM. */
  ioctl (fd, CDROMEJECT);
 
  /* Ferme le descripteur. */
  close (fd);
  return 0;
}

Le Listing !!cdromeject!! est un court programme qui éjecte le disque présent dans un lecteur de CD-ROM (si ce dernier le supporte). Il prend un argument en ligne de commande, le périphérique correspondant au lecteur de CD-ROM. Il ouvre un descripteur de fichier pointant vers le périphérique et invoque ioctl avec le code de requête CDROMEJECT. Cette requête, définie dans l’entête <linux/cdrom.h>, indique au périphérique d’éjecter le disque.

Par exemple, si votre système dispose d’un lecteur de CD-ROM connecté en tant que périphérique maître sur le second contrôleur IDE, le périphérique correspondant est /dev/hdc. Pour éjecter le disque du lecteur, invoquez cette commande:

% ./cdrom-eject /dev/hdc
1) Les utilisateurs de Windows reconnaîtront là un périphérique similaire au fichier magique LPT1 de Windows.
2) Votre imprimante peut nécessiter l’ajout de retours chariot, code ASCII 13, à la fin de chaque ligne et l’ajout d’un caractère de saut de page, code ASCII 12, à la fin de chaque page.
3) Sur la plupart des systèmes GNU/Linux, vous pouvez basculer vers le premier terminal en appuyant sur Ctrl+Alt+F1. Utilisez Ctrl+Alt+F2 pour le second terminal virtuel, etc.
4) Nous utilisons od plutôt que le programme hexdump du Listing B.4, même s’il font plus ou moins la même chose, car hexdump se termine lorsqu’il n’y a plus de données à lire, alors que od attend des données supplémentaires. L’option -t x1 indique à od d’afficher le contenu du fichier en hexadécimal.
5) Si le système de fichiers subit des dommage et que des données sont récupérées sans être associées à un fichier, elles sont placées dans lost+found.
 
livre/chap6/peripheriques.txt · Dernière modification: 2011/05/31 06:25 par jaaf
 
Recent changes RSS feed Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki Hosted by TuxFamily