È possibile copiare un'installazione Raspbian esistente e configurata su una scheda SD più piccola?
Quando ho installato Raspbian per la prima volta avevo solo una scheda da 32 GB a portata di mano, ovviamente più grande del necessario.
È possibile copiare un'installazione Raspbian esistente e configurata su una scheda SD più piccola?
Quando ho installato Raspbian per la prima volta avevo solo una scheda da 32 GB a portata di mano, ovviamente più grande del necessario.
Risposte:
In questa risposta, dimostrerò cosa fare passo dopo passo affinché le persone comprendano la logica alla base della soluzione e siano in grado di applicare i passaggi agli altri problemi.
Ma in primo luogo, si dovrebbe affermare che è un problema generico (non specifico per raspi) migrare i filesystem da una scheda SD a una scheda SD più piccola (ma abbastanza grande per i dati).
Un laptop con un lettore di schede micro SD e Linux (preferisco Ubuntu) in esecuzione su di esso.
PIBOX : Raspberry Pi which is used
SD_CARD_A : 8GB micro SD card which is used on PIBOX and on which Raspbian-lite (the OS) is installed
SD_CARD_B : 2GB micro SD card which will be used on PIBOX and on which Raspbian-lite (the OS) will be installed
Mentre PIBOX è in esecuzione, elenchiamo le partizioni (qui non vengono visualizzate partizioni di sistema non necessarie).
root@pibox:~# df -Th
Filesystem Type Size Used Avail Use% Mounted on
/dev/root ext4 7.3G 1.1G 5.9G 16% /
/dev/mmcblk0p1 vfat 63M 21M 43M 33% /boot
Ci sono 2 partizioni su SD_CARD_A come /
e /boot
. Anche 2 GB non vengono utilizzati in totale.
Dopo aver spento e arrestato PIBOX, estraiamo SD_CARD_A dalla scheda PIBOX e lo inseriamo nel lettore di schede del nostro laptop.
Le partizioni di SD_CARD_A vengono automaticamente montate sul nostro sistema come /dev/sdc1
e /dev/sdc2
.
root@mylaptop:~# df -Th
Filesystem Type Size Used Avail Use% Mounted on
/dev/sdb2 ext4 22G 13G 7.9G 63% /
/dev/sdb1 vfat 197M 2.6M 195M 2% /boot/efi
/dev/sda8 ext4 66G 11G 52G 17% /home
/dev/sdc1 vfat 63M 21M 43M 33% /media/some_user_name/boot
/dev/sdc2 ext4 7.3G 1.1G 5.9G 16% /media/some_user_name/some_uuid_serial
Smontiamo quelle partizioni dal nostro sistema per operare con successo su di esse.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Mostriamo le informazioni sul dispositivo di SD_CARD_A in dettaglio per le conferme nei passaggi successivi.
root@mylaptop:~# fdisk -l /dev/sdc
Disk /dev/sdc: 7969 MB, 7969177600 bytes
246 heads, 62 sectors/track, 1020 cylinders, total 15564800 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
Disk identifier: 0x2019f6d8
Device Boot Start End Blocks Id System
/dev/sdc1 8192 137215 64512 c W95 FAT32 (LBA)
/dev/sdc2 137216 15564799 7713792 83 Linux
Sopra puoi vedere che SD_CARD_A ha una capacità di 8 GB.
Cloniamo SD_CARD_A nel file pibox.img.
root@mylaptop:~# dd bs=4MB if=/dev/sdc of=pibox.img
1992+1 records in
1992+1 records out
7969177600 bytes (8.0 GB) copied, 416.582 s, 19.1 MB/s
Controlla la dimensione dei byte copiati, è uguale al valore ottenuto dal fdisk -l /dev/sdc
comando.
Linux ha un modulo chiamato loopback che ci fornisce la gestione di un file come dispositivo a blocchi.
Carichiamo il modulo loopback.
root@mylaptop:~# modprobe loop
Troviamo un percorso di dispositivo di loopback inutilizzato.
root@mylaptop:~# losetup -f /dev/loop0
Ora creiamo un dispositivo di loopback per il file pibox.img.
root@mylaptop:~# losetup /dev/loop0 pibox.img
Attiviamo il kernel per le modifiche alle partizioni.
root@mylaptop:~# partprobe /dev/loop0
Confermiamo se le operazioni precedenti hanno esito positivo.
root@mylaptop:~# losetup /dev/loop0
/dev/loop0: [0806]:69 (/root/pibox.img)
Visualizziamo le informazioni del dispositivo di loopback in dettaglio per confrontarle con SD_CARD_A.
root@mylaptop:~# fdisk -l /dev/loop0
Disk /dev/loop0: 7969 MB, 7969177600 bytes
255 heads, 63 sectors/track, 968 cylinders, total 15564800 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
Disk identifier: 0x2019f6d8
Device Boot Start End Blocks Id System
/dev/loop0p1 8192 137215 64512 c W95 FAT32 (LBA)
/dev/loop0p2 137216 15564799 7713792 83 Linux
Sopra puoi vedere che le dimensioni del dispositivo di loopback (= 7969177600 byte) e le partizioni sono uguali a quelle di SD_CARD_A.
D'ora in poi, ci concentreremo sulla partizione /dev/loop0p2
. Chiamiamolo THE_PARTITION .
La dimensione del blocco è di 512 byte (come stampato sulla riga che inizia con Unità = settori .....)
THE_PARTITION inizia dal blocco 137216 e termina al blocco 15564799, il che significa che ha le dimensioni di 15427584 blocks
(= 15564799 - 137216 + 1).
Pertanto, la dimensione di THE_PARTITION in byte è 7898923008 bytes
(= 512 * 15427584).
Per adattarsi a THE_PARTITION in SD_CARD_B, vogliamo che abbia una nuova dimensione 3710940 blocks
o in altre parole 1900001280 bytes
(= 512 * 3710940).
Pertanto, il nuovo numero di blocco finale viene 3848155
calcolato da start block number
(= 137216) + size in blocks
(= 3710940) - 1
.
Ci sono 2 operazioni che non devono essere confuse l'una con l'altra.
3710940 blocks
.3848155
.Prima di ridurre il file system, dovrebbe essere contrassegnato come pulito da e2fsck
.
root@mylaptop:~# e2fsck -f /dev/loop0p2
e2fsck 1.42.9 (4-Feb-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/loop0p2: 41175/475776 files (0.2% non-contiguous), 309183/1928448 blocks
Riduciamo il file system con resize2fs
.
root@mylaptop:~# resize2fs /dev/loop0p2 3710940s
resize2fs 1.42.9 (4-Feb-2014)
Resizing the filesystem on /dev/loop0p2 to 463867 (4k) blocks.
The filesystem on /dev/loop0p2 is now 463867 blocks long.
Impariamo con che numero THE_PARTITION è parted
.
root@mylaptop:~# parted /dev/loop0
GNU Parted 2.3
Using /dev/loop0
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Model: Loopback device (loop)
Disk /dev/loop0: 7969MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number Start End Size Type File system Flags
1 4194kB 70.3MB 66.1MB primary fat16 lba
2 70.3MB 7969MB 7899MB primary ext4
(parted) quit
Riduciamo THE_PARTITION con parted
.
root@mylaptop:~# parted /dev/loop0 unit s resizepart 2 3848155
Warning: Shrinking a partition can cause data loss, are you sure you want to continue?
Yes/No? Yes
Abbiamo finito con il dispositivo di loopback. Lo stacciamo.
root@mylaptop:~# losetup -d /dev/loop0
Verifichiamo la nuova tabella delle partizioni.
root@mylaptop:~# fdisk -l pibox.img
Disk pibox.img: 7969 MB, 7969177600 bytes
255 heads, 63 sectors/track, 968 cylinders, total 15564800 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
Disk identifier: 0x2019f6d8
Device Boot Start End Blocks Id System
pibox.img1 8192 137215 64512 c W95 FAT32 (LBA)
pibox.img2 137216 3848155 1855470 83 Linux
Nell'output si vede chiaramente che il numero del blocco finale di THE_PARTITION è ridotto from 15564799 to 3848155
.
L'ultimo blocco che usiamo è 3848155
. La numerazione dei blocchi inizia da 0. Quindi, abbiamo 3848155 + 1 blocchi in totale e la nuova dimensione del file pibox.img dovrebbe essere 1970255872 bytes
(= (3848155 + 1) * 512).
Tronciamo il file pibox.img.
root@mylaptop:~# truncate --size=1970255872 pibox.img
Verifichiamo le nuove dimensioni del file pibox.img.
root@mylaptop:~# ls -l pibox.img
-rw-r--r-- 1 root root 1970255872 Oct 13 21:53 pibox.img
Abbiamo inserito SD_CARD_B nel lettore di schede del nostro laptop. Le partizioni di SD_CARD_B vengono automaticamente montate sul nostro sistema come /dev/sdc1
e /dev/sdc2
.
root@mylaptop:~# df -Th
Filesystem Type Size Used Avail Use% Mounted on
/dev/sdb2 ext4 22G 13G 7.9G 63% /
/dev/sdb1 vfat 197M 2.6M 195M 2% /boot/efi
/dev/sda8 ext4 66G 11G 52G 17% /home
/dev/sdc1 vfat 63M 21M 43M 33% /media/some_user_name/boot
/dev/sdc2 ext4 1.8G 1.6G 59M 97% /media/some_user_name/some_uuid_serial
Sopra puoi vedere che SD_CARD_B ha una capacità di 2 GB.
Smontiamo quelle partizioni dal nostro sistema per operare con successo su SD_CARD_B.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Cloniamo il file pibox.img in SD_CARD_B.
root@mylaptop:~# dd bs=4MB if=pibox.img of=/dev/sdc
492+1 records in
492+1 records out
1970255872 bytes (2.0 GB) copied, 646.967 s, 3.0 MB/s
Controlla la dimensione dei byte copiati, è uguale al valore ottenuto dal ls -l pibox.img
comando.
Dopo aver rimosso SD_CARD_B dal nostro laptop e averlo inserito nella scheda PIBOX, avviamo il sistema e accediamo alla console PIBOX.
Elenchiamo le partizioni (alcune altre partizioni di sistema non necessarie non vengono visualizzate qui).
root@pibox:~# df -Th
Filesystem Type Size Used Avail Use% Mounted on
/dev/root ext4 1.8G 1.1G 601M 64% /
/dev/mmcblk0p1 vfat 63M 21M 43M 33% /boot
losetup
o addirittura -o loop=whatever
. Come per l'altro post ho appena usato mount -o offset=123 /imagefilepath /mntpoint
e l'uso del loopback è implicito. Presumo che questo sia generalmente vero su Linux ora - prova a vedere. Potresti quindi ridurlo fino a dire semplicemente che le partizioni sono montate tramite un "dispositivo di loopback" virtuale.
Quando hai usato dd if=/dev/sdx of=/path/to/image bs=1M
, si /dev/sdx
riferisce all'intero "disco", quindi l'immagine sarebbe sempre la dimensione dell'intera scheda.
Invece, dovresti usare dd if=/dev/sdxn ...
dov'è n
il numero di partizione.
Probabilmente dovrai farlo due volte: una volta per la /boot
partizione e una volta per la /
partizione.
Quindi avresti bisogno di creare partizioni sulla nuova scheda che siano grandi almeno quanto quelle due originali, per riportare il contenuto.
Usa qualcosa come parted (editor di partizioni) per ridurre la partizione primaria a una dimensione più piccola e quindi usa uno strumento come Clonezilla per copiare dalla partizione ora più piccola alla tua nuova scheda. Tuttavia, probabilmente dovrai farlo su un altro computer.
dd if=/dev/sdx of=/path/to/image bs=1M
da questo thread: raspberrypi.stackexchange.com/questions/311/…
Crea un'immagine della scheda utilizzando uno dei metodi già menzionati: come posso eseguire il backup di Raspberry Pi?
Usa lo script su http://sirlagz.net/2013/03/10/10/script-automatic-rpi-image-downsizer/ per ridimensionare l'immagine
Ripristina l'immagine ridimensionata su una nuova scheda più piccola
script.sh
, Rendi eseguibile il file usando chmod
ed eseguilo.
Sto usando rsync
per copiare filesystem da un disco all'altro da un po 'di tempo, senza problemi. Il vantaggio di usare rsync è che sta copiando il contenuto del filesystem, piuttosto che fare una copia a livello di blocco del dispositivo; di conseguenza, in realtà non importa le dimensioni dell'unità di destinazione e di origine, a condizione che l'unità di destinazione disponga di spazio sufficiente per contenere i dati.
Quindi ecco come lo farei:
rsync -avx oldFilesystem newFilesystem
per copiare / sovrascrivere il filesystem sulla nuova scheda con il filesystem della vecchia scheda.rpi-update
per assicurarti che il tuo firmware sia coerente e aggiornato.Dopodiché, sulla tua nuova scheda dovrebbe essere installato un sistema Raspbian perfettamente funzionante.
Ho creato uno script di shell per il backup e il ripristino di tutti i dati su una scheda SD. Elimina prima alcuni dati (corrispondenti al mio progetto) e riduce la partizione alla dimensione minima in modo che l'immagine sia grande quanto i dati sulla scheda SD. Come aggiunta, lo script crea un file * .zip dell'immagine. Dopo aver ripristinato l'immagine creata su un'altra scheda SD, la partizione verrà ingrandita alla dimensione massima. Lo script utilizza i comandi menzionati nelle altre risposte. Dato che questo è il mio script di pugno con queste dimensioni, mi ci sono volute ore per crearlo e non è un jet perfetto. Soprattutto non so come gestire i valori di ritorno di resize2fs e fdisk, quindi l'utente deve digitare i valori di cui ho bisogno. Ci sono idee per risolverlo? Spero che questa sceneggiatura aiuti qualcun altro. Sentiti libero di modificarlo e migliorarlo.
"Usage:
<skriptname> -b <path> create backup of SC Card (dev/mmcblk0) to file <path>/JJJJ-MM-DD_HHMM.img
<skriptname> -r <path>/FILENAME.img restore an exitsting image (<path>/FILENAME.img) to the SD Card (dev/mmcblk0)
<skriptname> -r <path>/FILENAME.zip unzip and restore an exitsting image (<path>/FILENAME.zip) to the SD Card (dev/mmcblk0)
<skriptname> -h show this hlep
Ecco qui:
#!/bin/bash
# check if the user is root
if (( $EUID != 0 )); then
echo "This script requires root privileges please run as root"
exit
fi
while getopts ":b:r:h" opt; do
case $opt in
b)
mode="backup"
OUTPATH=$OPTARG
;;
r)
mode="restore"
DIRFILENAME=$OPTARG
;;
h)
mode="help"
;;
\?)
echo "Invalid option: -$OPTARG. Use -h for help" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument. Use -h for help" >&2
exit 1
;;
esac
done
# no option
if [ $OPTIND == 1 ]
then
echo "$(basename "$0") needs an option! Use -h for help"
exit 1
fi
myMount(){
# create mountpoint if not existing
if [ ! -d /tmp/sd2/ ] ; then
mkdir /tmp/sd2
fi
# mount partition
mount -v -t ext4 /dev/mmcblk0p2 /tmp/sd2
err=$?
if [ $err != 0 ]; then
echo "mount failed error: $err"
exit 1
fi
}
myUmount(){
cd /home/ # otherwise umount will fail
# fuser -vm /tmp/sd2/
# umount partition
umount -v /tmp/sd2
err=$?
if [ $err != 0 ]; then
echo "umount failed error: $err"
exit 1
fi
}
myEnlarge(){
echo "enlarge partition..."
# enlarge partition is not posible with fdisk -> delete and recreate it
(
echo d # delete partition
echo 2 # patition number
echo n # add a new partition
echo p # primary partition
echo 2 # partition number
echo # first sector (accept default: varies)
echo # last sector (accept default: varies)
echo w # write changes
) | fdisk /dev/mmcblk0
echo "\n check filesystem... "
e2fsck -f -v -C 0 /dev/mmcblk0p2
# enlarge filesystem to maxsize
resize2fs -p /dev/mmcblk0p2
}
case "$mode" in
"help")
echo "Usage:
$(basename "$0") -b <path> create backup of SC Card (dev/mmcblk0) to file <path>/JJJJ-MM-DD_HHMM.img
$(basename "$0") -r <path>/FILENAME.img restore an exitsting image (<path>/FILENAME.img) to the SD Card (dev/mmcblk0)
$(basename "$0") -r <path>/FILENAME.zip unzip and restore an exitsting image (<path>/FILENAME.zip) to the SD Card (dev/mmcblk0)
$(basename "$0") -h show this hlep
--------------------------------
Adrian Zeitler, Germany 2017"
;;
"backup") ####################################### backup #######################################
echo "an image of the SD Card (/dev/mmcblk0) whitch is as smal as possible will be created to $OUTPATH."
# ------------------ delete some data --------------------
echo "Do you want to delete tempfiles? [y/n]"
read delfiles
if [ "$delfiles" = "y" ]
then
echo "Delete tempfiles..."
myMount
# remove some data
cd /tmp/sd2/home/alarm/
rm -v -f hagelbeere.db
rm -v -f HAILcam.log
rm -v -f HAILcam.log.1
rm -v -f test.jpg
myUmount
elif [ "$delfiles" = "n" ]
then
echo "I don't delete anything."
else
echo "Sorry, I didn't understand."
exit 1
fi
# --------------------------------------------------------------
# shrink partition 2 to minimum size
echo "check file system... "
e2fsck -f -v -C 0 /dev/mmcblk0p2
err=$?
if [ $err != 0 ]; then
echo "file system check failed, error: $err"
exit 1
fi
echo "shrink filesystem of partition 2 to minimum size..."
resize2fs -p -M /dev/mmcblk0p2
err=$?
if [ $err != 0 ]; then
echo "resize2fs failed, error: $err"
exit 1
fi
# --> Das Dateisystem auf /dev/mmcblk0p2 ist nun 692365 Blöcke groß.
echo "Please tell me the new filesystem size displayed above:"
read size
# from resize2fs blocksize, fdisk wants sector: sector = block * 8
size=$(( $size*8 ))
# shrink partition is not posible with fdisk -> delete and recreate it
(
echo d # delete partition
echo 2 # patition number
echo n # add a new partition
echo p # primary partition
echo 2 # partition number
echo # first sector (accept default: varies)
echo +$size # last sector
echo w # write changes
) | fdisk /dev/mmcblk0
err=$?
if [ $err != 0 ]; then
echo "fdisk failed, error: $err"
exit 1
fi
# --------------------------------------------------------------
# fill unused space with zeros
echo "Do you want to fill unused space with zeros? [y/n]"
read fillzeros
if [ "$fillzeros" = "y" ]
then
echo "Copy zeros. This will end up with an error. But this is ok."
myMount
dd if=/dev/zero | pv | dd of=/tmp/sd2/nullen.datei conv=noerror,notrunc,sync bs=10240
# exits with error -> this is normal
# dlelete zeros
rm -v -f /tmp/sd2/nullen.datei
sync
myUmount
elif [ "$fillzeros" = "n" ]
then
echo "I don't delete anything."
else
echo "Sorry, I didn't understand."
exit 1
fi
# --------------------------------------------------------------
# find out end of partition
fdisk -l /dev/mmcblk0
echo "Please tell me the end of mmcblk0p2 displayed above."
read count
DATE=$(date +"%Y-%m-%d_%H%M")
IMGFILENAME=$DATE.img
echo "Do you want to create image with filename $OUTPATH$IMGFILENAME? [y/n]"
read answer
if [ "$answer" = "y" ]
then
echo "Do you want to create a *.zip file of the created image? [y/n]"
read zip
echo "Do you want to enlarge partition 2 to maxsize after image creation? [y/n]"
read enlarge
echo "create image..."
cd $OUTPATH
# create image with dd, stop at and of partition
# count=N copy only N input blocks
# bs=BYTES read and write up to BYTES bytes at a time = block size
# pv show status
dd if=/dev/mmcblk0 | pv -s $(( $count*512 )) | dd of=$IMGFILENAME bs=512 count=$count
err=$?
if [ $err != 0 ]; then
echo "dd failed error: $err"
exit 1
fi
# --------------------------------------------------------------
# create zip file
# or like this:
# sudo dd if=/dev/sdX | pv |gzip > /pfad/zur/datei.img.gz
if [ "$zip" = "y" ]
then
echo "create zip file..."
zip $DATE.zip $IMGFILENAME
fi
# --------------------------------------------------------------
fi
# --------------------------------------------------------------
# enlarge partition 2
if [ "$enlarge" = "y" ]
then
myEnlarge
fi
;; #end case mode backup
"restore") ####################################### restore #######################################
#chek if image exists
if [[ -s "$DIRFILENAME" ]]
then
# check if file is an image or zip file
if [[ $DIRFILENAME =~ \.img$ ]]
then
IMGFILENAME=$(basename "$DIRFILENAME")
elif [[ $DIRFILENAME =~ \.zip$ ]]
then
ZIPFILENAME=$(basename "$DIRFILENAME")
else
echo "Not the right file format. I accept *.img and *.zip"
exit 1
fi
else
echo "Image file does not exist."
exit 1
fi
echo "the file $DIRFILENAME will be restored to the SD Card /dev/mmcblk0"
#change to the path of the imagefile
SOURCEPATH=$(dirname "$DIRFILENAME")
cd $SOURCEPATH
if [ "$ZIPFILENAME" != "" ]
then
echo "unzip file"
# change file extention form zip zu img
l=$(( ${#ZIPFILENAME}-3 ))
IMGFILENAME="${ZIPFILENAME:0:l}img"
unzip $ZIPFILENAME
fi
echo "Do you realy want to restore $SOURCEPATH/$IMGFILENAME to the SD card /dev/mmcblk0?
Warning: all data on the device /dev/mmcblk0 will be lost! [y/n]"
read answer
if [ "$answer" = "y" ]
then
echo "Do you want to enlarge partition 2 to maxsize after restoring? [y/n]"
read enlarge
echo "restore image..."
filesize=$(wc -c <"$IMGFILENAME")
echo "Filesize = $filesize Byte"
dd if=$IMGFILENAME | pv -s $filesize | dd of=/dev/mmcblk0 bs=512
err=$?
if [ $err != 0 ]; then
echo "dd failed error: $err"
exit 1
fi
fi
# --------------------------------------------------------------
# enlarge partition 2
if [ "$enlarge" = "y" ]
then
myEnlarge
fi
;; #end case mode restore
esac
La soluzione più semplice che ho trovato è stata quella di fare un backup della scheda più grande originale usando i comandi dd descritti sopra e quindi ripristinare l'immagine sulla scheda più piccola usando qualcosa come piwriter. dd potrebbe anche funzionare ... non sono sicuro. PiWriter ha restituito un errore poiché ha esaurito lo spazio, ma poiché l'immagine non conteneva dati effettivi oltre le dimensioni della scheda più piccola, stava semplicemente troncando i settori vuoti. Non sono sicuro di quali siano le implicazioni di questo ... potrebbe essere necessario verificare o riparare la partizione, ma posso verificare che abbia funzionato quando l'ho inserito nel Pi.
Uso una vecchia versione di win32diskimager-RELEASE-0.1-r15-win32
per leggere l'immagine, crea un'immagine di 4 GB anche da una scheda SD da 8 GB e quindi scrive l'immagine con l'ultima versione di win32diskimager.
Uso la versione precedente perché la vecchia salterà ogni errore.