cClaude.rocks ☕ Le blog

[Nouvelles technologies du libre, sciences et coups de gueule…]

Menu

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

኿


â„č 2006 - 2024 | 🏠 Accueil du domaine | 🏡 Accueil du blog