前言
本文主要介绍以最小的方式完整备份树莓派SD卡镜像的方法。
准备工作
在树莓派的终端里运行下面这条命令,安装必备工具:
1
| $ sudo aptitude install dosfstools dump parted kpartx screen exfat-fuse fuse-utils ntfs-3g
|
说明:
dosfstools
:FAT32分区格式化工具。
dump
:dump 和 restore 备份工具。
screen
:ssh远程会话管理工具。
parted
,kpartx
:虚拟磁盘工具。
exfat-fuse
:挂载exFAT格式优盘工具。
fuse-utils
,ntfs-3g
:挂载NTFS格式优盘工具。
优盘编号
备份需要一个能够装下整个树莓派镜像的优盘或移动硬盘,在终端中运行 sudo fdisk -l
,确认已经插上的优盘或移动硬盘编号为 /dev/sda1
。若不是则记下具体编号,待会修改脚本中内容。
脚本配置
备份镜像文件名,修改 raspberrypi.img
即可:
1
| IMG_PATH="${USB_PATH}/raspberrypi.img"
|
挂载优盘,修改 /dev/sda1
为具体的编号:
1
| sudo mount -o uid=pi,gid=pi /dev/sda1 ${USB_PATH}
|
生成镜像文件大小,默认4G=4096×1048576字节(b)。想要生成?G,只需要修改count的值即可,count=?×1024×1024×1024÷4096:
1
| sudo dd if=/dev/zero of=${IMG_PATH} bs=4096 count=1048576
|
boot分区卷标:
1
| sudo dosfslabel ${bootPath} "rpi-boot"
|
系统分区卷标:
1
| sudo e2label ${rootPath} "rpi-sys"
|
备份脚本
将以下内容保存为 backup.sh
文件,并赋予执行权限 sudo chmod +x backup.sh
。在终端中输入 screen -S backup
创建backup会话,找到 backup.sh
文件所在位置执行 ./backup.sh
开始备份树莓派的SD卡全部内容,备份后的镜像文件 raspberrypi.img
保存在优盘或移动硬盘的根目录下。最后使用快捷键Ctrl+a+d(即按住Ctrl,依次再按a,d)离开backup会话。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #!/bin/sh
USB_PATH="/mnt/usb" IMG_PATH="${USB_PATH}/raspberrypi.img" TMP_BOOT="/mnt/tmp_boot" TMP_ROOT="/mnt/tmp_root"
if [ ! -d ${USB_PATH} ]; then sudo mkdir ${USB_PATH} fi
sudo mount -o uid=pi,gid=pi /dev/sda1 ${USB_PATH}
if [ -f ${IMG_PATH} ]; then sudo rm -f ${IMG_PATH} fi
sudo dd if=/dev/zero of=${IMG_PATH} bs=4096 count=1048576
sudo parted -s ${IMG_PATH} -- mklabel msdos sudo parted -s ${IMG_PATH} -- mkpart primary fat32 8192s 122879s sudo parted -s ${IMG_PATH} -- mkpart primary ext4 122880s -1 sudo parted -s ${IMG_PATH} print
loopDev=`sudo losetup -f --show ${IMG_PATH}` devPath=`sudo kpartx -va ${loopDev} | sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1` devPath="/dev/mapper/${devPath}"
bootPath="${devPath}p1" sudo mkfs.vfat ${bootPath} sudo dosfslabel ${bootPath} "rpi-boot"
rootPath="${devPath}p2" sudo mkfs.ext4 ${rootPath} sudo e2label ${rootPath} "rpi-sys"
if [ ! -d ${TMP_BOOT} ]; then sudo mkdir ${TMP_BOOT} fi
sudo umount ${TMP_BOOT} sudo mount -t vfat ${bootPath} ${TMP_BOOT} sudo cp -rfp /boot/* ${TMP_BOOT}/ sudo umount ${TMP_BOOT}
if [ ! -d ${TMP_ROOT} ]; then sudo mkdir ${TMP_ROOT} fi
sudo umount ${TMP_ROOT} sudo mount -t ext4 ${rootPath} ${TMP_ROOT} cd ${TMP_ROOT} sudo dump -0uaf - / | sudo restore -rf - cd ~ sudo umount ${TMP_ROOT}
sudo kpartx -d ${loopDev} sudo losetup -d ${loopDev}
sudo umount ${USB_PATH}
|
还原镜像
Windows下还原镜像可以使用以下工具: Win32DiskImager,USB Image Tool(推荐),HDDRawCopy(可以进一步压缩img镜像文件)。
新系统运行
还原后的新系统第一次运行记得执行以下命令,然后选择 Expand Filesystem
扩展新SD卡未使用的空间。
脚本说明
镜像文件分区
8192s
和 122879s
是根据官方镜像文件分区得到的数据,也就是第一个boot分区大小。-1
代表直到镜像文件结尾。
1 2 3 4
| sudo parted -s ${IMG_PATH} -- mklabel msdos sudo parted -s ${IMG_PATH} -- mkpart primary fat32 8192s 122879s sudo parted -s ${IMG_PATH} -- mkpart primary ext4 122880s -1 sudo parted -s ${IMG_PATH} print
|
挂载并格式化虚拟磁盘
1 2 3 4 5 6 7 8 9 10 11
| loopDev=`sudo losetup -f --show ${IMG_PATH}` devPath=`sudo kpartx -va ${loopDev} | sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1` devPath="/dev/mapper/${devPath}"
bootPath="${devPath}p1" sudo mkfs.vfat ${bootPath} sudo dosfslabel ${bootPath} "rpi-boot"
rootPath="${devPath}p2" sudo mkfs.ext4 ${rootPath} sudo e2label ${rootPath} "rpi-sys"
|
备份boot分区
1 2 3 4 5 6 7 8
| if [ ! -d ${TMP_BOOT} ]; then sudo mkdir ${TMP_BOOT} fi
sudo umount ${TMP_BOOT} sudo mount -t vfat ${bootPath} ${TMP_BOOT} sudo cp -rfp /boot/* ${TMP_BOOT}/ sudo umount ${TMP_BOOT}
|
备份系统分区
使用 dump
和 restore
工具配合备份系统:
1 2 3 4 5 6 7 8 9 10
| if [ ! -d ${TMP_ROOT} ]; then sudo mkdir ${TMP_ROOT} fi
sudo umount ${TMP_ROOT} sudo mount -t ext4 ${rootPath} ${TMP_ROOT} cd ${TMP_ROOT} sudo dump -0uaf - / | sudo restore -rf - cd ~ sudo umount ${TMP_ROOT}
|
卸载虚拟磁盘
1 2
| sudo kpartx -d ${loopDev} sudo losetup -d ${loopDev}
|
修改镜像文件
明白了以上脚本内容,以后我们想要修改镜像文件里的内容可以使用以下的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #!/bin/sh
USB_PATH="/mnt/usb" IMG_PATH="${USB_PATH}/raspberrypi.img" BOOT_PATH="/mnt/tmp_boot" ROOT_PATH="/mnt/tmp_root"
if [ ! -d ${USB_PATH} ]; then sudo mkdir ${USB_PATH} fi
sudo mount -o uid=pi,gid=pi /dev/sda1 ${USB_PATH}
loopDev=`sudo losetup -f --show ${IMG_PATH}` devPath=`sudo kpartx -va ${loopDev} | sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1` devPath="/dev/mapper/${devPath}"
bootPath="${devPath}p1"
if [ ! -d ${BOOT_PATH} ]; then sudo mkdir ${BOOT_PATH} fi
sudo umount ${BOOT_PATH} sudo mount -t vfat ${bootPath} ${BOOT_PATH}
rootPath="${devPath}p2"
if [ ! -d ${ROOT_PATH} ]; then sudo mkdir ${ROOT_PATH} fi
sudo umount ${ROOT_PATH} sudo mount -t ext4 ${rootPath} ${ROOT_PATH}
echo "bootPath: ${BOOT_PATH}" echo "rootPath: ${ROOT_PATH}"
echo "sudo umount ${BOOT_PATH}" echo "sudo umount ${ROOT_PATH}"
echo "sudo kpartx -d ${loopDev}" echo "sudo losetup -d ${loopDev}"
echo "sudo umount ${USB_PATH}"
|
修改完成之后记得执行最后那几行打印的命令,卸载虚拟磁盘,保存结果。