8.2. Gestion des paquets

On nous a souvent demandé d’ajouter la gestion des paquets au livre LFS. Un gestionnaire de paquets permet de suivre l'installation des fichiers, simplifiant ainsi la suppression ou la mise à jour des paquets. Un bon gestionnaire de paquets gère également les fichiers de configuration pour conserver la configuration spécifique de l'utilisateur lorsque le paquet est réinstallé ou mis à jour. Avant toute chose, cette section ne parle pas et ne recommande pas un gestionnaire de paquets en particulier. Elle résume les techniques les plus populaires et leur fonctionnement. Le gestionnaire de paquets qui vous convient le mieux peut se trouver parmi ces techniques ou être une combinaison d'une ou plusieurs techniques. Cette section mentionne brièvement les problèmes qui peuvent survenir lors de la mise à jour de paquets.

Voici la raison pour laquelle aucun gestionnaire de paquets n’est mentionné dans LFS ou BLFS :

Nous avons évoqué quelques astuces sur le sujet de la gestion des paquets. Consultez le Hints Project et trouvez le gestionnaire qui correspond à vos besoins.

8.2.1. Problèmes de mise à jour

Un gestionnaire de paquets facilite la mise à jour des nouvelles versions au moment de leur sortie. Généralement, les instructions contenues dans les livres LFS et BLFS peuvent être utilisées pour mettre à jour les paquets vers de nouvelles versions. Voici quelques points à connaître pour mettre à jour vos paquets, spécifiquement sur un système en cours de fonctionnement.

  • Si le noyau Linux doit être mis à jour, et passer par exemple de la version 5.10.17 à la version 5.10.18 ou 5.11.1, vous n’avez pas besoin de reconstruire d'autres éléments. Le système continuera de fonctionner correctement grâce à l'interface bien définie entre le noyau et l'espace utilisateur. Plus précisément, les headers de l'API Linux n'ont pas besoin d'être mis à jour (et ne doivent pas l'être, voir le point suivant) en même temps que le noyau. Vous devrez simplement redémarrer votre système pour utiliser le noyau à jour.

  • Si les headers de l'API Linux ou de glibc doivent être mis à jour vers une nouvelle version, et passer par exemple de la version glibc-2.31 à glibc-2.32, il est plus sécurisé de reconstruire LFS. Même si vous pourriez être capable de reconstruire tous les paquets dans leur ordre de dépendance, nous vous le déconseillons.

  • Si un paquet contenant une bibliothèque partagée est mis à jour et si le nom de cette dernière est modifié, alors les paquets liés dynamiquement à la bibliothèque devront être recompilés pour être liés à la nouvelle bibliothèque. Notez qu'il n'y a aucune corrélation entre la version du paquet et le nom de la bibliothèque. Par exemple, prenez un paquet foo-1.2.3 qui installe une bibliothèque partagée appelée libfoo.so.1. Partons du principe que vous mettez à jour le paquet avec une nouvelle version foo-1.2.4 qui installe une bibliothèque partagée appelée libfoo.so.2. Dans ce cas, tous les paquets liés dynamiquement à libfoo.so.1 doivent être recompilés pour être liés à libfoo.so.2. Vous ne devez pas supprimer les anciennes bibliothèques avant que les paquets indépendants ne soient tous recompilés.

  • Si un paquet est (directement ou indirectement) lié à la fois à l'ancien et au nouveau nom d'une bibliothèque partagée (par exemple, le paquet se lie à la fois à libfoo.so.2 et à libbar.so.1, alors que cette dernière est un lien vers libfoo.so.3), le paquet peut ne pas fonctionner correctement car les différentes versions des bibliothèques partagées fournissent des définitions incompatibles pour certains noms de symboles. Cela peut arriver en recompilant certains paquets, mais en en oubliant d'autres, liés à d'anciennes bibliothèques après la mise à jour du paquet qui fournit la bibliothèque partagée. Pour éviter ce problème, vous devrez recompiler tous les paquets liés à une bibliothèque partagée qui possède une nouvelle révision (p. ex. libfoo.so.2 devient libfoo.so.3) le plus vite possible.

  • Si vous mettez à jour un paquet qui contient une bibliothèque partagée et que le nom de la bibliothèque ne change pas, mais que le numéro de version du fichier de la bibliothèque décroît (par exemple le nom reste libfoo.so.1, mais le nom du fichier de la bibliothèque change de libfoo.so.1.25 à libfoo.so.1.24), vous devez supprimer le fichier de bibliothèque de la version précédente (libfoo.so.1.25 dans ce cas). Sinon, en exécutant ldconfig manuellement via la ligne de commande, ou en installant un paquet, vous réinitialiserez le lien symbolique libfoo.so.1 vers l'ancien fichier de bibliothèque, car sa version est « plus récente », puisque le numéro est plus grand. Cette situation arrive quand vous installez une version précédente d'un paquet, ou que l’auteur du paquet change de pratique de nommage des versions.

  • Si vous mettez à jour un paquet qui contient une bibliothèque partagée et que le nom de la bibliothèque ne change pas, mais qu'un problème important, comme une vulnérabilité de sécurité, est corrigé, tous les programmes en cours d'exécution liés à la bibliothèque partagée doivent être redémarrés. La commande suivante, lancée en tant qu’utilisateur root après la mise à jour, affiche les processus qui utilisent les anciennes versions de ces bibliothèques (remplacez libfoo par le nom de la bibliothèque) :

    grep -l 'libfoo.*deleted' /proc/*/maps | tr -cd 0-9\\n | xargs -r ps u

    Si OpenSSH est utilisé pour accéder au système et qu'il est lié à la bibliothèque mise à jour, vous devez redémarrer le service sshd, vous déconnecter, vous reconnecter et relancer la commande précédente pour confirmer qu’aucun processus n'utilise les bibliothèques supprimées.

    Si le démon systemd (qui tourne en tant que PID 1) est lié à une bibliothèque mise à jour, vous pouvez le recharger sans redémarrage en exécutant la commande systemctl daemon-reexec en tant qu'utilisateur root.

  • Si un programme ou une bibliothèque partagée est écrasé, les processus utilisant le code ou les données du programme ou de la bibliothèque peuvent planter. La bonne manière de mettre à jour un programme ou une bibliothèque partagée sans interruption anormale du processus est de le supprimer d'abord, puis d'installer la nouvelle version. La commande install fournie par coreutils implémente déjà cela et la plupart des paquets l'utilisent pour installer des binaires et des bibliothèques. Cela signifie que vous n'aurez pas ce problème la plupart du temps. Cependant, le processus d'installation de certains paquets, notamment Mozilla JS dans BLFS, se contente de réécrire sur le fichier s'il existe déjà et cause un crash, donc il est plus prudent de sauvegarder votre travail et de fermer les processus inutiles avant de mettre à jour un paquet.

8.2.2. Techniques de gestion des paquets

Voici une liste des techniques les plus courantes en gestion de paquets. Avant de choisir un gestionnaire de paquets, cherchez les différentes techniques et notamment les points faibles de chaque système.

8.2.2.1. Tout est dans ma tête !

Oui, c'est une technique de gestion des paquets. Certains n'ont pas besoin d'un gestionnaire de paquets parce qu'ils connaissent très bien les paquets et connaissent les fichiers installés pour chaque paquet. D’autres n'en ont pas besoin parce qu'ils planifient la reconstruction entière de LFS dès qu'un paquet est modifié.

8.2.2.2. Installation dans des répertoires distincts

C'est une technique de gestion des paquets simple qui ne nécessite aucun paquet supplémentaire pour gérer les installations. Chaque paquet est installé dans un répertoire distinct. Par exemple, le paquet foo-1.1 est installé dans /usr/pkg/foo-1.1 et un lien symbolique est créé depuis /usr/pkg/foo vers /usr/pkg/foo-1.1. Lors de la mise à jour vers la nouvelle version foo-1.2, elle est installée dans /usr/pkg/foo-1.2 et l'ancien lien symbolique est remplacé par le lien symbolique qui mène à la nouvelle version.

Les variables d'environnement telles que PATH, LD_LIBRARY_PATH, MANPATH, INFOPATH et CPPFLAGS ont besoin d'être étendues pour inclure /usr/pkg/foo. Si vous installez beaucoup de paquets, ce système devient ingérable.

8.2.2.3. Gestion de paquets par lien symbolique

Il s’agit d’une variante de la technique précédente. Chaque paquet est installé de façon similaire au système précédent. Mais au lieu de créer le lien symbolique avec un nom générique pour chaque paquet, chaque fichier dispose d'un lien symbolique dans la hiérarchie /usr. Il n’y a alors plus besoin d'étendre les variables d'environnement. Même si les liens symboliques peuvent être créés par l'utilisateur, beaucoup de gestionnaires de paquets utilisent cette approche pour automatiser la création de liens symboliques. Parmi les plus populaires, on retrouve Stow, Epkg, Graft et Depot.

Le script d'installation doit être faussé de façon à ce que chaque paquet pense qu'il est installé dans le répertoire /usr, alors qu'en réalité il est installé dans l'arborescence /usr/pkg. Réaliser l’installation de cette manière n'est généralement pas tâche aisée. Par exemple, supposons que vous installez un paquet libfoo-1.1. Les instructions suivantes peuvent ne pas installer correctement le paquet :

./configure --prefix=/usr/pkg/libfoo/1.1
make
make install

L'installation fonctionnera, mais les paquets dépendants peuvent ne pas se lier à libfoo de la manière prévue. Si vous compilez un paquet lié à libfoo, vous verrez que qu’il est aussi lié à /usr/pkg/libfoo/1.1/lib/libfoo.so.1 au lieu de /usr/lib/libfoo.so.1 comme attendu. La bonne approche consiste à utiliser la stratégie DESTDIR pour diriger l'installation du paquet. Cette approche fonctionne ainsi :

./configure --prefix=/usr
make
make DESTDIR=/usr/pkg/libfoo/1.1 install

La plupart des paquets prennent en charge cette approche, mais elle pose problème à certains utilisateurs. Pour les paquets non compatibles, vous pouvez soit les installer manuellement, soit opter pour une méthode plus simple en installant les paquets posant problème dans /opt.

8.2.2.4. Basé sur l’horodatage

Avec cette technique, un fichier est horodaté avant l'installation du paquet. Après l'installation, une simple exécution de la commande find avec les options appropriées peut générer une trace de tous les fichiers installés après la création du fichier horodaté. Le gestionnaire de paquets install-log utilise ce système.

Bien que ce schéma ait l'avantage d'être simple, il a deux inconvénients. Si à l'installation les fichiers sont installés dans autre horodatage que celui de l'heure actuelle, ils ne seront pas suivis par le gestionnaire de paquets. De plus, ce système peut être utilisé seulement lorsqu'un seul paquet est installé à la fois. Les traces ne sont pas fiables si deux paquets sont installés depuis deux consoles différentes.

8.2.2.5. Tracer les scripts d'installation

Avec cette approche, les commandes que les scripts d'installation exécutent sont enregistrées. Il existe deux techniques :

Vous pouvez initialiser la variable d'environnement LD_PRELOAD pour qu'elle pointe vers une bibliothèque à précharger avant l'installation. Lors de l'installation de cette dernière, la bibliothèque trace les paquets en cours d'installation en s'attachant aux différents exécutables comme cp, install, mv et trace les appels système qui modifient le système de fichiers. Pour que cette approche fonctionne, tous les exécutables ont besoin d'être liés dynamiquement sans bit suid ou sgid. Le préchargement de la bibliothèque peut provoquer des effets secondaires indésirables lors de l'installation ; effectuez donc quelques tests pour vous assurer que le gestionnaire de paquets n’endommage rien et trace bien les fichiers nécessaires.

La seconde technique consiste à utiliser la commande strace, qui trace tous les appels du système effectués pendant l'exécution des scripts d'installation.

8.2.2.6. Créer des archives de paquets

Dans ce système, l'installation d'un paquet est déplacé pour de faux dans un répertoire séparé comme décrit plus haut. Après l'installation, une archive du paquet est créée grâce aux fichiers installés. L'archive est ensuite utilisée pour installer le paquet, soit sur la machine locale, soit sur d'autres machines.

Cette approche est utilisée par la plupart des gestionnaires de paquets trouvés dans les distributions commerciales. Les exemples de gestionnaires qui suivent cette approche sont RPM, qui d'ailleurs est requis par la Spécification de base de Linux Standard, pkg-utils, apt de Debian et le système de portage de Gentoo. Une astuce montrant comment adopter ce style de gestion de paquets pour les systèmes LFS se trouve ici : http://www.fr.linuxfromscratch.org/view/astuces/fakeroot-fr.txt.

La création de fichiers de paquet qui incluent des informations de dépendance est complexe et va au-delà de l'objectif de LFS.

Slackware utilise un système basé sur tar pour les archives de paquets. Ce système ne gère volontairement pas les dépendances de paquets car d'autres gestionnaires de paquets plus complexes le font. Pour plus d’informations sur la gestion des paquets, voir https://www.slackbook.org/html/package-management.html.

8.2.2.7. Gestion basée sur les utilisateurs

Cette méthode, unique à LFS, a été décrite par Matthias Benkmann et est disponible sur le Hints Project. Selon cette méthode, chaque paquet est installé en tant qu'utilisateur séparé dans les emplacements standards. Les fichiers appartenant à un paquet sont facilement identifiables grâce à l'identifiant de l'utilisateur. Les avantages et inconvénients de cette approche sont trop complexes pour pouvoir tous les décrire dans cette section. Pour plus d’informations, voir l'astuce sur http://www.fr.linuxfromscratch.org/view/astuces/gestionnaire-paquets-utilisateur.txt.

8.2.3. Déployer LFS sur plusieurs systèmes

Le fait qu’il n'y ait pas de fichiers dépendants de la position des fichiers sur un système de disque est l’un des avantages du système LFS. Cloner la construction d'un système LFS sur un autre ordinateur avec une architecture similaire au système de base se résume à utiliser la commande tar sur la partition LFS qui contient le répertoire racine (environ 900 Mo décompressés pour une construction LFS de base), en copiant ce fichier via un transfert par réseau ou par CD-ROM ou clé USB vers le nouveau système et en le décompressant. Vous devez ensuite modifier quelques fichiers de configuration. Les fichiers de configuration qui nécessitent une mise à jour comprennent : /etc/hosts, /etc/fstab, /etc/passwd, /etc/group, /etc/shadow, /etc/ld.so.conf,

Vous pouvez construire un noyau personnalisé pour le nouveau système selon les différences dans le système matériel et la configuration du noyau initial.

[Note]

Note

Quelques problèmes ont été rapportés lors de la copie entre architectures similaires mais pas identiques. Par exemple, l'ensemble d'instructions pour l'architecture Intel n'est pas identique à celle d’un processeur AMD et les versions plus récentes de certains processeurs peuvent avoir des instructions qui ne sont pas disponibles pour des versions antérieures.

Enfin, vous devez rendre le nouveau système démarrable via Section 10.4, « Utiliser GRUB pour paramétrer le processus de démarrage ».