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 :
La gestion des paquets ne fait pas partie de l’objectif de ces livres, qui visent à apprendre aux utilisateurs à construire un système Linux.
Il existe de nombreuses solutions pour gérer des paquets. Chacune a ses points forts et ses points faibles. En trouver une qui satisfait tout le monde est difficile.
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.
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.
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.
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é.
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.
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
.
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.
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.
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.
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.
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.
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 ».