jeudi, août 19, 2010

Réparation des bibliothèques manquantes

Suite à la mise à jour d'une bibliothèque critique sur mon FreeBSD (mise à jour de devel/icu4 qui est passé de 4.3 vers 4.4) et d'une erreur de ma part lors de l'étape de mise à jour:
Je me suis retrouvé avec un FreeBSD dont la base était pleinement fonctionnelle (merci à la séparation de la base et des ports) mais dont la grosse majoritée des applications ne voulaient plus démarrer (dont gnome).
En effet, les applications recherchaient les bibliothèques libicu*.so.43 qui n'existaient plus car remplacées par libicu*.so.44.
Pour retrouver rapidement un système fonctionnel, j'ai en premier lieu ajouté les correspondances «anciennes libs <=> nouvelles libs» dans le fichier /etc/libmap.conf:


libicule.so.43          libicule.so.44
libicui18n.so.43        libicui18n.so.44
libicudata.so.43        libicudata.so.44
libicuuc.so.43          libicuuc.so.44
libicutu.so.43          libicutu.so.44
libiculx.so.43          libiculx.so.44
libicuio.so.43          libicuio.so.44

Ce «bidouillage» ma permis de retrouver un système fonctionnel très rapidement, mais ca ne me plaisait pas d'avoir un système «pas si propre que ça».
Je me suis donc attelé à la rédaction d'un script shell qui
  1. Parcours l'ensemble des dossiers /usr/local/bin, /usr/local/sbin et /usr/local/lib à la recherche de fichier lié à des bibliothèques manquantes
  2. Puis retrouve le port correspondant à ces fichiers (pkg_info)
  3. Puis enfin recompile/réinstalle ces ports (portmaster)
Tout contents de moi, je suis aller le proposer sur #freebsd-fr, pour découvrir que je venais de ré-inventer la roue :-(
Ce script existe déjà en zsh (Reconstruire les paquets cassés) et il existe un port en ruby (sysutils/libchk).
Mais comme la version de mon script:
  1. Est en sh (et donc ni dépendante de zsh ni de ruby… qui sont des ports potentiellement «cassés» au moment ou vous avez besoin de ce script)
  2. Que c'est moi qui l'ai fait tout seul comme un grand, et que ca m'embête de le jeter après les heures (oui c'est très très chiant le sh) passé dessus
Je mes suis décidé à le publier quand même:

#!/bin/sh
# Found file with missing libs, and recompile the related breaked ports
set -e
dirs="/usr/local/lib /usr/local/libexec /usr/local/bin /usr/local/sbin"

portnames_tmp=""
for dir in ${dirs}; do
    for filename in `find -L ${dir} -type f`; do
    if file ${filename} | grep -q ELF; then
        if ldd ${filename} 2>&1 | grep -q "not found"; then
            portnames_tmp=${portnames_tmp}" "`pkg_info -qoW ${filename}`
        fi
    fi
    done
done

if [ "${portnames_tmp}" = "" ];then
    echo "No missing lib found"
    exit 0
fi

# Filtering duplicate name in $portnames_tmp
portnames=`for port in ${portnames_tmp}; do  echo $port; done |  sort -u | xargs echo`

echo "Detecting missing library for theses ports:"
echo ${portnames}

echo "Start upgrading them…"
portmaster -B ${portnames}

PS (1): le port devel/icu4 étant buggué (il oublie d'installer la bibliothèque libicutest.so.44), à chaque lancement de ce script, il détectera que devel/icu4 à une bibliothèque manquante et voudra donc le ré-installer :-)
PS (2): Ne pas oublier de faire le ménage dans /etc/libmap.conf après avoir corrigé vos problèmes.

1 commentaire:

Anonyme a dit…

Aussi penser à utiliser l'option -w pour portmaster (ou à la mettre dans le portmaster.rc : SAVE_SHARED=wopt), comme ça les libs des ports qui sont remplacés vont direct dans /usr/local/lib/compat/pkg et tout continue de fonctionner.
Très utile lors d'un gros update de lib (genre y'a pas longtemps avec gettext) qui foire en plein milieu à cause d'une dépendance...