Booter un disque externe USB

Introduction

Booter un disque externe USB devrait être aussi simple que de booter un disque interne. Mais ce n'est pas le cas, sinon je n'écrirais pas cette page.

Il y a des grandes chances que ceci ne s'applique pas directement à votre cas parce que cela dépend du BIOS, de la carte mère, du disque, ... Il faudra donc extrapoler. Vous pouvez remplacer Ubuntu et Void Linux par les OS de votre choix, car dans cette page, ils ne sont pas générateurs des problèmes.

Le contexte

Préparation du disque WD

Le disque arrive préformaté en FAT avec une taille de 4 TB. Pour le mettre en service, il suffit de connecter la prise USB.

On va donc repartitionner le disque avec gdisk au format GPT pour disposer d'un grand nombre de partitions que l'on va formater en ext4. Il est recommandé d'avoir une première parttion de type bios boot pour loger le bootloader. La deuxième est prévue pour loger un OS. Les autres sont pour les data utilisateurs. La table suivante montre une possibilité de partitionnement.

# gdisk -l /dev/sdb
GPT fdisk (gdisk) version 1.0.6

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/sdb: 7813969920 sectors, 3.6 TiB
Model: Elements 2620   
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): 29356D07-62D6-4F0C-8E9B-8AC683F46E5F
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 7813969886
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            4095   1024.0 KiB  EF02  BIOS boot partition
   2            4096        41945087   20.0 GiB    8300  Linux filesystem
   3        41945088      1090521087   500.0 GiB   8300  Linux filesystem
   4      1090521088      2139097087   500.0 GiB   8300  Linux filesystem
   5      2139097088      3187673087   500.0 GiB   8300  Linux filesystem
   6      3187673088      4236249087   500.0 GiB   8300  Linux filesystem
   7      4236249088      5284825087   500.0 GiB   8300  Linux filesystem
   8      5284825088      6333401087   500.0 GiB   8300  Linux filesystem
   9      6333401088      7813969886   706.0 GiB   8300  Linux filesystem

On peut alors installer Ubuntu sur la parttion 20 GB. Comme on est déja sous linux, on monte le fichier ubuntu-mate-20.04.1-desktop-amd64.iso avec l'option loop sur /mnt, on décompresse le filesystem.squashfs et on copie les fichiers dans la future partition root /dev/sdb2 mntée sur /a.

mount -o loop ubuntu-mate-20.04.1-desktop-amd64.iso /mnt
unsquashfs /mnt/casper/filesystem.squashfs
mount /dev/sdb2 /a
cp -ar squashfs-root/* /a
cp /mnt/casper/initrd /a/boot
cp /mnt/casper/vmlinuz /a/boot

En faisant un chroot sur la partition /a, on a maintenant un système ubuntu que l'on peut mettre à jour et aussi installer grub.

Problème de démarrage de la machine avec disque connecté

Si le disque reste connecté, et que l'on redémarre la machine, le bios se plante et il faut couper l'alimentation et débrancher la prise usb. Voici les paramètres USB du bios:

Si on passe l'USB storage function à disable, la machine boote normalement sur le disque interne.

L'effet secondaire est que les clés USB bootable ne sont plus détectées.

Il faudra donc rebasculer cette option si on veut booter une clé USB.

Installation sur machine gigabyte pour booter Ubuntu

On suppose Ubuntu correctement installé. Après un essai sur une autre machine et en utilisant super_grub2_disk_hybrid_2.04s1.iso copié sur une clé USB, il est possible de booter Ubuntu, losque l'on a activé l'option nativedisk puis en choisissant l'option du menu correspondant à Ubuntu. Il faut bien sûr que le clé USB et le disque USB soit connectés à la machine.

Ceci est impossible sur la machine gigabyte, parce que l'on a déactivé USB storage.

Sur la machine gigabyte, on ne peut booter qu'en utilisant GRUB sur le disque interne. Dans une première étape, on branche le disque externe, on lance la commande grub-mkconfig, qui va détecter le disque externe et créer une entrée menu dans le fichier grub.cfg. Cette entrée menu ne va pas fonctionner parce qu'elle utilise les resources du bios pour charger linux à travers USB.

/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg

Dans la deuxième étape, on commence par copier l'entrée menu Ubuntu du fichier grub.cfg dans un fichier /etc/grub.d/40_custom, on y rajoute la commande nativedisk, on débranche le disque externe et on relance la commande grub-mkconfig. Ceci a pour effet de créer le fichier de configuration du disque interne avec une entrée menu pour le disque externe.

On aurait pu penser qu'utiliser nativedisk d'une manière globale dans le grub.cfg était une bonne solution. Mais ceci a encore un effet secondaire qui est de faire passer le temps de chargement de linux et initrd de 5 s à 3 mn, ce qui inacceptable sur un système Void Linux qui boote, tout compris, en 20 s.

Mon fichier 40_custom généré à partir de grub.cfg

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry 'Ubuntu 20.04.2 LTS (20.04) (on /dev/sdb2)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'osprober-gnulinux-simple-a8e6acf6-97df-4172-a344-931e598cc1b6' {
        insmod part_gpt
        insmod ext2
	nativedisk
        set root='hd1,gpt2'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd1,gpt2 --hint-efi=hd1,gpt2 --hint-baremetal=ahci1,gpt2  a8e6acf6-97df-4172-a344-931e598cc1b6
        else
          search --no-floppy --fs-uuid --set=root a8e6acf6-97df-4172-a344-931e598cc1b6
        fi
        linux /boot/vmlinuz-5.4.0-70-generic root=UUID=a8e6acf6-97df-4172-a344-931e598cc1b6 ro net.ifnames=0 biosdevname=0 quiet splash $vt_handoff
        initrd /boot/initrd.img-5.4.0-70-generic
}

Et effectivement, ça fonctionne,,, Le temps de boot sur le disque externe est acceptable.

Installation sur Toshiba Satellite L300

Sur Toshiba le méthode précédente ne fonctionne pas. On obtient une erreur après les opérations suivantes:

error: attempt to read or write outside the disk 'hd0'.
Entering rescue mode ...

Une autre erreur survient après les opérations suivantes: problème avec l'uuid du rootfs Ubuntu...

error: hd1 cannot get C/H/S values.
error: no such device: a8e6acf6-....
error: hd1 cannot get C/H/S values.
error: you need to load the kernel first.

Cette erreur indique que grub ne sait pas accéder au disque externe. On va lui rajouter les modules: part_gpt, ext2, usb, usbms, ehci et modifier les variables prefix et root pour pointer sur le disque externe (voir plus bas). A partir de maintenant, c'est le grub installé sur le disque externe qui devient actif et c'est le grub Ubuntu qui produit l'erreur suivante:

error: symbol grub_calloc not found

C'un symbole de fonction utilisé dans le code et définit nulle part, code non testé mais quand même mis à disposition, du professionnel ! Il s'agit bien sûr du code Ubuntu. Le remède indiqué sur internet est de réinstaller grub. J'ai donc mis à jour et réinstallé le grub Ubuntu et rien n'a changé.

Alors pourquoi ne pas installer le grub du système hôte sur le disque externe:

mount /dev/sdb2 /a
grub-install --target=i386-pc --boot-directory=/a/boot --recheck /dev/sdb
umount /a

On réinstalle le grub.cfg sur le disque interne avec grub-mkconfig et avec un fichier /etc/grub.d/40_custom dont voici le contenu:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry 'Ubuntu 20.04.2 LTS (20.04) (on /dev/sdb2)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'osprober-gnulinux-simple-a8e6acf6-97df-4172-a344-931e598cc1b6' {
        insmod part_gpt
        insmod ext2
        insmod usb
        insmod usbms
        insmod ehci
        set prefix=(usb0,gpt2)/boot/grub
        set root=(usb0,gpt2)
        linux /boot/vmlinuz-5.4.0-72-generic root=UUID=a8e6acf6-97df-4172-a344-931e598cc1b6 ro net.ifnames=0 biosdevname=0 quiet splash $vt_handoff
        initrd /boot/initrd.img-5.4.0-72-generic
}

Et effectivement, ça fonctionne,,, On va donc faire la même manip sur la carte gigabyte.

Installation sur carte gigabyte

On copie le fichier /etc/grub.d/40_custom précédent sur la machine gigabyte et on exécute grub-mkconfig, disque externe débranché, pour générer le grub.cfg sur le disque interne.

Si on démarre la machine disque externe branché, et que l'on sélectionne l'entrée Ubuntu dans le menu grub on démarre sur le disque externe. C'est le but recherché.

Installation sur Toshiba avec Super Grub

Après avoir copier super_grub2_disk_hybrid_2.04s1.iso sur une clé USB, on arrive à booter le disque externe, après les opérations suivantes:

Le fonctionnement n'est pas très stable, mais il arrive que l'on puisse booter sur le disque externe.