[info+script] 📍 Montage partition + image iso/disque + Squashfs pour l'usager lambda

Sujet montage partitions et images disque qui pourrait paraütre simple, mais qui ne l’est pas si on ne se pose pas les bonnes questions.
Quelques recommandations, Ă  toutes fins utiles, chacun ayant sa perception du problĂšme, en considĂ©rant qu’il n’existe pas de rĂšgles absolues dans un univers Ă  solutions multiples.
―――
Dans la suite, on distinguera trĂšs explicitement deux types de montage:
1 - le montage des partitions systĂšme impliquant fstab/systemd dont l’accĂšs doit ĂȘtre exclusivement rĂ©servĂ© Ă  l’administrateur, et personne d’autre;
2 - tout ce qui n’est pas systĂšme, c’est-Ă -dire Ă  un usager lambda, ou une session invitĂ©, de pouvoir monter un pĂ©riphĂ©rique externe pour lecture/Ă©criture, ou une image disque, fichier iso hybride (ou non), Squashfs etc etc, pour en lire le contenu.

C’est le cas N°2 qui concerne ce sujet: l’usager lambda, en environnement bureau.

:large_blue_circle: Les commandes:
Beaucoup d’outils dans l’historique des solutions, de la confusion, selon le backend utilisĂ©, en passant par udevil, udev, udisks, udisks2, gvfs, kio, fuse, avec des terminologies telles que polkit, policykit pour gĂ©rer les droits. On s’y perd vite pour comprendre le rĂŽle prĂ©cis de chaque Ă©lĂ©ment impliquĂ©, ou redondant Ă  Ă©viter.

Sauf cas trĂšs particulier oĂč l’usager unique est aussi l’administrateur, mount est une commande qui ne doit pas ĂȘtre utilisĂ©e dans un environnement bureau pour un montage de pĂ©riphĂ©rique externe pour les raisons suivantes:
→ par dĂ©faut, mount est uniquement accessible Ă  l’administrateur pour une opĂ©ration de montage/dĂ©montage.
→ mount est trop bas niveau pour interagir directement avec l’utilisateur;
→ on n’imaginerait pas un administrateur mettre chaque utilisateur dans un groupe â€č sudo â€ș pour l’autoriser Ă  Ă©couter sa musique sur son pĂ©riphĂ©rique externe, et accessoirement bricoler un fstab, et casser le systĂšme, avec un doigt qui fourche sur le clavier.

pmount par exemple, s’appuie sur HAL (Hardware Abstraction Layer), et ne comprend pas D-bus/udev/udisks2; peut donc encore convenir en usage terminal, mais pas nĂ©cessaire ( pmount 2011 ).

S’il est possible de cliquer sur un icĂŽne pour monter une clef USB, c’est que la commande existe dĂ©jĂ , sans rien installer de spĂ©cifique. Elle s’appelle udisksctl, fournie par udisks2 normalement installĂ©.

udisksctl crée automatiquement les points de montage sous /media/<user>/... (par défaut le label si existant, ou PARTUUID):
→ inutile de bricoler fstab ou des points de montage sous /media/<user>/, espace rĂ©servĂ© Ă  udisks.
→ udisksctl ne gĂšre pas des permissions user/group d’écriture sur un disque, ce n’est pas sa fonction.

:large_blue_circle: Limitation de confusion d’identification des partitions:
Afin d’éviter toute confusion, on ne dĂ©signe pas dans un script une partition par son inode (ex: /dev/sdc3), parce-qu’un script ne peut pas prĂ©dire quel inode sera utilisĂ© lorsque plusieurs pĂ©riphĂ©riques externes sont connectĂ©s.
→ dĂ©finir un label clair, explicite, unique et sans espaces pour identifier une partition;
→ le PARTUUID peut aussi ĂȘtre utilisĂ© de maniĂšre trĂšs fiable, bien que moins expressif, mais indiquant le N° de partition, toujours mieux que l’UUID dont la combinaison de l’ordre de { 36 puissance 32 } caractĂšres est ridiculement Ă©levĂ©e pour distinguer 3 malheureux pĂ©riphĂ©riques.

remarque:
L’avantage du PARTUUID n’est valable essentiellement que pour une table de partitions de type MBR.
Pour le GPT, c’est plus alĂ©atoire, selon l’outil utilisĂ© pour le partitionnement.

Exemple d’identification /dev/sdc5

 LABEL    : backup
 PARTUUID : 7a092ff8-05
 UUID     : 423dg594-9412-4940-a9c8-37f22565498c

:large_blue_circle: Comment mettre un label (Ă©tiquette) Ă  une partition:
Avec e2fsprogs installé, pour ext2/3/4:
# e2label /dev/sdxy monlabel
ou :
# tune2fs /dev/sdxy -L monlabel
ou pour du vfat, avec dosfstools installé:
# dosfslabel /dev/sdxy monlabel

:large_blue_circle: Gestion du « mot de passe » nécessaire au montage
→ rien Ă  voir avec des permissions d’écriture.
La gestion ciblĂ©e des droits â€č sudo â€ș par commande et utilisateur est possible, mais un Ă©ventuel remplacement de â€č sudo â€ș par â€č doas â€ș par exemple, obligerait Ă  tout reconsidĂ©rer: trĂšs vite un casse-tĂȘte.
Pour monter une partition de pĂ©riphĂ©rique type disque externe, par dĂ©faut, une fenĂȘtre s’ouvrira pour demander un mot de passe.
Si considĂ©rĂ© superflu par l’administrateur, c’est facilement contournable en autorisant par exemple les utilisateurs du groupe plugdev Ă  monter les partitions, en ajoutant une rĂšgle policykit dans un fichier â€č /etc/polkit-1/rules.d/10-udisks2.rules â€ș qui contient:

// Allow udisks2 to mount devices without authentication
// for users in the "plugdev" group.

polkit.addRule(function(action, subject) {
    if ((action.id == "org.freedesktop.udisks2.filesystem-mount-system" ||
         action.id == "org.freedesktop.udisks2.filesystem-mount" ||
         action.id == "org.freedesktop.udisks2.loop-delete-others") &&
        subject.isInGroup("plugdev")) {
        return polkit.Result.YES;
    }
});

On vĂ©rifie que l’utilisateur est bien dans le groupe â€č plugdev â€ș avec la commande groups, sinon, l’administrateur le rajoute.

:large_blue_circle: Les droits d’écriture sur le disque:
Si les rĂ©pertoires du disque appartiennent Ă  l’utilisateur, ou Ă  son groupe, il n’y a aucune raison de ne pas pouvoir y Ă©crire si le disque n’est pas montĂ© en read-only.
Si des rĂ©pertoires ont prĂ©cĂ©demment Ă©tĂ© crĂ©Ă©s avec des vilains â€č sudo â€ș, il suffit de redĂ©finir correctement les droits.
# chown -R toto:users <mon rep>, pouvant ĂȘtre directement le point de montage, Ă  faire au premier montage: le file-system de la partition montĂ©e retiendra les droits demandĂ©s lors du prochain montage.

Autre possibilitĂ© plus gĂ©nĂ©rique pour de l’ext2/3/4: prĂ©-optionner la partition pour en dĂ©finir l’utilisateur par dĂ©faut, option de permission qui sera prise en compte lors de l’opĂ©ration de montage:
# tune2fs -u 1000 -g 1000 /dev/sdxy

:large_blue_circle: Un script générique de montage: Mount
Passons Ă  la pratique avec un script que j’appelle Mount, un couteau suisse pour monter des partitions (cas le plus simple), mais aussi des images isos hybrides Ă  au moins deux partitions (vfat + iso par exemple), ou un fichier Squashfs, qui a Ă©voluĂ© selon des cas particuliers que j’ai rencontrĂ©s lors de tests de fichiers disques exotiques.
Il est bien Ă©videmment sur-spĂ©cifiĂ© pour monter une partition, mais lors du dĂ©montage (-u), vĂ©rifie que la partition peut ĂȘtre dĂ©montĂ©e â€č proprement â€ș en signalant les applications en cours d’utilisation.
→ Monter une partition est une chose, mais la dĂ©monter correctement est fondamental pour ne pas risquer de corrompre le file-system, ce qui nĂ©cessiterait une opĂ©ration de vĂ©rification avant tout remontage. Ce point est gĂ©nĂ©ralement nĂ©gligĂ©. Forcer un dĂ©montage rĂ©calcitrant n’est pas une bonne habitude.

Avec une prise en main de quelques essais, et un â€č help â€ș suffisamment explicite, ça ne devrait pas poser de problĂšmes d’usage.
――――――――――――――――――――――――――
Mount

#!/bin/bash
# 20240910
# script de montage/démontage udisks2.
# monte/démonte: partition, iso, image disque, squashfs
#----------------------------------------------
[[ $1 = -h ]] && { cat <<EOF |sed 's/Mount/\x1b[33m&\x1b[m/g'
 Usage: Mount <option> FICHIER/OBJET

 Description:
  script de montage partitions, fichiers de type
  image disque ou ISO ou Squashfs, avec quelques vérifications d'usage,
  pour usage en environnement bureau, tout utilisateur.
  Utilisation en espace <user>, ne nécessite ni sudo, mount, ou bricolage fstab
  Le montage udisks se fait sous /media/<user>/...
  -> lecture seule pour images/isos/squashfs
  -> mode Ă©criture pour partitions
  Les points de montage sont automatiquement créés.
  Le nom de montage est le Label partition si existant (recommandé).
  Nécessite le paquet util-linux, et lsof pour détection occupation disque.

 * Sans argument, la liste des block-devices disponibles est affichée
 * Partition en argument, identifiée indifféremment par soit:
   /dev/.... ou Label, ou PartUUID, ou UUID.
 * détecte les applications en cours bloquant un démontage 'propre'

 Options:
 -u: (=unmount) démontage
     sans argument, liste les points de montage actifs sous /media/<user>/
 -c: nettoyage des /dev/loops résiduels inutilisés (non essentiel)
 -h: ce message d'aide

 Exemples:
    Mount ; Mount -u ; Mount /dev/sdc9 ; Mount -u 7a970ff8-05
    Mount <label>    ; Mount -u <point de montage>
    Mount sparkylinux-lxqt.iso ; Mount linuxfs ; Mount bookworm_dev.img
EOF
exit
}
[[ $1 = -? ]] && { a=$1; I=$2; } || { I=$1; a=$2; }
#--------------------------
V='PATH,FSTYPE,LABEL,MOUNTPOINTS,PARTUUID'
lsb() { lsblk -lpo $V -x PATH |awk '$3~/./' ; }

if [[ -z $I ]] ; then
  case $a in
 -c) while read x ; do udisksctl loop-delete -b $x
     done < <(lsblk -no PATH -x PATH |grep -o '/dev/loop[^p]*' |sort -u)
     lsblk -lpo $V -x PATH |awk '/loop/' ; exit 0 ;;
 -u) lsb |sed -n "1p;\%/media/%p" ;;
  *) lsb ; exit ;;
  esac
 else
  case $a in
 -u) #---| DĂ©montage |---
  D=$(lsb |sed -n "\%${I}%{s/ .*//p;q}")
  [ "$D" ] && echo " -> démontage $D" || exit
  msg() { if [ -f /usr/bin/lsof ] ; then
          printf "――\n$I est peut-ĂȘtre en cours d'utilisation par une application\n"
          lsof +f -- $(lsblk -no PATH,MOUNTPOINTS |sed -n "\%${D}%s/[^ ]* //p") | \
          awk 'NR>1{print $1,$9}'
        else echo "lsof est manquant"
          fi ; }
  [ $D = ${D/\/loop/} ] && { udisksctl unmount -b $D 2>/dev/null || msg ; } || \
  { [ $D = ${D/p*p/} ] || D="${D%p*}"
    L=$(lsblk -no PATH,MOUNTPOINTS |sed -n '\%/loop%p')
    for x in $(ls -r ${D}*); do udisksctl unmount -b $x 2>/dev/null; done
    udisksctl loop-delete -b $D 2>/dev/null
    lsblk -no $V | grep "$D" && msg ; }
 ;;
 *)  #---| Montage |---
  if [ -s "$I" ] ; then # fichier image|iso|squashfs
    file -b "$I"
    D=$(udisksctl loop-setup --file "$I" --read-only |grep -o '/dev/loop[^.]*')
    echo " -> $D"
    for x in ${D}* ; do udisksctl mount -b $x 2>/dev/null; done
  else V1="${V},UUID"  # partition
    A=$(LC_ALL=C lsblk -Po $V1 |sed -n "\%=\"${I}\"%{s/\" /\n/g;s/\"//g;p}")
    [[ $A ]] && D=$(sed -n '/PATH/s/.*=//p' <<< "$A") || \
    { echo " ‘${I}’ non accessible"; lsb ; exit; }
    grep -q 'FSTYPE=$' <<< "$A" && echo "Partition non formatée" && exit
    grep -q 'MOUNTPOINTS=.' <<< "$A" && \
    { echo "Partition $I déjà montée"; lsb |sed -n "1p;\%${D}%p"; exit; }
    grep -q 'LABEL=$' <<< "$A" && \
    echo "La partition ‘${I}’ n'a pas encore de label; c'est dommage"
    # montage / Point de Montage passé à la variable PM
    PM=$(udisksctl mount -b $D |grep -o '/media/[^.]*$')
    [[ $PM ]] && lsb |sed -n "1p;\%${PM}%p"
  fi
  ;;
  esac
fi
#--------------------------
exit

――――――――――――――――――――――――――
Exemples:

$ Mount
  PATH      FSTYPE LABEL    MOUNTPOINTS PARTUUID
  /dev/sda1 ext2   sda1                 7a579ff8-01
  /dev/sda2 ext4   devuan               7a579ff8-02
  /dev/sda3 ext4   trixie   /           7a579ff8-03
  /dev/sda5 ext4   S5_home  /home       7a579ff8-05
  /dev/sda6 ext4   S6_extra /mnt/extra  7a579ff8-06
  /dev/sda7 ext4   backup               7a579ff8-07

$ Mount backup
  PATH      FSTYPE LABEL     MOUNTPOINTS       PARTUUID
  /dev/sda7 ext4   backup    /media/user1/backup 7a579ff8-07

$ Mount TinyCore-current.iso
  ISO 9660 CD-ROM filesystem data (DOS/MBR boot sector) 'TinyCore' (bootable)
   -> /dev/loop0
  Mounted /dev/loop0p1 at /media/user1/TinyCore

$ Mount easy.sfs
  Squashfs filesystem, little endian, version 4.0, zstd compressed
   -> /dev/loop1
  Mounted /dev/loop1 at /media/user1/disk

$ Mount sparkylinux-2024.05-x86_64-lxqt.iso
  ISO 9660 CD-ROM filesystem data (DOS/MBR boot sector) 'SPARKY_64bit' (bootable)
  -> /dev/loop2
  Mounted /dev/loop2p1 at /media/user1/SPARKY_64bit
  Mounted /dev/loop2p2 at /media/user1/6484-3985

$ Mount -u
  PATH         FSTYPE   LABEL        MOUNTPOINTS             PARTUUID
  /dev/loop0p1 iso9660  TinyCore     /media/user1/TinyCore     1a8d81de-01
  /dev/loop1   squashfs              /media/user1/disk
  /dev/loop2p1 iso9660  SPARKY_64bit /media/user1/SPARKY_64bit 05aa05a3-01
  /dev/loop2p2 vfat                  /media/user1/6484-3985    05aa05a3-02
  /dev/sda7    ext4     backup       /media/user1/backup       7a579ff8-07

$ Mount -u SPARKY_64bit
  -> démontage /dev/loop2p2
  Unmounted /dev/loop2p2.
  Unmounted /dev/loop2p1.