Construction d'un système LINUX embarqué

Pierre Ficheux (pierre@alienor.fr)

Septembre 2000


0. Résumé

Le but de cet article est de présenter les différentes étapes de la réalisation d'un système LINUX embarqué (embeddable LINUX). L'article détaille les différents éléments majeurs du système ainsi que les étape de la réduction de l'occupation mémoire et disque. Nous aborderons également quelques techniques pratiques propres à la réalisation de systèmes embarqués. L'article s'appuie sur une réalisation personnelle de l'auteur. Il ne s'agit pas de la présentation de la revue d'un système embarqué de plus mais plutot d'une démarche pédagogique.

1. A propos de la course aux performances

La chute vertigineuse des couts du hardware ces dernières années a provoqué une inflation dans l'espace utilisé par les systèmes d'exploitation modernes. Alors que certains d'entre nous ont débuté avec 1Ko de mémoire vive et un système sur 8Ko de ROM (le ZX-81 !) il n'est pas rare aujourd'hui de voir des adolescents pester contre le PII de l'année précédente qui n'affiche pas assez vite les formes plantureuses de Lara Croft :-)

La banalisation des performances a quelques effets pervers:

L'exemple de plus flagrant de cette course à la consommation est bien entendu le système MS Windows et les applications associées pour lesquelles chaque version est accompagnée d'un certain embompoint compensé par l'achat de la dernière carte 3D, de quelques Go de plus ou d'une barrette de RAM supplémentaire.

La tendance n'épargne pas les systèmes LINUX dont les distributions les plus célèbres prennent de plus en plus de poids. J'ai longtemps utilisé ma première distribution avec un kernel 0.99 puis 1.0 sur un 486SX25 avec 8Mo de RAM, peux-t-on l'imaginer sur les distributions standards d'aujourd'hui ?

Un avantage notable avec LINUX est la complète transparence du système. Un utilisateur averti pourra à partir d'une configuration standard créer un système très optimisé tant au niveau de l'espace disque que de la mémoire utilisée. A partir d'un certain niveau extrème de réduction, on pourra parler de système embarqué (embedded ou embeddable).

2. Définition d'un système embarqué

Un système embarqué est susceptible d'être utilisé dans un environnement matériel de faible performances (si l'on compare au PC de bureau d'aujourd'hui). Si l'ajout de quelques Mo de mémoire sur un PC de bureau n'a pas une grosse influence sur le budget d'un utilisateur, le gain de quelques Mo sur un produit de grande consommation (téléphone, équipement automobile, organiseur personnel) a une énorme influence sur le cout final.

Cependant, l'évolution du matériel permet aujourd'hui d'envisager des systèmes d'exploitation embarquées ayant les même caractéristiques qu'un système utilisé sur une machine classique, ce qui présente un triple intérêt:

Cette même évolution permet d'envisager une migration rapide des produits de large consommation: téléphonie, audio, vidéo, electro-ménager, équipement automobile vers des versions plus évoluées et communicantes (les internet appliances). Un certain nombre d'applications de ce type sont citées à la fin de l'article.

3. Construction du système

3.1 Choix du matériel

La réalisation actuelle concerne un système x86 (Intel et compatibles). Dans un premier temps, le plus simple est de réaliser la construction du système sur une partition spécifique d'un disque dur classique sur lequel on effectuera les configurations successives définies ci-dessous (en particulier la réduction du système). On disposera sur une autre partition d'un système complet ce qui permettra de démarrer alternativement sur l'une ou l'autre des partitions afin de tester l'évolution de la partition réduite.

Concernant la cible du système définitif, diverses solutions sont disponibles:

Les constructeurs suivants fournissent de telles solutions (IDE ou non)

3.2 Principe général de la construction

La construction d'un système embarquée passe par l'analyse du système LINUX standard, l'optimisation de sa procédure de démarrage et la réduction de l'occupation de celui-ci.

La structure générale simplifiée d'un système LINUX est la suivante:

La réduction du système passe par les étapes suivantes:

  1. optimisation de la procédure de démarrage du système: le temps de démarrage d'un système standard est relativement long de part le nombre de services installés par défaut (http, smtp, etc...). Si l'on réduit le nombre de services, la procédure de démarrage en sera grandement accélérée. Pour donner un ordre d'idée, le temps de démarrage du système réalisé (hors chargement du BIOS) est inférieur à 10 secondes.

  2. réduction drastique du nombre de commandes disponibles et des bibliothèques partagées. C'est cette étape qui permet de réduire fortement la taille du système, le nombre de commandes indispensables au fonctionnement du système étant très réduit.

  3. optimisation du noyau en fonction des fonctionnalités nécessaires (pilotes de périphériques, réseau ou non, etc...). Les distributions de base installent en général un grand nombre de pilotes et de fonctionnalités afin de s'adapter au plus grand nombre de configurations matérielles possibles. Dans le cas d'un système embarqué, le matériel est parfaitement connu donc la réduction est aisée. Cependant, les pilotes étant peu gourmants en espace disque, le gain sera nettement plus faible que dans l'étape précédente.

  4. réduction et simplification du nombre de fichiers et répertoires de configuration comme /etc contenant la majorités des fichiers de config. La aussi la taille occupée est relativement faible.

  5. suppression du système de swap: un système embarqué est destiné à un usage bien défini et sera donc suffisamment dimensionné en mémoire vive pour éviter l'utilisation d'une partition de swap.

3.3 Optimisation du démarrage

Le schéma de démarrage d'un système LINUX est le suivant:
  1. boot du système par LILO (LInux LOader) ou un programme équivalent

  2. chargement du noyau

  3. lancement par le noyau du processus init (/sbin/init)

  4. lecture du fichier /etc/inittab par le processus init. Ce fichier contient en général le nom du script de démarrage:
    # System initialization (runs when system boots).
    si:S:sysinit:/etc/rc.d/rc.S
    
    

  5. le script en question poursuit l'initialisation du système

Le distributions LINUX classiques utilisent en général un système de démarrage hérité des versions UNIX® System V, basé sur le lancement de services en fonction du niveau d'exécution (runlevel). Ce système a le gros avantage de définir proprement la localisation des différents scripts de démarrage dans des sous-répertoires correspondants aux niveaux d'exécution:

  drwxr-xr-x   2 root     root         1024 fév 10  2000 init.d
  -rwxr-xr-x   1 root     root         1593 jun  7  1998 rc
  -rwxr-xr-x   1 root     root         1175 aoû  1 14:29 rc.local
  -rwxr-xr-x   1 root     root         7355 jun 18  1998 rc.sysinit
  drwxr-xr-x   2 root     root         1024 fév 10  2000 rc0.d
  drwxr-xr-x   2 root     root         1024 fév 10  2000 rc1.d
  drwxr-xr-x   2 root     root         1024 fév 10  2000 rc2.d
  drwxr-xr-x   2 root     root         1024 aoû  4 14:53 rc3.d
  drwxr-xr-x   2 root     root         1024 aoû  4 14:53 rc4.d
  drwxr-xr-x   2 root     root         1024 aoû  4 14:53 rc5.d
  drwxr-xr-x   2 root     root         1024 fév 10  2000 rc6.d

La gestion de ce système est cependant relativement complexe pour un système embarqué comprenant normalement très peu de services à démarrer. Dans notre cas, les scripts de démarrage seront tous localisés dans le répertoire /etc/rc.d:

  -r-xr-xr-x   1 root     root         1634 mai 24 15:06 rc.S
  -rwxr-xr-x   1 root     root         1148 mai 24 11:45 rc.inet1
  -rwxr-xr-x   1 root     root          264 mai 24 11:45 rc.inet2
et les fichiers de configuration associé dans le répertoire /etc/sysconfig:
  -rw-r--r--   1 root     root           41 mai 24 11:45 keyboard
  -rw-r--r--   1 root     root          181 mai 24 11:45 network

Le script rc.S effectue les actions suivantes:

  1. le démarrage du programme /sbin/update destiné à vider les buffers mémoire sur le disque:
    # Start update.
    /sbin/update &
    

  2. la vérification des filesystems:
    # Check the integrity of all filesystems
    /sbin/fsck -A -a -T
    

  3. le montage du root filesystem et des autres filesystems définis dans /etc/fstab:
    # Remount the root filesystem in read-write mode
    /sbin/mount -w -n -o remount /
    /sbin/mount -at nonfs
    

  4. l'initialisation du réseau:
    # Network
    /etc/rc.d/rc.inet1 start
    /etc/rc.d/rc.inet2 start
    
  5. le lancement de l'applicatif principal, celui pour lequel le système embarqué est utilisé. Si le système est destiné à une console graphique (client léger), on pourra lancer le système graphique à ce moment la (par exemple en utilisant xinit). Si l'on désire obtenir immédiatement un interprèteur de commande sur la console système, on pourra lancer /bin/sh:
    # Shell
    /bin/sh
    

Les scripts rc.inet1 et rc.inet2 sont appelés en fin du script rc.S pour l'initialisation du réseau:

La configuration du réseau est définie dans le fichier network:

  HOSTNAME=myname
  DOMAINNAME=some.where
  DEVICE=eth0
  IPADDR=192.168.1.1
  NETWORK=192.168.1.0
  GATEWAY=
  NETMASK=255.255.255.0
  BROADCAST=192.168.1.255
  DNS1=
  DNS2=

Le démarrage du réseau se fait de manière classique par l'initialisation de l'interface locale:

  # Loopback
  /sbin/ifconfig lo 127.0.0.1
  /sbin/route add -net 127.0.0.0
  /sbin/ifconfig lo up

Si une adresse IP fixe est définie, on initialise l'interface ethernet, le routage ainsi qu'éventuellement le DNS (fichier /etc/resolv.conf):

  # Ethernet
  if [ "$IPADDR" != "" ]
  then
    /sbin/ifconfig ${DEVICE} ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK}
    /sbin/route add -net ${NETWORK} netmask ${NETMASK}
    /sbin/ifconfig ${DEVICE} up
	
    # external addresses
    if [ "$GATEWAY" != "" ]
    then
      /sbin/route add default gw ${GATEWAY}
    fi
  fi

  # DNS
  if [ "$DNS1" != "" ]; then
    echo "nameserver $DNS1" >> $RESOLV
  fi

  if [ "$DNS2" != "" ]; then
    echo "nameserver $DNS2" >> $RESOLV
  fi

Dans le cas d'un système embarqué, il est très intéressant de pouvoir gérer une connexion DHCP (adresse IP dynamique), très utilisée pour les internet appliances. Il suffira pour cela de ne pas définir d'adresse dans le fichier network:

  if [ "$DEVICE" != "" -a "$IPADDR" = "" ]; then
        echo -n "Using DHCP for ${DEVICE}"
	/sbin/dhcpcd ${DEVICE}
	for i in 1 2 3 4 5 6 7 8 9 10 11 12
	do
		echo -n "."
		if [ -r /etc/dhcpc/hostinfo-${DEVICE} ]; then
			DHCP_OK=true
			break
		fi
		sleep 5
	done

	if [ "$DHCP_OK" = "" ]; then
		echo "ERROR !"
	else
		echo "OK."
	fi	
  fi

3.4 Réduction du nombre de commandes et bibliothèques

Cette phase représente le plus gros travail d'analyse du système. Il convient en effet de bien comprendre le fonctionnement du système et bien définir les taches qu'il aura à accomplir pour ne laisser disponible que le minimum nécessaire.

En général, les commandes indispensables au démarrage du système se trouvent sur le répertoire /sbin:

  -rwxr-xr-x   1 root     root        25144 mai 24 11:45 dhcpcd
  -rwxr-xr-x   1 root     root        69252 mai 24 11:45 e2fsck
  -rwxr-xr-x   1 root     root         9008 mai 24 11:45 fsck
  -r-xr-xr-x   1 root     root        18761 mai 24 11:45 ifconfig
  -r-xr-xr-x   1 root     root        16757 mai 24 11:45 inetd
  -r-xr-xr-x   1 root     root        20592 mai 24 11:45 init
  -rwxr-xr-x   1 root     root        58744 mai 24 11:45 lilo
  -rwsr-xr-x   1 root     root        36084 mai 24 11:45 mount
  -r-xr-xr-x   1 root     root         9513 mai 24 11:45 route
  -rwsr-xr-x   1 root     root        20200 mai 24 11:45 umount
  -rwxr-xr-x   1 root     root         7077 mai 24 11:45 update

On trouve sur le répertoire /bin les commandes moins orientées systèmes dont le nombre dépendra de l'utilisation du système:

  -rwxr-xr-x   1 root     root        62660 mai 24 11:44 ash
  -r-xr-xr-x   1 root     root         7737 mai 24 11:44 cat
  -rwxr-xr-x   1 root     root         9232 mai 24 11:44 chmod
  -rwxr-xr-x   1 root     root        19652 mai 24 11:44 cp
  -rwxr-xr-x   1 root     root         5268 mai 24 11:44 free
  -rwxr-xr-x   1 root     root        64161 mai 24 11:44 grep
  -r-xr-xr-x   1 root     root         5696 mai 24 11:44 hostname
  -rwxr-xr-x   1 root     root        10644 mai 24 11:44 ln
  -r-xr-xr-x   1 root     root        26976 mai 24 11:44 ls
  -r-xr-xr-x   1 root     root         7416 mai 24 11:44 mkdir
  -rwsr-xr-x   1 root     root        36084 mai 24 11:44 mount
  -rwxr-xr-x   1 root     root        12464 mai 24 11:44 mv
  -r-xr-xr-x   1 root     root        28948 mai 24 11:44 ps
  -rwxr-xr-x   1 root     root         9424 mai 24 11:44 rm
  -rwxr-xr-x   1 root     root        53672 mai 24 11:44 sed
  lrwxrwxrwx   1 root     root            4 mai 24 11:44 sh -> ash
  -rwxr-xr-x   1 root     root         4421 mai 24 11:44 sleep
  -rwxr-xr-x   1 root     root          380 mai 24 11:44 sync
  -rwxr-xr-x   1 root     root        10713 mai 24 11:44 tail

Le choix des commandes dépend directement de l'applicatif final installé sur le système, en particulier:

Le choix des bibliothèques à conserver est plus compliqué dans la mesure ou il faut connaitre exactement les bibliothèques utilisées par les programmes restants. On peut faire cela par la commande ldd:

[pierre@atkins pierre]$ ldd /sbin/init 
        libutil.so.1 => /lib/libutil.so.1 (0x40007000)
        libc.so.6 => /lib/libc.so.6 (0x4000a000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
[pierre@atkins pierre]$ ldd /bin/cat   
        libc.so.6 => /lib/libc.so.6 (0x40007000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)

Il faut noter que l'ajout de commandes supplémentaires peut entrainer l'ajout de biblitohèques partagées, exemple pour le client telnet:

[pierre@atkins pierre]$ ldd /usr/bin/telnet 
        libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40007000)
        libc.so.6 => /lib/libc.so.6 (0x40045000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
Notons également que les distributions les plus récentes sont en général plus gourmandes en espace disque. Ceci s'explique le plus souvent par des fonctionnalités supplémentaires ou bien une meilleure modularité dans les bibliothèques utilisées mais dans le cas de la construction d'un système embarquée, les contraintes de ce type sont moins prépondérantes et le critère d'espace utilisé est souvent le plus important.

On peut donc se poser la question de la bibliothèque C à utiliser. Les anciennes distributions LINUX (comme la RedHat 4.2) utilisaient la libc5 alors que les distributions plus récentes (RedHat 5.x, compatibles, et suivantes...) utilisent la libc6 (ou glibc2). La glibc a apporté un grand nombre d'avantages concernant les fonctionnalités et la modularité mais le fait de baser un système embarqué sur la libc5 n'est pas forcément une aberration.

Le bibliothèques à utiliser dans de le case d'une distribution basé sur la glibc-2.0 sont les suivantes:

  -rwxr-xr-x   1 root     root        40452 jan  5  2000 ld-2.0.7.so
  lrwxrwxrwx   1 root     root           11 mai 23 18:16 ld-linux.so.2 -> ld-2.0.7.so
  lrwxrwxrwx   1 root     root           11 mai 23 18:16 ld.so -> ld.so.1.9.5
  -rwxr-xr-x   1 root     root       104236 jan  5  2000 ld.so.1.9.5
  -rwxr-xr-x   1 root     root       650524 jan  5  2000 libc-2.0.7.so
  lrwxrwxrwx   1 root     root           13 mai 23 18:16 libc.so.6 -> libc-2.0.7.so
  -rwxr-xr-x   1 root     root       181993 jan  5  2000 libcrypt-2.0.7.so
  lrwxrwxrwx   1 root     root           17 mai 23 18:16 libcrypt.so.1 -> libcrypt-2.0.7.so
  -rwxr-xr-x   1 root     root        37146 jan  5  2000 libdl-2.0.7.so
  lrwxrwxrwx   1 root     root           14 mai 23 18:16 libdl.so.2 -> libdl-2.0.7.so
  -rwxr-xr-x   1 root     root        35622 jan  5  2000 libproc.so.1.2.6
  -rwxr-xr-x   1 root     root        34674 jan  5  2000 libutil-2.0.7.so
  lrwxrwxrwx   1 root     root           16 mai 23 18:16 libutil.so.1 -> libutil-2.0.7.so

et dans le cas de la libc5:

  lrwxrwxrwx   1 root     root           18 mai 24 11:45 ld-linux.so.1 -> ld-linux.so.1.7.14
  -r-xr-xr-x   1 root     root        21531 mai 24 11:45 ld-linux.so.1.7.14
  lrwxrwxrwx   1 root     root           12 mai 24 11:45 ld.so -> ld.so.1.7.14
  -r-xr-xr-x   1 root     root        24580 mai 24 11:45 ld.so.1.7.14
  lrwxrwxrwx   1 root     root           14 mai 24 11:45 libc.so.5 -> libc.so.5.4.44
  -rw-r--r--   1 root     root       580816 mai 24 11:45 libc.so.5.4.44

De même il sera parfois nécessaire de recompiler certains applicatifs à partir des sources de manière à supprimer certaines fonctionnalités superflus qui peuvent augmenter la taille du code ou nécessiter l'ajout de bibliothèques partagées supplémentaires.

Prenons l'exemple des programmes login et passwd utilisés pour la validation des mots de passe:

[root@atkins /root]# ldd /bin/login 
        libcrypt.so.1 => /lib/libcrypt.so.1 (0x40007000)
        libpam.so.0 => /lib/libpam.so.0 (0x40034000)
        libdl.so.2 => /lib/libdl.so.2 (0x4003b000)
        libpam_misc.so.0 => /lib/libpam_misc.so.0 (0x4003f000)
        libc.so.6 => /lib/libc.so.6 (0x40042000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)

[root@atkins /root]# ldd /usr/bin/passwd
        libpwdb.so.0 => /lib/libpwdb.so.0 (0x40007000)
        libpam.so.0 => /lib/libpam.so.0 (0x40048000)
        libpam_misc.so.0 => /lib/libpam_misc.so.0 (0x4004f000)
        libdl.so.2 => /lib/libdl.so.2 (0x40053000)
        libc.so.6 => /lib/libc.so.6 (0x40056000)
        libcrypt.so.1 => /lib/libcrypt.so.1 (0x400fb000)
        libnsl.so.1 => /lib/libnsl.so.1 (0x40128000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)

Ce deux utilitaires utilisent PAM (Pluggable Authentification Module) qui impose la présence des bibliothèques et des fichiers de configuration correspondant. La recompilation de ces utilitaires SANS le support PAM peut simplifier la structure du système final.

L'absence totale d'outil de configuration sur le système (comme éditeurs de texte, clients ftp/telnet, etc...) peut se révèler très gènante lors de la mise au point de la plate-forme finale. Une solution simple est de définir un répertoire /extra sur lequel on pourra placer les programmes ou bibliothèques utiles à la mise au point mais à supprimer dans la version finale:

  # ls -l /extra
  total 4
  drwxr-xr-x   2 root     root         1024 Sep  5 16:08 bin
  drwxr-xr-x   2 root     root         1024 Sep  5 09:09 boot
  drwxr-xr-x   2 root     root         1024 Sep  5 16:09 etc
  drwxr-xr-x   2 root     root         1024 Sep  5 15:01 lib
  lrwxrwxrwx   1 root     root            3 Sep  5 09:09 sbin -> bin

3.5 Configuration du noyau

Une fois la taille du système largement réduite, on peut s'attaquer à l'optimisation du noyau en fonction des besoins du système. Le gain en espace disque ne sera pas énorme mais le temps de chargement du noyau sera réduit et son fonctionnement optimisé. J'ai personnellement testé avec un noyau 2.0 (2.0.36) comportant moins d'options de compilation que les noyaux 2.2.

La principale optimisation consiste à supprimer tous les pilotes non utilisés par le matériel prévu ou les fonctionnalités finales du système. Pour cela, on utilisera la méthode classique de configuration du noyau LINUX:

  cd /usr/src/linux
  make xconfig
puis
  make dep; make clean; make zImage; make modules

La suppression des pilotes peut affecter en vrac:

Concernant les modules chargeable, on notera qu'il n'est pas forcément nécessaire de valider leur utilisation, leur intéret principal étant la possibilité d'obtenir un noyau de taille raisonnable malgré la présence d'un grand nombre de pilotes. La fonction de chargement/déchargement dynamique n'a pas forcément non plus un grand intérêt dans le cas d'un système embarqué destiné à une tache bien définie. Il est cependant simple de valider le support des modules en ajoutant le programme /sbin/kerneld et le répertoire /lib/modules.

On peut également effectuer quelques modifications plus avancée du noyau LINUX comme par exemple la suppression des messages de boot. Cette modification peut-être intéressante afin d'éviter au démarrage d'être trop verbeux en cas de disponibilité d'une console de visualisation.

Ceci peut se faire très facilement en ajoutant le code suivant en haut de la fonction printk() définie dans kernel/printk.c:

	  switch (my_anim) {
	  case 0 : 
	    (*console_print_proc)("\\");
	    break;

	  case 1 : 
	    (*console_print_proc)("|");
	    break;

	  case 2 : 
	    (*console_print_proc)("/");
	    break;

	  default : 
	    (*console_print_proc)("-");
	    break;
	  }
	  
	  if (my_anim == 3)
	    my_anim = 0;
	  else
	    my_anim++;
	  (*console_print_proc)("\r");
	  return 0;
	}

L'affichage des messages de trace sera alors remplacé par une petite animation tournante.

L'installation du noyau se fera de manière classique par la copie du fichier zImage sur le répertoire /boot.

3.6 Configuration du répertoire /etc

Le répertoire /etc/ est naturellement peu gourmant en espace disque (1 ou 2 Mo en moyenne). On s'attachera cependant à réduire la liste des fichiers utiles au strict minimun. Le contenu de ces même fichiers sera également optimisé, comme par exemple la réduction de la liste des services disponibles dans /etc/services et /etc/inetd.conf. Voici l'exemple d'une session telnet vers un système reduit:
[root@atkins /root]# telnet 194.51.49.150
Trying 194.51.49.150...
Connected to 194.51.49.150.
Escape character is '^]'.

Linux 2.0.36 (poste1) (ttyp0)


poste1.local.com1.fr login: root

# ls -l /etc# ls -l /etc
total 35
drwxr-xr-x   2 root     root         1024 Sep  5 17:36 dhcpc
drwxr-xr-x   2 root     root         1024 Sep  5 09:09 fs
-r--r--r--   1 root     root           88 Sep  5 09:09 fstab
-r--r--r--   1 root     root          330 Sep  5 09:09 group
-r--r--r--   1 root     root           27 Sep  5 09:09 host.conf
-rw-r--r--   1 root     root          118 Sep  7 09:51 hosts
-r--r--r--   1 root     root          112 Sep  5 09:09 hosts.ref
-r--r--r--   1 root     root          325 Sep  7 09:45 inetd.conf
-r--r--r--   1 root     root          636 Sep  5 09:09 inittab
-rw-r--r--   1 root     root          451 Sep  5 09:09 ld.so.cache
-rw-r--r--   1 root     root           16 Sep  5 09:09 ld.so.conf
-rw-r--r--   1 root     root          317 Sep  5 15:12 lilo.conf
-rw-r--r--   1 root     root           47 Sep  7 09:51 mtab
-rw-r--r--   1 root     root          180 Sep  5 15:20 passwd
-rw-r--r--   1 root     root           51 Sep  5 09:09 profile
-r--r--r--   1 root     root          595 Sep  5 09:09 protocols
----------   1 root     root        12288 Sep  5 16:09 psdevtab
dr-xr-xr-x   2 root     root         1024 Sep  5 16:11 rc.d
-rw-r--r--   1 root     root           23 Sep  7 09:51 resolv.conf
-r--r--r--   1 root     root          230 Sep  7 09:49 services
-r--r--r--   1 root     root           18 Sep  5 09:09 shells
drwxr-xr-x   2 root     root         1024 Sep  5 17:34 sysconfig
-r--r--r--   1 root     root         1868 Sep  5 09:09 termcap
-rw-r--r--   1 root     root            0 Sep  5 09:09 utmp
-rw-r--r--   1 root     root            0 Sep  5 09:09 wtmp
# du -s /etc
47      /etc

Le répertoire /etc a été réduit à 47 Ko, sachant qu'il contient les scripts de démarrage dans rc.d et les fichiers de config dans sysconfig.

4. Utilisation d'un disque mémoire (RAMdisk)

Le cout de la mémoire flash au méga-octet étant encore assez élevé, on peut imaginer d'utiliser un disque mémoire ramdisk afin de limiter la taille de mémoire flash nécessaire. L'idée est de créer des packages (par exemple au format tar+gz ou tar+bz2) que l'on stockera sur un répertoire /archives du disque flash.

Le principe est simple:

Il existe bien entendu d'autre solutions plus évoluées mais aussi plus complexes à mettre en oeuvre comme par exemple l'utilisation de filesystems compressés comme le JFFS développé par la société AXIS, voir les liens en fin d'article.

5. Conclusion

Cet article a proposé un petit tour d'horizon des méthodes utilisables pour la réduction d'un système LINUX. Si l'on fait le bilan de la distribution installée, on obtient les resultats suivant:

# cd /
# du -s .
3549    .
# du -s extra
1519    extra
La partie définitive du système (sans le /extra) occupe donc un peu moins de 2 Mo ce qui est largement suffisant pour les disques flash de plus petite capacité (4Mo).

De part sa structure ouverte et modulaire, LINUX est particulièrement bien adapté à la construction de micro-systèmes. La preuve en est la société Lynx Real-Time Systems, un des leaders des systèmes embarqués depuis plusieurs années, qui a effectué une migration complète vers LINUX au point même de changer son nom en LynuxWorks!

LINUX everywhere est pour demain...

6. Bibliographie