¿Es posible copiar una instalación Raspbian existente y configurada en una tarjeta SD más pequeña?
Cuando instalé Raspbian por primera vez, solo tenía una tarjeta de 32 GB a mano, que obviamente es más grande de lo necesario.
¿Es posible copiar una instalación Raspbian existente y configurada en una tarjeta SD más pequeña?
Cuando instalé Raspbian por primera vez, solo tenía una tarjeta de 32 GB a mano, que obviamente es más grande de lo necesario.
Respuestas:
En esta respuesta, demuestro qué hacer paso a paso para que las personas entiendan la lógica detrás de la solución y puedan aplicar pasos en sus otros problemas.
Pero, en primer lugar, debe señalarse que es un problema genérico (no específico de raspi) migrar los sistemas de archivos de una tarjeta SD a una tarjeta SD más pequeña (pero lo suficientemente grande como para datos).
Una computadora portátil con un lector de tarjetas micro SD y Linux (prefiero Ubuntu) ejecutándose en ella.
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
Mientras PIBOX se está ejecutando, enumeramos las particiones (las particiones innecesarias del sistema no se muestran aquí).
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
Hay 2 particiones en SD_CARD_A como /
y /boot
. Incluso 2GB no se usa en total.
Después de apagar y detener PIBOX, sacamos SD_CARD_A de la placa PIBOX y la colocamos en el lector de tarjetas de nuestra computadora portátil.
Las particiones de SD_CARD_A se montan automáticamente en nuestro sistema como /dev/sdc1
y /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
Desmontamos esas particiones de nuestro sistema para operarlas con éxito.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Mostramos la información del dispositivo de SD_CARD_A en detalles para confirmaciones en los próximos pasos.
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
Arriba puede ver que SD_CARD_A tiene una capacidad de 8GB.
Clonamos SD_CARD_A en el archivo 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
Verifique el tamaño de los bytes copiados, es igual al valor que obtuvimos por fdisk -l /dev/sdc
comando.
Linux tiene un módulo llamado loopback que nos permite manejar un archivo como un dispositivo de bloque.
Cargamos el módulo loopback.
root@mylaptop:~# modprobe loop
Encontramos una ruta de dispositivo de bucle invertido no utilizada.
root@mylaptop:~# losetup -f /dev/loop0
Ahora, creamos un dispositivo loopback para el archivo pibox.img.
root@mylaptop:~# losetup /dev/loop0 pibox.img
Activamos el núcleo sobre los cambios de partición.
root@mylaptop:~# partprobe /dev/loop0
Confirmamos si las operaciones anteriores son exitosas.
root@mylaptop:~# losetup /dev/loop0
/dev/loop0: [0806]:69 (/root/pibox.img)
Mostramos la información del dispositivo de bucle invertido en detalles para compararla 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
Arriba puede ver que el tamaño del dispositivo de bucle invertido (= 7969177600 bytes) y las particiones son las mismas con las SD_CARD_A.
De ahora en adelante, nos centraremos en la partición /dev/loop0p2
. Llamémosle THE_PARTITION .
El tamaño del bloque es de 512 bytes (como se imprime en la línea que comienza con Unidades = sectores .....)
THE_PARTITION comienza desde el bloque 137216 y termina en el bloque 15564799, lo que significa que tiene el tamaño de 15427584 blocks
(= 15564799 - 137216 + 1).
Entonces, el tamaño de THE_PARTITION en bytes es 7898923008 bytes
(= 512 * 15427584).
Para ajustar THE_PARTITION en SD_CARD_B, queremos que tenga un nuevo tamaño 3710940 blocks
o, en otras palabras 1900001280 bytes
(= 512 * 3710940).
Entonces, el nuevo número de bloque final se 3848155
calcula mediante start block number
(= 137216) + size in blocks
(= 3710940) - 1
.
Hay 2 operaciones que no deben confundirse entre sí.
3710940 blocks
.3848155
.Antes de reducir el sistema de archivos, debe estar marcado como limpio por 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
Reducimos el sistema de archivos 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.
Aprendemos con qué está el número 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
Encogemos 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
Hemos terminado con el dispositivo de bucle invertido. Lo separamos.
root@mylaptop:~# losetup -d /dev/loop0
Verificamos la nueva tabla de particiones.
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
En la salida, se ve claramente que el número de bloque final de THE_PARTITION disminuye from 15564799 to 3848155
.
El último bloque que usamos es 3848155
. La numeración de los bloques comienza desde 0. Entonces, tenemos 3848155 + 1 bloques en total y el nuevo tamaño del archivo pibox.img debe ser 1970255872 bytes
(= (3848155 + 1) * 512).
Truncamos el archivo pibox.img.
root@mylaptop:~# truncate --size=1970255872 pibox.img
Verificamos el nuevo tamaño del archivo pibox.img.
root@mylaptop:~# ls -l pibox.img
-rw-r--r-- 1 root root 1970255872 Oct 13 21:53 pibox.img
Ponemos SD_CARD_B en el lector de tarjetas de nuestra computadora portátil. Las particiones de SD_CARD_B se montan automáticamente en nuestro sistema como /dev/sdc1
y /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
Arriba puede ver que SD_CARD_B tiene una capacidad de 2GB.
Desmontamos esas particiones de nuestro sistema para operar con éxito en SD_CARD_B.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Clonamos el archivo pibox.img en 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
Verifique el tamaño de los bytes copiados, es igual al valor que obtuvimos por ls -l pibox.img
comando.
Después de sacar SD_CARD_B de nuestra computadora portátil y ponerlo en la placa PIBOX, arrancamos el sistema e iniciamos sesión en la consola PIBOX.
Enumeramos las particiones (algunas otras particiones innecesarias del sistema no se muestran aquí).
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
ni siquiera -o loop=whatever
. Según la otra publicación que acabo de usar mount -o offset=123 /imagefilepath /mntpoint
y el uso de loopback es implícito. Supongo que eso es generalmente cierto en Linux ahora, intente y vea. Luego, podría reducir eso a solo decir que las particiones se montan a través de un "dispositivo de bucle invertido" virtual.
Cuando lo usó dd if=/dev/sdx of=/path/to/image bs=1M
, se /dev/sdx
refiere a todo el "disco", por lo que la imagen siempre tendrá el tamaño de toda la tarjeta.
En su lugar, necesitaría usar dd if=/dev/sdxn ...
dónde n
está el número de partición.
Probablemente necesite hacer esto dos veces: una para la /boot
partición y otra para la /
partición.
Luego, necesitaría crear particiones en la nueva tarjeta que sean al menos tan grandes como esas dos originales, para volver al contenido.
Use algo como parted (editor de particiones) para reducir la partición primaria a un tamaño más pequeño y luego use una herramienta como Clonezilla para copiar desde la partición ahora más pequeña a su nueva tarjeta. Sin embargo, es probable que tengas que hacer esto en otra computadora.
Cree una imagen de la tarjeta utilizando uno de los métodos ya mencionados: ¿Cómo hago una copia de seguridad de mi Raspberry Pi?
Use el script en http://sirlagz.net/2013/03/10/script-automatic-rpi-image-downsizer/ para reducir el tamaño de la imagen
Restaura la imagen reducida en una nueva tarjeta más pequeña
script.sh
. Haga que el archivo sea ejecutable chmod
y ejecútelo.
He estado usando rsync
para copiar sistemas de archivos de un disco a otro durante un tiempo, sin problemas. La ventaja de usar rsync es que está copiando el contenido del sistema de archivos, en lugar de hacer una copia a nivel de bloque del dispositivo; Como resultado, realmente no le importa el tamaño de las unidades de destino y de origen, siempre que la unidad de destino tenga suficiente espacio para almacenar los datos.
Así que así es como lo haría:
rsync -avx oldFilesystem newFilesystem
para copiar / sobrescribir el sistema de archivos en la nueva tarjeta con el sistema de archivos de la tarjeta anterior.rpi-update
para asegurarse de que su firmware sea consistente y esté actualizado.Después de esto, su nueva tarjeta debería tener un sistema Raspbian perfectamente funcional instalado.
Creé un script de shell para hacer una copia de seguridad y restaurar todos los datos en una tarjeta SD. Primero elimina algunos datos (correspondientes a mi proyecto) y reduce la partición al tamaño mínimo para que la imagen sea tan grande como los datos de la tarjeta SD. Además, el script crea un archivo * .zip de la imagen. Después de restaurar la imagen creada en otra tarjeta SD, la partición se ampliará al tamaño máximo. El script usa los comandos que se mencionan en las otras respuestas. Como este es mi primer script de shell con este tamaño, me llevó horas crearlo y no es el jet perfecto. Especialmente no sé cómo manejar los valores de retorno de resize2fs y fdisk, por lo que el usuario tiene que escribir los valores que necesito. ¿Hay alguna idea para arreglar eso? Espero que este script ayude a alguien más. Siéntase libre de editarlo y mejorarlo.
"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
aquí está:
#!/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 solución más fácil que encontré fue hacer una copia de seguridad de la tarjeta más grande original usando los comandos dd descritos anteriormente y luego restaurar la imagen a la tarjeta más pequeña usando algo como piwriter. dd puede funcionar tan bien ... no estoy seguro. PiWriter devolvió un error ya que se quedó sin espacio, pero dado que la imagen no contenía datos reales más allá del tamaño de la tarjeta más pequeña, solo estaba truncando sectores vacíos. No estoy seguro de cuáles son las implicaciones de esto ... la partición puede necesitar revisión o reparación, pero puedo verificar que funcionó cuando la puse en el Pi.
Utilizo una versión anterior de win32diskimager-RELEASE-0.1-r15-win32
para leer la imagen, crea una imagen de 4GB incluso desde una tarjeta SD de 8GB y luego escribe la imagen con la última versión de win32diskimager.
Uso la versión anterior porque la anterior omitirá todos los errores.