Install fichiers kernel et grub dans /boot/subdir

Tags: #<Tag:0x00007f63f54e17f8> #<Tag:0x00007f63f54e1320> #<Tag:0x00007f63f54e1078> #<Tag:0x00007f63f54e0d30>

Salut à tous,

Bon voilà j’aurai besoin d’un petit coup de pouce comme énoncé dans le titre, si toutefois c’est faisable…

Je suis sous Sid sur du BTRFS, donc pour profiter de la souplesse des sous-volumes, j’ai installé en parallèle de Debian une Fedora.
J’ai gardé le GRUB installé par Debian, et il faudrait que je ponte le grub.cfg de Fedora de manière à ce que, quelle que soit la MàJ d’un côte comme de l’autre, le menu GRUB le soit toujours également (sous-entendu à jour)…

Pour celà, j’ai crée un sous-volume pour /boot à la racine de ma partition BTRFS, dans lequel j’ai pour l’instant deux sous-volumes (debian et fedora) et qui sont montés sur /boot en fonction du système démarré… Et pour avoir le chaînage, dans chaque distribution sous /boot j’ai crée un dossier pour l’autre distribution dans lequel je monte l’autre sous-volume…

Bref pour donner un exemple plus concret au cas où ce ne serait pas forcément clair pour tout le monde, mon “partitionnement” sur la partition BTRFS se présente comme suit :

/dev/sda1 (BIOS-boot)
/dev/sda2 (EFI)
/dev/sda3 (partition-récup)
/dev/sda4 (swap)
/dev/sda5 (chiffrée LUKS)
  |
  |--- /dev/mapper/linux (partition BTRFS)
        |
        |--- @boot 
        |      |--- @debian (contient ce que contient le chemin /boot pour Debian)
        |      |--- @fedora  (contient ce que contient le chemin /boot pour Fedora)
        |       
        |--- @containers
        |--- @debian 
        |      |--- @fsroot (contient la racine de Debian)
        |      |--- @home 
        |      | ...
        |    
        |--- @fedora 
        |      |--- @fsroot (contient la racine de Fedora)
        |      |--- @home
        | ... 

Exemple, en lançant Debian le montage se fait comme suit :

/                    (sous-volume /@debian/@fsroot)
|--- /bin
|--- /boot           (sous-volume /@boot/@debian)
       |--- /efi     (/dev/sda2)
       |--- /fedora  (sous-volume /@boot/@fedora)
       |--- /grub 
       | ...
|--- /data
|--- /dev
|--- /etc
| ... 

Donc ça c’est la solution provisoire (où peut-être définitive si ma question n’a pas de solution…).
Ce que je prévoyais (prévois) de faire au départ, c’était un seul sous-volume @boot contenant des dossiers “debian” et “fedora” (éventuellement ajouter d’autres dossiers ultérieurement pour d’autres installations en dur…) et faire le montage suivant :

/                        (sous-volume /@debian/@fsroot)
|--- /bin
|--- /boot               (sous-volume /@boot)
       |--- /debian      (contenant tout ce que contient /boot sous Debian)
       |     |--- /grub
       |     |...
       |
       |--- /efi         (/dev/sda2)
       |--- /fedora      (contenant tout ce que contient /boot sous Fedora)
       |     |--- /grub
       |     |...
       | ...
       |
|--- /data
|--- /dev
|--- /etc
| ... 

Ce montage est plus simple pour une question de maintenance, mais le problème, que je rencontre, est que je ne sais pas comment dire au système d’installer les fichiers courants du kernel (config*, System.map*, vmlinuz*, …) dans un autre chemin que le chemin habituel “/boot”…

Pour le grub j’utilise la commande :

# grub-install --boot-directory=/boot/debian /dev/sda (par exemple pour Debian)

Mais au delà un “update-grub” même avec l’option “-o” pour spécifier le chemin du fichier “grub.cfg” ne sait pas remplir ce dernier complètement étant donné qu’il ne trouve pas les fichiers courants du kernel à leur emplacement habituel…

Donc voilà la question est là : est-il possible de configurer le chemin où vont se trouver les fichiers du kernel, de grub, l’initrd, etc… pour mettre tout çà dans un sous-dossier de “/boot” selon le schéma ci-dessus?

D’après sa page de manuel, update-grub n’a pas d’option -o. Cette option appartient à grub-mkconfig, appelé en sous-main, par update-grub.

Les emplacement des fichiers vmlinuz*, config* et System.map* sont définis dans le paquet linux-image. Il doit être possible de les déplacer proprement avec le système de “détournement” (diversion) grâce à dpkg-divert, mais il faut le faire pour chaque version de noyau installée, et d’autres programmes se basent sur /boot, comme update-initramfs qui crée ou met à jour l’initramfs /boot/initrd*, os-prober, et j’en oublie sûrement.

Que penses-tu de simplement renommer /boot et le remplacer par un lien symbolique qui pointe vers le répertoire de ton choix ?

Néanmoins, je ne vois pas en quoi tout cela répond à ton souhait initial :

D’ailleurs je ne suis pas sûr de comprendre ce que tu veux dire.

Oui tout à fait, j’ai mentionné “update-grub” au lieu de “grub-mkconfig” par automatisme.

J’avais pas pensé à “dpkg-divert”, peut-être qu’il serait possible de placer un script quelque part dans /etc qui pourrait automatiser cette étape, en jouant avec les fichiers config d’APT qui appelleraient ce script si une MàJ inclut le noyau… À voir, mais ça m’a l’air d’être une solution pénible à mettre en oeuvre rien que comme ça à vue d’oeil.

Pour update-initramfs c’est pas un problème tant qu’on le fait manuellement, par contre ça devient un problème lorsque il est appelé lors d’une MàJ.
Os-prober ne me sert à rien dans mon cas étant donné que pour l’instant il ne sait pas aller chercher d’autres install’s dans des sous-volumes BTRFS… :confused:
Mais bon comme tu dis il doit y avoir d’autres programmes qui peuvent faire appel à cette commande donc la liste n’est pas exhaustive.

Ce serait effectivement une solution plus simple. Dans ce cas il me faudrait créer un répertoire à la racine par exemple sur lequel je monterai mon sous-volume @boot et vers lequel je ferais pointer le lien symbolique /boot?
Mais qu’en est-il lorsque s’installe une nouvelle version du kernel et/ou lors d’un update-initramfs et/ou update-grub? Il faudrait que je fasse le test pour voir comment faire ça proprement.

En fait j’ai mes deux distributions dans leurs sous-volumes respectifs selon le schéma présenté au début du sujet. Pour l’instant pour avoir les menus de Fedora dans le GRUB j’ai bêtement copié/collé la partie utile du fichier grub.cfg de Fedora dans le fichier de config 40_custom sous Debian, mais c’est évidemment provisoire juste histoire que ça fonctionne pour l’instant.

L’objectif c’est de démarrer sur n’importe quel des deux systèmes, et d’avoir lors de mises à jour, que ce soit d’un côté comme de l’autre, un fichier grub.cfg automatiquement également à jour sans pour autant redémarrer sur l’autre distribution pour mettre à jour celui-ci, ni faire ça par un chroot etc… En gros je souhaite bricoler tout ça afin que ça se fasse en toute transparence.

En partant sur l’idée de détournement avec dpkg-divert, est-ce qu’il serait possible d’exploiter le chemin /etc/kernel qui contient par défaut des dossiers de config {install, postinst, preinst, prerm, postrm, …} en y collant des scripts personnalisés?

Je pensais à quelque chose comme ceci :

|--- /boot -> boot.real/debian
|--- /boot.real          (sous-volume /@boot)
       |--- /debian      (contenant tout ce que contient /boot sous Debian)
       |     |--- /grub
       |     |--- /efi   (/dev/sda2)
       |
       |--- /fedora      (contenant tout ce que contient /boot sous Fedora)
       |     |--- /grub
       |     |--- /efi

Ça devrait être transparent pour tous les programmes qui utilisent /boot.

Mais je reviens à la charge : je ne vois pas en quoi cela va t’aider à synchroniser les menus de démarrage des deux GRUB. Tout ce chantier n’est pas nécessaire pour extraire ou dupliquer la section 10_linux du fichier grub.cfg et la copier dans le fichier grub/custom.cfg (chargé par la section 41_custom) de l’autre GRUB. Cela doit pouvoir s’automatiser avec un script placé dans /etc/grub.d et n’a aucun besoin de ce montage compliqué, jusque que le répertoire /boot/grub de l’autre système soit accessible.

Note que la syntaxe d’un fichier grub.cfg généré par une version de GRUB n’est pas forcément compatible avec une version différente de GRUB. Je l’ai constaté notamment entre le GRUB 1.9x de Squeeze/Wheezy et le GRUB 2.0x de Jessie.

Franchement, tu sais ce que je ferais : un simple chainload (si EFI) ou multiboot (si BIOS) de la core image de l’autre GRUB dans 40_custom. Ainsi, pas besoin de synchroniser et pas de risque d’incompatibilité entre les syntaxes des versions de GRUB.

Merci Pascal, je vais regarder tout ça à tête reposée j’y verrais plus clair, là avec la fatigue je vois plus rien, puis je reviendrai avec la solution.

Je reviens entre temps sur ce point uniquement pour l’instant : si je me souviens bien, si je chaîne avec la core.img de l’autre GRUB, lors de l’execution ça va m’amener sur une deuxième fenêtre avec menu GRUB lorsque je sélectionnerai cet autre distribution?

Ça va simplement exécuter l’autre GRUB qui va charger ses propres modules, son propre fichier de configuration et afficher son propre menu de démarrage.

oui donc c’est bien ce que je pensais, mais ce n’est pas une option que j’envisage étant donné que j’ai déjà trois interfaces à passer au boot : “déverrouillage du GRUB” avec le mot de passe LUKS, le menu de démarrage GRUB, déverrouillage de la partition LUKS, puis enfin login…

Si je comprends bien, en fait tout ce que tu veux, c’est inclure les entrées de noyau de l’autre distribution dans le menu de GRUB ?

Oui, quand je suis loggué sous Debian, l’idée c’est d’inclure automatiquement les entrées noyau des éventuelles autres installations présentes. Pour ce point c’est réglé, je viens de me pondre un script que j’ai collé dans /etc/grub.d/ et que j’ai nommé “11_multiboot” pour avoir ces entrées juste après celles de Debian… :

#!/bin/sh

os_release="fedora ubuntu kubuntu archlinux gentoo elementary_os"
for folder in ${os_release}
do
    if  [ -d /boot/"${folder}"/grub ];
    then

      sed -n "/### BEGIN \/etc\/grub.d\/10_linux ###/,/### END \/etc\/grub.d\/10_linux ###/p" /boot/"${folder}"/grub/grub.cfg |
      sed -e "s/.*### BEGIN \/etc\/grub.d\/10_linux ###/# ---> "${folder}" menuentry /" -e "s/### END \/etc\/grub.d\/10_linux ###.*//"

    elif [ -d /boot/"${folder}"/grub2 ];
    then

      sed -n "/### BEGIN \/etc\/grub.d\/10_linux ###/,/### END \/etc\/grub.d\/10_linux ###/p" /boot/"${folder}"/grub2/grub.cfg |
      sed -e "s/.*### BEGIN \/etc\/grub.d\/10_linux ###/# ---> "${folder}" menuentry /" -e "s/### END \/etc\/grub.d\/10_linux ###.*//"

    fi

done

exit 0

Par contre ce que je voulais au niveau des montages, c’etait d’effectuer un seul montage sur /boot qui contiendrait des sous-dossiers désignant chaque distribution installée… Plus facile à maintenir que de monter un sous-volume sur /boot, puis monter chaque sous-volume sur le sous-dossier correspondant à une autre distribution autre que celle sur laquelle j’ai booté.

Mais je viens de me rendre compte d’un truc, c’est que mon idée ne marcherait de toute façon que du côté de Debian, car le grub a été installé sur /dev/sda à partir de Debian… Donc côté Fedora ou autre, j’aurai beau mettre à jour le fichier grub.cfg lorsque c’est nécessaire…, ça ne changera rien au démarrage tant que je n’aurai pas redémarré sur Debian pour faire un update-grub, ou bien depuis Fedora en chroot…

Donc le mieux serait peut-être de coller un script qui ferait tout le travail “chroot” côté Fedora et qui serait appellé à chaque fois qu’une opération côté Fedora nécessite la mise à jour de son fichier “grub.cfg”…

En effet ta méthode fonctionne en mode “pull” (le système maître du menu principal de GRUB doit récupérer la configuration des autres systèmes. D’où ma suggestion du chaînage. Si les versions de GRUB sont compatibles entre elles, tu peux aussi te contenter de simplement charger le grub.cfg de l’autre système avec configfile au lieu de chaîner l’image de l’autre GRUB elle-même.

Si tu veux incorporer les entrées des noyaux d’un autre système en mode “push-pull”, je propose la méthode suivante :

  • dans l’autre système, modifier le script update-grub ou update-grub2 pour, après la génération de grub.cfg, en extraire la section “10_linux” et l’enregistrer dans un fichier stocké à une emplacement accessible par le GRUB principal.
  • dans le système maître du menu principal de GRUB, ajouter un script dans /etc/grub.d/ qui ajoute dans grub.cfg de quoi inclure le contenu de ce fichier à l’exécution de GRUB avec source.

Il me semble que la méthode par symlink que j’ai proposée plus haut peut faire l’affaire. Il faudrait la tester.

C’est exactement ça.
Celà dit pour ce qui est d’utiliser configfile j’ai jamais réussi à faire fonctionner ça de cette manière, sans doute que je m’y prends mal, et puis cette méthode ne revient elle pas aussi à afficher une deuxième fenêtre avec le menu GRUB de l’autre distribution comme on en avait parlé ci-dessus?

À vrai dire je t’ai devancé un peu là-dessus, mais c’est vrai qu’entre temps je n’ai pas mis à jour le sujet sur mon avancée depuis hier. J’ai déjà fait ce que tu proposes, à cela près que j’ai modifié le script que j’ai copié/collé au-dessus, et que j’ai abandonné l’idée du sous-volume pour /boot et des sous-dossiers ou sous-volumes pour chaque distribution.

Car comme tu l’as bien suggéré plus haut, c’est effectivement tout un chantier, relativement pénible, pour une commande (update-initramfs et/ou update-grub) qui sera statistiquement executée tous les 36 du mois (même sous Sid la fréquence d’execution lors de MàJ est faible donc ça n’en vaut pas vraiment la peine…).

Je suis donc revenu au montage classique, c’est à dire chaque distribution à son chemin /boot avec ses propres fichiers, et du côté de l’installation maître (Debian) j’ai inclus le script suivant dans /etc/grub.d/ :

root@blabla:/mnt/@fedora/@fsroot# cat /etc/grub.d/11_multiboot 
#!/bin/sh

if [ ! -d /tmp/btrfs_part ]; then
    mkdir /tmp/btrfs_part
fi

mount -t btrfs -o rw,relatime,space_cache,autodefrag,compress=lzo /dev/mapper/linux /tmp/btrfs_part

os_release="fedora ubuntu kubuntu archlinux gentoo elementary_os"
for folder in ${os_release}
do
    if  [ -d /tmp/btrfs_part/@"${folder}"/@fsroot/boot/grub ]; then

      sed -n "/### BEGIN \/etc\/grub.d\/10_linux ###/,/### END \/etc\/grub.d\/10_linux ###/p" /tmp/btrfs_part/@"${folder}"/@fsroot/boot/grub/grub.cfg |
      sed -e "s/.*### BEGIN \/etc\/grub.d\/10_linux ###/# ---> \u"${folder}" \umenuentry /" -e "s/### END \/etc\/grub.d\/10_linux ###.*//"

    elif [ -d /tmp/btrfs_part/@"${folder}"/@fsroot/boot/grub2 ]; then

      sed -n "/### BEGIN \/etc\/grub.d\/10_linux ###/,/### END \/etc\/grub.d\/10_linux ###/p" /tmp/btrfs_part/@"${folder}"/@fsroot/boot/grub2/grub.cfg |
      sed -e "s/.*### BEGIN \/etc\/grub.d\/10_linux ###/# ---> \u"${folder}" \umenuentry /" -e "s/### END \/etc\/grub.d\/10_linux ###.*//"

    fi
done

umount /tmp/btrfs_part && rmdir /tmp/btrfs_part
unset folder os_release

exit 0

Je l’ai mis en “11_…” pour avoir les menus dans l’ordre que je veux (juste après ceux de Debian) dans le GRUB, et ça me permettra d’aspirer la partie “10_linux” de n’importe quelle distribution présente sur la partition en question, pourvu que la variable “os_release” contienne son nom, en montant la partition dans un dossier temporaire… Et surtout je suis sûr que ce sera executé à chaque appel de la commande “update-grub” ou “grub-mkconfig”, ce qui est le plus important.

Du côté du/des autres systèmes, pour l’instant Fedora uniquement donc, j’ai collé un autre script qui va monter cette fois-ci, lorsque ce système est lancé, le sous-volume contenant la racine de Debian dans un dossier temporaire et à l’aide d’un chroot va mettre à jour GRUB en incluant l’opération ci-dessus :

root@blabla:~# cat /mnt/@fedora/@fsroot/usr/local/bin/update-debgrub 
#!/bin/sh

if [ ! -d /tmp/deb_subvol ]; then

    mkdir /tmp/deb_subvol
fi

mount -t btrfs -o rw,relatime,space_cache,autodefrag,compress=lzo,subvol=/@debian/@fsroot /dev/mapper/linux /tmp/deb_subvol

DIRECTORY="dev dev/pts sys proc run"
for i in ${DIRECTORY}
  do
    mount -o bind /"${i}" /tmp/deb_subvol/"${i}"

  done

chroot /tmp/deb_subvol <<EOF
update-grub
exit
EOF

umount -R /tmp/deb_subvol && rmdir /tmp/deb_subvol
unset DIRECTORY

exit 0

Ça me permet d’ailleurs de me passer de ton idée de fichier dans lequel on enregistrerait la sortie du script.

Par contre j’aimerais bien que côté Fedora ce script soit aussi inclus automatiquement à chaque fois que la commande “grub-mkconfig” serait invoquée, et bien évidemment cette fois je ne peux pas placer ce script dans le /etc/grub.d/ de Fedora…
Mais ton idée de modifier le script update-grub (enfin sous Fedora c’est “grub-mkconfig”, il n’y a pas d’aternative “update-grub” ou "update-grub2) m’a mis la puce à l’oreille… : plutôt que de modifier “grub-mkconfig”, si j’en fais une copie dans le chemin /usr/local/sbin/ et que je modifie cette copie, prendra t-elle le dessus à l’execution sur le script original dans /usr/sbin ou pas?

Bon je me réponds à moi-même, ça fonctionne.