Nei due articoli su mkfs e dd abbiamo lavorato con immagini di disco: file che contengono un file system o una tabella delle partizioni. Per formattarli, montarli o ispezionarli come se fossero dischi veri serve un passaggio intermedio, che li presenta al sistema come dispositivi a blocchi. Lo fa losetup.
Cos'è
losetup fa parte di util-linux e gestisce i dispositivi loop (da loopback), cioè pseudo-dischi come /dev/loop0, /dev/loop1 e così via, il cui contenuto non sta su un disco fisico ma in un normale file. Sono usati per montare immagini ISO e immagini di dischi, per creare file system di prova, per le immagini dei pacchetti Snap e in molte situazioni di test o di recupero dati.
Cosa fa
Associa un file a un dispositivo loop libero, elenca le associazioni attive e le scioglie. Una volta collegato, il dispositivo loop si comporta come qualunque disco: puoi formattarlo con mkfs, controllarlo con fsck, leggerlo con blkid, montarlo con mount. Ciò che scrivi sul dispositivo finisce nel file.
Come si usa
$ sudo losetup [opzioni] [DISPOSITIVO] [FILE]Serve quasi sempre sudo. In pratica si usano due forme: losetup -f --show FILE per collegare un file al primo dispositivo libero (stampando quale), e losetup -d DISPOSITIVO per scollegarlo. Negli esempi lavoro su immagini nella cartella corrente; i nomi come /dev/loop0 dipendono da quali dispositivi sono già in uso sul tuo sistema. Gli output sono di losetup 2.39.3, in inglese: con un sistema in italiano alcune righe potrebbero comparire tradotte.
Esempio 1: collegare un file a un dispositivo loop
$ sudo losetup -f
/dev/loop0
$ sudo losetup -f --show d.img
/dev/loop0-f da solo stampa il primo dispositivo libero senza usarlo. Con un file indicato lo collega, e --show stampa il nome del dispositivo scelto: è la forma comoda negli script, perché permette di catturarlo in una variabile (L=$(sudo losetup -f --show d.img)). Se il file non esiste, l'errore è chiaro: losetup: nope.img: failed to set up loop device: No such file or directory (codice 1).
Esempio 2: vedere cosa è collegato
$ losetup -l
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC
/dev/loop0 0 0 0 0 /tmp/lo/d.img 0 512
$ losetup -j d.img
/dev/loop0: [65024]:1269842 (/tmp/lo/d.img)-l elenca i dispositivi loop in uso con una tabella leggibile: BACK-FILE è il file collegato, OFFSET e SIZELIMIT (vedi l'esempio 5) i limiti dell'area usata, RO indica la sola lettura. -a elenca tutti i dispositivi nel formato breve che vedi nella seconda riga; -j FILE cerca invece quali dispositivi usano un file preciso. I numeri tra parentesi quadre (dispositivo e inode del file) cambiano da sistema a sistema. Se non c'è nessun dispositivo collegato, -l non stampa nulla.
Esempio 3: usarlo come un disco
$ sudo losetup -f --show d.img
/dev/loop0
$ sudo blkid /dev/loop0
/dev/loop0: LABEL="dati" UUID="a550a157-..." BLOCK_SIZE="4096" TYPE="ext4"
$ sudo mount /dev/loop0 /mnt
$ df -h /mnt | tail -1
/dev/loop0 56M 28K 52M 1% /mnt
$ sudo umount /mnt
$ sudo losetup -d /dev/loop0Il dispositivo loop mostra il file system ext4 contenuto nell'immagine, che si monta con mount e si usa come qualunque altro. L'UUID mostrato è un esempio e ho accorciato la riga con i puntini. Alla fine umount smonta e losetup -d scollega il dispositivo (codice 0). Un modo più breve è sudo mount -o loop d.img /mnt: mount chiama losetup da solo e, dopo umount, libera il dispositivo (nel mio test, a smontaggio fatto, losetup -l non elencava più nulla). Per scollegare un dispositivo inesistente: losetup: /dev/loop99: failed to use device: No such device.
Esempio 4: collegare in sola lettura
$ sudo losetup -f --show -r d.img
/dev/loop0
$ losetup -l -O NAME,RO
NAME RO
/dev/loop0 1
$ sudo dd if=/dev/zero of=/dev/loop0 bs=1 count=1
dd: error writing '/dev/loop0': Operation not permittedCon -r il dispositivo è di sola lettura: il kernel rifiuta qualsiasi scrittura, anche da parte di root. È il modo giusto per esaminare un'immagine senza rischiare di modificarla (un'immagine di un disco da analizzare, per esempio). Con -O scegli le colonne di -l. Se provi a montarlo, mount lo monta in sola lettura e te lo dice con un avviso (WARNING: source write-protected, mounted read-only).
Esempio 5: lavorare su una porzione del file (offset e sizelimit)
$ sudo losetup -f --show -o 1048576 --sizelimit 20480000 disco.img
/dev/loop0
$ sudo mkfs.ext4 -q -L p1 /dev/loop0
$ sudo losetup -d /dev/loop0
$ blkid -p -O 1048576 disco.img
disco.img: LABEL="p1" UUID="348005af-..." VERS...Con -o (offset, in byte) e --sizelimit il dispositivo loop corrisponde solo a una parte del file: serve per accedere a una partizione dentro l'immagine di un disco intero. Il mio disco.img ha una prima partizione che inizia al settore 2048 (2048 × 512 = 1048576 byte) e lunga 40000 settori (20480000 byte), come mostra fdisk -l. Ho creato l'ext4 sul dispositivo e blkid, guardando il file a quell'offset, l'ha trovato (ho accorciato la riga in fondo). Lo stesso offset si passa direttamente a mount: sudo mount -o loop,offset=1048576,sizelimit=20480000 disco.img /mnt, e ha funzionato.
Esempio 6: le partizioni come dispositivi separati (-P)
$ sudo losetup -f --show -P disco.img
/dev/loop0
$ ls /dev/loop0*
/dev/loop0 /dev/loop0p1 /dev/loop0p2Con -P (partscan) il kernel rilegge la tabella delle partizioni e crea un dispositivo per ciascuna: /dev/loop0p1, /dev/loop0p2. Su un sistema normale è il modo più comodo per usare un'immagine di disco intero. Non sono riuscito a verificarlo nel mio sandbox: l'opzione veniva accettata (il flag partscan in /sys/block/loop0/loop/ valeva 1) ma i dispositivi loop0p1 e loop0p2 non comparivano. L'elenco qui sopra è quello che ci si aspetta su un sistema con udev; se non compaiono, usa la tecnica dell'offset dell'esempio 5.
Esempio 7: aggiornare la dimensione dopo aver ingrandito il file
$ truncate -s 128M g.img
$ lsblk -n -o NAME,SIZE /dev/loop0
loop0 64M
$ sudo losetup -c /dev/loop0
$ lsblk -n -o NAME,SIZE /dev/loop0
loop0 128MSe ingrandisci il file mentre il dispositivo è collegato, il dispositivo non se ne accorge subito: losetup -c (set-capacity) lo aggiorna. È il passaggio preliminare per resize2fs quando si allarga un file system contenuto in un'immagine. L'esempio parte da g.img collegato su /dev/loop0 da 64 MB, e l'ho provato così.
Esempio 8: scollegare tutto
$ losetup -l | wc -l
3
$ sudo losetup -D
$ losetup -l | wc -l
0-D scollega tutti i dispositivi loop non in uso. Qui wc -l contava 3 righe (intestazione più due dispositivi) prima e 0 dopo. I dispositivi ancora montati restano elencati finché non li smonti. Si usa come "pulizia generale" dopo una sessione di prove, come ho fatto io tra un test e l'altro.
Esempio 9: uso negli script
#!/bin/bash
[ $# -eq 3 ] || { echo "uso: $0 immagine partizione cartella" >&2; exit 1; }
IMG="$1"
N="$2"
MNT="$3"
start=$(fdisk -l -o Device,Start "$IMG" 2>/dev/null |
awk -v d="$IMG$N" '$1 == d {print $2}')
[ -n "$start" ] || { echo "partizione $N non trovata in $IMG" >&2; exit 1; }
mount -o loop,ro,offset=$((start * 512)) "$IMG" "$MNT" && echo "montata in $MNT"Lo script monta in sola lettura una partizione di un'immagine di disco: legge con fdisk -l il settore di inizio della partizione richiesta e lo converte in byte (per settori da 512 byte) per l'opzione offset. Sulla prima partizione del mio disco.img ha stampato "montata in m" (codice 0) e ho potuto leggerci un file; per una partizione inesistente, "partizione 3 non trovata" (codice 1); per la seconda partizione, che avevo lasciato senza file system, mount ha risposto "wrong fs type" (codice 32). Senza argomenti stampa il messaggio d'uso. Il calcolo con 512 vale per i dischi con settori da 512 byte; con altri settori va adattato.
Opzioni utili
-f: usa il primo dispositivo libero (da solo, lo stampa).--show: stampa il dispositivo scelto.-d DISPOSITIVO: scollega un dispositivo.-D: scollega tutti quelli non in uso.-l: elenca i dispositivi in uso (-Osceglie le colonne).-a: elenco breve.-j FILE: cerca per file.-r: sola lettura.-o BYTEe--sizelimit BYTE: usa solo una parte del file.-P: rileva le partizioni (non verificato nel sandbox).-c DISPOSITIVO: aggiorna la dimensione dopo aver cambiato quella del file.-b DIMENSIONE: dimensione logica del settore (nel mio test-b 4096l'ha impostata, vediLOG-SEC).
Attenzione a
- Scollegare sempre: un dispositivo loop dimenticato continua a tenere aperto il file e a occupare uno dei dispositivi disponibili. Dopo l'uso:
umounte poilosetup -d. - Prima smonta, poi scollega:
losetup -dsu un dispositivo ancora montato non dà errore (codice 0), ma si limita a marcarlo per lo scollegamento automatico (colonnaAUTOCLEARa 1): il dispositivo resta in uso finché non eseguiumount. Anche-Dlascia in elenco i dispositivi montati. - Le scritture finiscono nel file: se il file è l'immagine di un disco reale, un
mkfssul dispositivo loop la rovina. Per sicurezza lavora su una copia o usa-r. - Offset in byte, non in settori: sbagliare l'unità di misura dà un file system "non riconosciuto". Il settore di inizio va moltiplicato per la dimensione del settore (di solito 512).
- Il numero di dispositivi può essere limitato: con molte immagini montate (per esempio i pacchetti Snap) i dispositivi liberi possono finire. Se
losetup -fnon trova più dispositivi liberi, scollega quelli inutili. - Servono i permessi: senza
sudolosetupnon può collegare i file. Il mio sandbox gira come root, per cui non ho potuto provare l'uso senzasudo. - Non è un'astrazione sicura per dati sensibili: chiunque legga il file legge il contenuto del "disco". Per cifrarlo servono strumenti come
cryptsetup.
Riepilogo
| Comando | Cosa fa |
|---|---|
losetup -f --show FILE | Collega un file al primo dispositivo libero |
losetup -l | Elenca i dispositivi in uso |
losetup -j FILE | Cerca i dispositivi che usano un file |
losetup -d DEV | Scollega un dispositivo |
losetup -D | Scollega tutti i dispositivi non in uso |
losetup -r -f --show FILE | Collega in sola lettura |
losetup -o BYTE --sizelimit BYTE | Collega solo una porzione del file |
losetup -P -f --show FILE | Collega e rileva le partizioni |
losetup -c DEV | Aggiorna la dimensione dopo un truncate |
mount -o loop FILE DIR | Monta un'immagine senza usare losetup a mano |