Jâai beaucoup de sauvegarde dâimages SD, cela permet de faire des migrations de mes PIs de maniĂšre assez sure. Pour cela jâutilise la commande dd qui Ă lâavantage de sauvegarder toutes les partitions dâun coup. Le problĂšme câest que la taille de lâimage est aussi grosse que la taille de la SD. Or, je prĂ©vois mes SD de telle sorte que lâespace utilisĂ© ne dĂ©passe pas les 60 % de lâespace total ; sur certaines machines, câest largement moins.
Comment rĂ©duire la taille de ces images, la compression ? Câest trĂšs long et pas forcĂ©ment trĂšs efficace.
LâidĂ©e est donc dâutiliser les commandes gparted, fdisk et truncate.
- On va utiliser gparted pour redimensionner les partitions contenues dans le fichier
.img
, - Utiliser fdisk pour connaßtre la zone occupée sur le disque,
- et enfin tronquer le fichier avec truncate pour ne garder que la partie significative.
Procédure détaillée
Je vous conseille de vous positionner dans le dossier du fichier image à traiter, par exemple :
cd ~/Documents/raspbian-images/backups/
Sachant que GParted opĂšre sur des pĂ©riphĂ©riques, et non sur de simples fichiers comme les images, il est dâabord nĂ©cessaire de crĂ©er un pĂ©riphĂ©rique pour lâimage. Nous le faisons en utilisant la fonctionnalitĂ© de bouclage (loop
) de Linux.
Il est probable que loop
soit dĂ©jĂ actif, mais si ce nâest pas le cas vous pouvez le faire Ă lâaide de :
sudo modprobe loop # Si besoin uniquement
Demandons un nouveau périphérique de bouclage (libre) :
sudo losetup --find
La commande renvoie le chemin vers un périphérique de bouclage libre, par exemple :
/dev/loop18
CrĂ©ons un pĂ©riphĂ©rique de lâimage :
sudo losetup /dev/loop18 2022-03-17.09-00.framboiseXXXXXX.img
ou
Vous pouvez faire cela en une fois comme suit :
sudo losetup --find --partscan 2022-03-17.09-00.framboiseXXXXXX.img
Puis utilisez lsblk pour voir quels périphériques ont été associés à cette image.
lsblk
Mais vous pouvez également utiliser losetup :
losetup --json # ou --list
Pour continuer, vous devez avoir identifié le périphérique /dev/loopN
correspondant Ă votre imageâŠ
Maintenant, il faut demander au noyau de charger le fichier :
sudo partprobe /dev/loop18
Dans lâexemple, on a le pĂ©riphĂ©rique /dev/loop18
qui pointe vers le fichier image 2022-03-17.09-00.framboiseXXXXXX.img
.
Maintenant, il est possible de lancer GParted comme suit :
sudo gparted /dev/loop18
Dans GParted, vous pouvez alors redimensionner les partitions comme pour un disque standard. LâidĂ©e Ă©tant de redimensionner la ou les partitions de maniĂšre Ă ce quâelle sâadapte Ă son contenu.
DĂ©placer vers la gauche autant que possible les partitions.
Nâoubliez pas de finaliser lâopĂ©ration en appliquant les modifications.
Maintenant le pĂ©riphĂ©rique de bouclage nâest plus nĂ©cessaire, alors dĂ©chargez-le :
sudo losetup -d /dev/loop18
LâĂ©tape suivante consiste Ă tronquer le fichier en supprimant la derniĂšre partie maintenant inutile ; lâopĂ©ration prĂ©cĂ©dente consistant justement Ă mettre les donnĂ©es importantes au dĂ©but de lâimage.
Nous devons savoir oĂč se termine notre partition et oĂč commence la partie non allouĂ©e. Pour ce faire, nous utiliserons fdisk :
fdisk -l 2022-03-17.09-00.framboiseXXXXXX.img
Disk 2022-03-17.09-00.framboiseXXXXXX.img: 29,74 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x5d05d223
Device Boot Start End Sectors Size Id Type
2022-03-17.09-00.framboiseXXXXXX.img1 8192 532479 524288 256M c W95 FAT32 (LBA)
2022-03-17.09-00.framboiseXXXXXX.img2 532480 14868479 14336000 6,9G 83 Linux
Notez deux informations importantes dans le résultat affiché :
- La partition se termine sur le bloc 14868479 (indiqué sous « End »).
- La taille du bloc est de 512 octets (indiquĂ©e sous forme de secteurs de « 1 * 512 » â comprendre : 1 Ă 512).
Nous utiliserons ces chiffres dans le reste de lâexemple. La taille du bloc (512) est la valeur que vous retrouverez le plus souvent, mais le bloc de fin (14868479) sera diffĂ©rent pour vous.
Ces chiffres signifient que la partition se termine sur lâoctet 14 868 479 Ă 512 du fichier. AprĂšs cet octet vient la partie non allouĂ©e. Seuls les 14 868 479 Ă 512 premiers octets seront utiles pour notre image.
Pour réduire le fichier image à une taille qui peut juste contenir la partition nous utiliserons la commande truncate.
La commande truncate nécessite de fournir la taille du fichier en octets.
Le dernier bloc Ă©tait 14868479 et les numĂ©ros de bloc commencent Ă 0. Cela signifie que nous avons besoin de (14 868 479 + 1) Ă 512 octets. Câest important, sinon la partition ne sâadaptera pas Ă lâimage.
Il est possible de faire le calcul directement en bash
comme suit :
echo $(( (14868479+1)*512 ))
7612661760
Il est possible truncate avec les calculs, comme suit :
truncate --size=$(( (14868479+1)*512 )) 2022-03-17.09-00.framboiseXXXXXX.img
Un petit script pour aiderâŠ
-
gparted-dd-img-and-resize.sh
Script sans garantie Ă utiliser sur une sauvegarde, Ă©vitez dâutilisĂ© lâimage originale.
#!/bin/bash # # gparted-dd-img-and-resize.sh # function mount_dd_image { local -r img_file_realpath="$1" sudo losetup --find --partscan "${img_file_realpath}" >&2 || return $? local __json__= __json__="$( set -x losetup --json | jq --arg image "${img_file_realpath}" '.loopdevices[] | select( .["back-file"] == $image )' )" || return $? jq . <<<"${__json__}" >&2 local __device__= __device__="$( jq -r .name <<<"${__json__}" )" || return $? echo "Device: ${__device__}" >&2 sudo partprobe "${__device__}" >&2 || return $? echo "${__device__}" } function open_gparted_dd_image { local -r img_file="$1" local img_file_realpath= img_file_realpath="$( realpath "${img_file}" )" || return $? if [ ! -f "${img_file_realpath}" ] ; then echo "File not found: '${img_file}'" return 1 fi local __device__= __device__="$( mount_dd_image "${img_file_realpath}" )" || return $? echo "Start gparted on '${__device__}'" sudo gparted "${__device__}" || return $? echo "Free device '${__device__}'" sudo losetup -d "${__device__}" || return $? } function dd_image_auto_resize { local -r img_file="$1" fdisk -l "${img_file}" || return $? local -i size=0 size="$( fdisk -l "${img_file}" | grep 'Units: ' | sed -E 's,(.*)=[[:blank:]]*(.*)[[:blank:]]*bytes,\2,g' )" || return $? if [ "${size}" -eq 0 ] ; then echo 'Units size error' return 1 fi local -i end=0 end="$( fdisk -l "${img_file}" | grep "^${img_file}" | sed -E 's,^(.*)[[:blank:]]+([0-9]+)[[:blank:]]+([0-9]+)[[:blank:]]+([0-9]+)[[:blank:]]+(.*),\3,g'| sort -n -r | head -n 1 )" || return $? if [ "${end}" -eq 0 ] ; then echo 'End position error' return 1 fi local -i new_size=0 new_size=$(( ( end + 1 ) * size )) if [ "${new_size}" -eq 0 ] ; then echo 'New size error' return 1 fi ( set -x truncate --size=${new_size} "${img_file}" ) || return $? } function gparted_dd_img_and_resize { local -r img_file="$1" open_gparted_dd_image "${img_file}" || return $? dd_image_auto_resize "${img_file}" || return $? } function main { gparted_dd_img_and_resize "$1" || return $? } main "$@" || exit $?
Références
- How to resize img file created with dd?
- "Re-size" the .img for smaller SD-card. How to SHRINK a bootable SD card image
኿