Чи можливо скопіювати існуючу та налаштовану установку Raspbian на меншу SD-карту?
Коли я вперше встановив Raspbian, у мене було під рукою лише 32 Гб картки, що очевидно більше, ніж потрібно.
Чи можливо скопіювати існуючу та налаштовану установку Raspbian на меншу SD-карту?
Коли я вперше встановив Raspbian, у мене було під рукою лише 32 Гб картки, що очевидно більше, ніж потрібно.
Відповіді:
У цій відповіді я демонструю, що робити поетапно, щоб люди зрозуміли логіку рішення і мати можливість застосувати кроки до своїх інших проблем.
Але, по-перше, слід зазначити, що проблема міграції файлових систем із SD-картки на меншу (але достатньо велику для передачі даних) SD-карту є загальною (не специфічною для Raspi).
Ноутбук з мікросхемою зчитування SD-карт та Linux (я вважаю за краще Ubuntu), що працює на ньому.
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
Поки PIBOX працює, ми перераховуємо розділи (непотрібні системні розділи тут не відображаються).
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
На SD_CARD_A є 2 розділи як /
і /boot
. Навіть 2 Гб загалом не використовується.
Після того як ми відключили та зупинили PIBOX, ми виймаємо SD_CARD_A з плати PIBOX і поміщаємо її в кард-рідер нашого ноутбука.
Розділи SD_CARD_A автоматично монтуються до нашої системи як /dev/sdc1
і /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
Ми демонтуємо ці розділи з нашої системи, щоб успішно працювати над ними.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Ми відображаємо інформацію про пристрій SD_CARD_A детально для підтвердження в наступних кроках.
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
Вище видно, що SD_CARD_A є ємністю 8 Гб.
Ми клонуємо SD_CARD_A у файл 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
Перевірте розмір скопійованих байтів, він дорівнює значенню, яке ми отримали за fdisk -l /dev/sdc
командою.
У Linux є модуль під назвою loopback, який дає нам можливість обробляти файл як блок-пристрій.
Завантажуємо петльовий модуль.
root@mylaptop:~# modprobe loop
Ми знаходимо невикористаний шлях пристрою циклу.
root@mylaptop:~# losetup -f /dev/loop0
Тепер ми створюємо пристрій циклу для файлу pibox.img.
root@mylaptop:~# losetup /dev/loop0 pibox.img
Ми запускаємо ядро про зміни розділу.
root@mylaptop:~# partprobe /dev/loop0
Ми підтверджуємо, що попередні операції були успішними.
root@mylaptop:~# losetup /dev/loop0
/dev/loop0: [0806]:69 (/root/pibox.img)
Ми відображаємо інформацію про пристрій петлі детально, щоб порівняти його з 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
Вище видно, що розмір пристрою петлевого звороту (= 7969177600 байт) та розділи збігаються з SD_CARD_A.
Відтепер ми будемо зосереджені на розділі /dev/loop0p2
. Давайте назвемо його THE_PARTITION .
Розмір блоку - 512 байт (як надруковано у рядку, починаючи з одиниць = сектори .....)
THE_PARTITION починається з блоку 137216 і закінчується на блоці 15564799, що означає, що він має розмір 15427584 blocks
(= 15564799 - 137216 + 1).
Отже, розмір THE_PARTITION у байтах становить 7898923008 bytes
(= 512 * 15427584).
Щоб розмістити THE_PARTITION у SD_CARD_B, ми хочемо, щоб він мав новий розмір 3710940 blocks
або іншими словами 1900001280 bytes
(= 512 * 3710940).
Отже, нове число кінцевого блоку 3848155
обчислюється start block number
(= 137216) + size in blocks
(= 3710940) - 1
.
Є 2 операції, які не повинні помилятися один з одним.
3710940 blocks
.3848155
.Перш ніж скоротити файлову систему, її слід позначити як чисту 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
Ми скорочуємо файлову систему 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.
Ми дізнаємося, що означає номер 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
Ми скорочуємо THE_PARTITION за допомогою 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
Ми робимо за допомогою петлевого пристрою. Ми від'єднуємо його.
root@mylaptop:~# losetup -d /dev/loop0
Ми перевіряємо нову таблицю розділів.
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
На виході чітко видно, що кількість кінцевих блоків THE_PARTITION зменшено from 15564799 to 3848155
.
Останній блок, який ми використовуємо, - це 3848155
. Нумерація блоків починається з 0. Отже, у нас є 3848155 + 1 блоків, і новий розмір файлу pibox.img повинен бути 1970255872 bytes
(= (3848155 + 1) * 512).
Ми усікаємо файл pibox.img.
root@mylaptop:~# truncate --size=1970255872 pibox.img
Ми перевіряємо новий розмір файлу pibox.img.
root@mylaptop:~# ls -l pibox.img
-rw-r--r-- 1 root root 1970255872 Oct 13 21:53 pibox.img
Ми поміщаємо SD_CARD_B у зчитувач карт на нашому ноутбуці. Розділи SD_CARD_B автоматично монтуються до нашої системи як /dev/sdc1
і /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
Вище видно, що SD_CARD_B є ємністю 2 Гб.
Ми демонтуємо ці розділи з нашої системи для успішної роботи на SD_CARD_B.
root@mylaptop:~# umount /dev/sdc1
root@mylaptop:~# umount /dev/sdc2
Ми клонуємо файл pibox.img в 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
Перевірте розмір скопійованих байтів, він дорівнює значенню, яке ми отримали за ls -l pibox.img
командою.
Після того, як ми виймаємо SD_CARD_B зі свого ноутбука і поміщаємо його на плату PIBOX, ми завантажуємо систему та входимо в консоль PIBOX.
Ми перелічуємо розділи (деякі інші непотрібні системні розділи тут не відображаються).
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 loop=whatever
. Відповідно до іншої публікації, яку я просто використовую, mount -o offset=123 /imagefilepath /mntpoint
і використання циклічного зворотного зв’язку неявне. Я припускаю, що це взагалі вірно в Linux - спробуйте і подивіться. Потім ви можете звести це до просто кажучи, що розділи монтуються через віртуальний "пристрій для зворотного зв'язку".
Коли ви використовували dd if=/dev/sdx of=/path/to/image bs=1M
, /dev/sdx
посилаєтесь на весь "диск", тож зображення завжди було б розміром всієї карти.
Замість цього, ви повинні використовувати , dd if=/dev/sdxn ...
де n
це номер розділу.
Вам, ймовірно, потрібно буде зробити це двічі - один раз для /boot
розділу та один раз для /
розділу.
Тоді вам потрібно буде створити на новій карті розділи, принаймні такі ж великі, як ці дві оригінальні, щоб додати вміст назад до.
Використовуйте щось на зразок розірваного (редактор розділів), щоб зменшити основний розділ на менший розмір, а потім скористайтеся інструментом, як Clonezilla, щоб скопіювати з теперішнього меншого розділу на нову карту. Це, мабуть, доведеться робити на іншому комп'ютері.
dd if=/dev/sdx of=/path/to/image bs=1M
з цієї нитки: raspberrypi.stackexchange.com/questions/311 / ...
Створіть зображення картки за допомогою одного з уже згаданих методів - Як зробити резервну копію свого Raspberry Pi?
Використовуйте сценарій на веб-сторінці http://sirlagz.net/2013/03/10/script-automatic-rpi-image-downsizer/, щоб зменшити розмір зображення
Відновлення зменшеного зображення на новій меншій карті
script.sh
, зробіть файл виконуваним за допомогою chmod
та виконайте його.
Я вже rsync
деякий час використовую для копіювання файлових систем з одного диска на інший, без жодної хіки. Перевага використання rsync полягає в тому, що це копіювання вмісту файлової системи, а не копіювання пристрою на рівні блоку; в результаті цього насправді не важливо, якого розміру мають цільові та вихідні накопичувачі, якщо цільовий диск має достатньо місця для зберігання даних.
Отже ось як я це зробив:
rsync -avx oldFilesystem newFilesystem
для копіювання / перезаписування файлової системи на новій картці файлову систему зі старої карти.rpi-update
щоб переконатися, що ваша мікропрограмна версія є послідовною та оновленою.Після цього у вашій новій картці має бути встановлена ідеально функціональна система Raspbian.
Я створив сценарій оболонки для резервного копіювання та відновлення всіх даних на SD-карті. Спочатку він видаляє деякі дані (відповідають моєму проекту) і скорочує розділ до мінімального розміру, щоб зображення було таким же великим, як дані на SD-картці. Як додаток, сценарій створює * .zip файл зображення. Після відновлення створеного зображення на іншій SD-картці розділ буде збільшено до максимального розміру. Сценарій використовує команди, які згадуються в інших відповідях. Оскільки це мій сценарій кулакової оболонки такого розміру, на його створення знадобилися години, і це не ідеальний струмінь. Тим більше я не знаю, як обробити значення повернення resize2fs та fdisk, тому користувачеві доводиться вводити мені потрібні значення. Чи є якісь ідеї, щоб це виправити? Я сподіваюся, що цей сценарій допомагає комусь іншому. Не соромтесь редагувати та вдосконалювати.
"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
ось:
#!/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
Найпростішим рішенням, який я знайшов, було зробити резервну копію оригінальної великої карти за допомогою команд DD, зазначених вище, а потім відновити зображення на меншій карті, використовуючи щось на кшталт piwriter. ДД може також працювати ... не впевнений. PiWriter повернув помилку, оскільки не вистачало місця, але оскільки зображення не містило фактичних даних, що перевищують розмір меншої карти, воно просто обрізало порожні сектори. Я не впевнений, що це означає для цього ... розділ може потребувати перевірки чи ремонту, але я можу переконатися, що він працював, коли я вклав його в Pi.
Я використовую стару версію програми win32diskimager-RELEASE-0.1-r15-win32
для читання зображення, вона створює зображення 4 Гб навіть з 8 Гб SD-карти, а потім записує зображення з останньою версією win32diskimager.
Я використовую старішу версію, оскільки стара буде пропускати кожну помилку.