Cela dépend entièrement des services que vous souhaitez avoir sur votre appareil.
Programmes
Vous pouvez faire démarrer Linux directement dans un shell . Ce n'est pas très utile en production - qui voudrait juste avoir un shell assis là - mais c'est utile comme mécanisme d'intervention lorsque vous avez un chargeur de démarrage interactif :passez init=/bin/sh
à la ligne de commande du noyau. Tous les systèmes Linux (et tous les systèmes Unix) ont un shell de style Bourne/POSIX en /bin/sh
.
Vous aurez besoin d'un ensemble d'utilitaires shell . BusyBox est un choix très courant; il contient un shell et des utilitaires communs pour la manipulation de fichiers et de texte (cp
, grep
, …), configuration réseau (ping
, ifconfig
, …), manipulation de processus (ps
, nice
, …), et divers autres outils système (fdisk
, mount
, syslogd
, …). BusyBox est extrêmement configurable :vous pouvez sélectionner les outils que vous voulez et même les fonctionnalités individuelles au moment de la compilation, pour obtenir le bon compromis taille/fonctionnalité pour votre application. Sauf sh
, le strict minimum sans lequel vous ne pouvez vraiment rien faire est mount
, umount
et halt
, mais il serait atypique de ne pas avoir aussi cat
, cp
, mv
, rm
, mkdir
, rmdir
, ps
, sync
et quelques autres. BusyBox s'installe en tant que binaire unique appelé busybox
, avec un lien symbolique pour chaque utilitaire.
Le premier processus sur un système Unix normal est appelé init
. Son travail consiste à démarrer d'autres services. BusyBox contient un système d'initialisation. En plus du init
binaire (généralement situé dans /sbin
), vous aurez besoin de ses fichiers de configuration (généralement appelés /etc/inittab
- certains remplacements d'init modernes suppriment ce fichier mais vous ne les trouverez pas sur un petit système embarqué) qui indiquent quels services démarrer et quand. Pour BusyBox, /etc/inittab
est facultatif ; s'il manque, vous obtenez un root shell sur la console et le script /etc/init.d/rcS
(emplacement par défaut) est exécuté au démarrage.
C'est tout ce dont vous avez besoin, au-delà bien sûr des programmes qui permettent à votre appareil de faire quelque chose d'utile. Par exemple, sur mon routeur domestique exécutant une variante OpenWrt, les seuls programmes sont BusyBox, nvram
(pour lire et modifier les paramètres dans la NVRAM) et les utilitaires de mise en réseau.
À moins que tous vos exécutables ne soient liés statiquement, vous aurez besoin du chargeur dynamique (ld.so
, qui peuvent être appelées par des noms différents selon le choix de libc et les architectures de processeur) et toutes les bibliothèques dynamiques (/lib/lib*.so
, peut-être certains d'entre eux en /usr/lib
) requis par ces exécutables.
Structure des répertoires
Le Filesystem Hierarchy Standard décrit la structure commune des répertoires des systèmes Linux. Il est orienté vers les installations de bureau et de serveur :une grande partie peut être omise sur un système embarqué. Voici un minimum typique.
/bin
:programmes exécutables (certains peuvent être en/usr/bin
à la place)./dev
:nœuds de périphérique (voir ci-dessous)/etc
:fichiers de configuration/lib
:bibliothèques partagées, y compris le chargeur dynamique (sauf si tous les exécutables sont liés statiquement)/proc
:point de montage pour le système de fichiers proc/sbin
:programmes exécutables. La distinction avec/bin
est-ce/sbin
est pour les programmes qui ne sont utiles qu'à l'administrateur système, mais cette distinction n'a pas de sens sur les appareils embarqués. Vous pouvez faire/sbin
un lien symbolique vers/bin
./mnt
:pratique à avoir sur les systèmes de fichiers racine en lecture seule comme point de montage scratch pendant la maintenance/sys
:point de montage pour le système de fichiers sysfs/tmp
:emplacement des fichiers temporaires (souvent untmpfs
montage)/usr
:contient les sous-répertoiresbin
,lib
etsbin
./usr
existe pour les fichiers supplémentaires qui ne sont pas sur le système de fichiers racine. Si vous ne l'avez pas, vous pouvez faire/usr
un lien symbolique vers le répertoire racine.
Fichiers de l'appareil
Voici quelques entrées typiques dans un /dev
minimal :
console
full
(y écrire rapporte toujours "pas d'espace disponible sur l'appareil")log
(un socket que les programmes utilisent pour envoyer des entrées de journal), si vous avez unsyslogd
démon (tel que celui de BusyBox) lisant à partir de celui-cinull
(agit comme un fichier toujours vide)ptmx
et unpts
répertoire, si vous souhaitez utiliser des pseudo-terminaux (c'est-à-dire tout terminal autre que la console) - par ex. si l'appareil est en réseau et que vous souhaitez entrer telnet ou sshrandom
(renvoie des octets aléatoires, risque de bloquer)tty
(désigne toujours le terminal du programme)urandom
(renvoie des octets aléatoires, ne bloque jamais mais peut être non aléatoire sur un appareil fraîchement démarré)zero
(contient une séquence infinie d'octets nuls)
Au-delà de cela, vous aurez besoin d'entrées pour votre matériel (à l'exception des interfaces réseau, celles-ci n'obtiennent pas d'entrées dans /dev
) :ports série, stockage, etc.
Pour les périphériques intégrés, vous devez normalement créer les entrées de périphérique directement sur le système de fichiers racine. Les systèmes haut de gamme ont un script appelé MAKEDEV
pour créer /dev
entrées, mais sur un système embarqué, le script n'est souvent pas intégré à l'image. Si certains matériels peuvent être branchés à chaud (par exemple, si le périphérique dispose d'un port hôte USB), alors /dev
doit être géré par udev (vous pouvez toujours avoir un ensemble minimal sur le système de fichiers racine).
Actions au démarrage
Au-delà du système de fichiers racine, vous devez en monter quelques autres pour un fonctionnement normal :
- procfs sur
/proc
(presque indispensable) - sysfs sur
/sys
(presque indispensable) tmpfs
système de fichiers sur/tmp
(pour permettre aux programmes de créer des fichiers temporaires qui seront en RAM, plutôt que sur le système de fichiers racine qui peut être en flash ou en lecture seule)- tmpfs, devfs ou devtmpfs sur
/dev
si dynamique (voir udev dans "Device files" ci-dessus) - devpts sur
/dev/pts
si vous souhaitez utiliser des [pseudo-terminaux (voir la remarque surpts
ci-dessus)
Vous pouvez faire un /etc/fstab
déposer et appeler le mount -a
, ou exécutez mount
manuellement.
Démarrez un démon syslog (ainsi que klogd
pour les journaux du noyau, si le syslogd
programme ne s'en occupe pas), si vous avez un endroit où écrire des journaux.
Après cela, l'appareil est prêt à démarrer les services spécifiques à l'application.
Comment créer un système de fichiers racine
C'est une histoire longue et variée, donc tout ce que je vais faire ici, c'est donner quelques conseils.
Le système de fichiers racine peut être conservé dans la RAM (chargé à partir d'une image (généralement compressée) dans la ROM ou la mémoire flash), ou sur un système de fichiers sur disque (stocké dans la ROM ou la mémoire flash), ou chargé à partir du réseau (souvent via TFTP) le cas échéant . Si le système de fichiers racine est en RAM, faites-en initramfs - un système de fichiers RAM dont le contenu est créé au démarrage.
De nombreux frameworks existent pour assembler des images racine pour les systèmes embarqués. Il y a quelques pointeurs dans la FAQ de BusyBox. Buildroot est populaire, vous permettant de créer une image racine complète avec une configuration similaire au noyau Linux et à BusyBox. OpenEmbedded est un autre framework de ce type.
Wikipédia a une liste (incomplète) des distributions Linux embarquées populaires. Un exemple de Linux embarqué que vous pouvez avoir près de chez vous est la famille de systèmes d'exploitation OpenWrt pour les appareils réseau (populaire sur les routeurs domestiques des bricoleurs). Si vous voulez apprendre par l'expérience, vous pouvez essayer Linux à partir de zéro, mais il est orienté vers les systèmes de bureau pour les amateurs plutôt que vers les appareils embarqués.
Une note sur le noyau Linux par rapport au noyau Linux
Le seul comportement intégré au noyau Linux est le premier programme lancé au démarrage. (Je n'entrerai pas dans les subtilités d'initrd et d'initramfs ici.) Ce programme, traditionnellement appelé init, a le processus ID 1 et a certains privilèges (immunité aux signaux KILL) et responsabilités (récolte des orphelins). Vous pouvez exécuter un système avec un noyau Linux et démarrer ce que vous voulez comme premier processus, mais alors ce que vous avez est un système d'exploitation basé sur le noyau Linux, et non ce qu'on appelle normalement "Linux" - Linux, dans le bon sens du terme, est un système d'exploitation de type Unix dont le noyau est le noyau Linux. Par exemple, Android est un système d'exploitation qui n'est pas de type Unix mais basé sur le noyau Linux.
Tout ce dont vous avez besoin est un exécutable lié statiquement, placé sur le système de fichiers, de manière isolée. Vous n'avez pas besoin d'autres fichiers. Cet exécutable est le processus init. Il peut s'agir d'une boîte occupée. Cela vous donne un shell et une foule d'autres utilitaires, tout en soi. Vous pouvez accéder à un système entièrement fonctionnel simplement en exécutant des commandes manuellement dans busybox pour monter le système de fichiers racine en lecture-écriture, créer des nœuds /dev, exec real init, etc.
Si vous n'avez pas besoin d'utilitaires shell, un mksh
lié statiquement binaire (par exemple contre klibc - 130K sur Linux/i386) fera l'affaire. Vous avez besoin d'un /linuxrc
ou /init
ou /sbin/init
script qui appelle simplement mksh -l -T!/dev/tty1
en boucle :
#!/bin/mksh
while true; do
/bin/mksh -l -T!/dev/tty1
done
Le -T!$tty
l'option est un ajout récent à mksh
qui lui dit de générer un nouveau shell sur le terminal donné et de l'attendre. (Avant cela, il n'y avait que -T-
pour démoniser un programme et -T$tty
pour apparaître sur un terminal mais pas l'attendre. Ce n'était pas très agréable.) Le -l
l'option lui dit simplement d'exécuter un shell de connexion (qui lit /etc/profile
, ~/.profile
et ~/.mkshrc
).
Cela suppose que votre terminal est /dev/tty1
, remplaçant. (Avec plus de magie, le terminal peut être trouvé automatiquement. /dev/console
ne vous donnera pas le contrôle total du travail.)
Vous avez besoin de quelques fichiers en /dev
pour que cela fonctionne :
- /dev/console
- /dev/null
- /dev/tty
- /dev/tty1
Démarrage avec l'option noyau devtmpfs.mount=1
élimine le besoin d'un /dev
rempli , laissez-le simplement être un répertoire vide (adapté à une utilisation en tant que point de montage).
Vous voudrez normalement avoir quelques utilitaires (de klibc, busybox, beastiebox, toybox ou toolbox), mais ils ne sont pas vraiment nécessaires.
Vous pouvez ajouter un ~/.mkshrc
fichier, qui configure $PS1 et certains alias et fonctions de base du shell.
Une fois, j'ai créé un initrd 171K compressé (371K non compressé) pour Linux/m68k en utilisant uniquement mksh (et son exemple de fichier mkshrc) et klibc-utils. (C'était avant que -T ! soit ajouté au shell, donc il a engendré le shell de connexion sur /dev/tty2
à la place et renvoyait un message à la console indiquant à l'utilisateur de changer de terminal.) Cela fonctionne bien.
C'est un minimum vraiment strict mettre en place. Les autres réponses fournissent d'excellents conseils pour des systèmes un peu plus performants. C'est vraiment un cas particulier.
Avis de non-responsabilité :je suis le développeur mksh.