0x00 前言

一般常见简单的备份方式是是使用Win32DiskImager备份,但是有几个缺点:

  1. 整卡备份,Win32DiskImager会将SD卡内的所有区块都会备份下来,就类似Linux的dd命令。一个SD卡是16G但里面的数据只有100M,那么备份下来的文件就是16G,生成的备份文件大小就是SD的大小,这无疑浪费了空间
  2. 备份时间长,前面提到Win32DiskImager会将SD卡的所有块都备份下来,因此备份时间也就长了。
  3. 恢复时卡的容量必须要和备份文件大小一致或更大,这样就会造成一个问题,原本一张16G的卡内只有100M的有效数据,现在如果想将数据恢复到一张8G的卡,那么通过这种备份的方式是行不通的。

最后通过查找找到了一个更好方法,就是通过dump备份,恢复时也只恢复有效数据,因此只要恢复的SD卡比有效数据大就行了。

0x01 需要的软件

  • dump 备份工具,用于备份系统
  • dosfstools fat32格式化工具,引导文件分区是fat32格式的
  • parted 分区调整工具
  • kpartx 虚拟文件系统工具

安装:

apt install dump -y &&
apt install dosfstools -y &&
apt install parted -y &&
apt install kpartx -y

0x02 创建img文件

img是用于存储系统的镜像文件

首先使用df -h查看实际空间大小,再生成文件,比如:

Filesystem      Size  Used Avail Use% Mounted on
/dev/root        15G  8.9G  5.0G  65% /
/dev/mmcblk0p1  252M   72M  180M  29% /boot

从上可以看出实际使用空间8.9G+252M的boot空间

需要注意这里显示的空间单位是G,这里的G是将大小舍入到接近GiB($2^{30}$字节),而不是GB($10^{9}$字节)。

GBGiB是两个有严格区别的单位,GB是方便10进制计算,GiB是方便2进制计算。

(插个题外话,Windows中默认的大小单位显示的是KBMBGB实际上计算的是KiBMiBGiB

因此需要生成的img需要大于等于8.9G+252M

dd if=/dev/zero of=raspi.img bs=1M count=9570

if是输入路径,这里选择使用0填充

of是输出路径,就是创建img文件的路径

bs是块大小,这里选择M,也就是MiB,这样生成的文件是512bytes的整数倍,为了与分区表对上

count是块数,bs*count=真实大小

因为要生成的img文件需要大于等于8.9G`+252M,而这里的8.9G是进行了大小舍入所以不精确,所以为了容纳误差而选择生成9.1G大小的系统。

因为bsM,所以count为:$(9.1\times2^{30}\div2^{20})+252\approx9570$

0x03 img镜像分区

分区前通过fdisk -l查看树莓派分区

Device         Boot  Start      End  Sectors  Size Id Type
/dev/mmcblk0p1 *      8192   524287   516096  252M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      524288 31223807 30699520 14.7G 83 Linux

可以看到SD卡有两个分区,其中关键信息为:

  1. /dev/mmcblk0p1是引导分区(boot),分区类型是fat32,从8192柱面开始,到524287柱面结束。
  2. /dev/mmcblk0p2是系统分区,分区从524288柱面开始。

接下来使用parted将刚生成的img文件进行分区

parted raspi.img -s  -- mklabel msdos   # 创建msdos分区表
parted raspi.img -s  -- mkpart primary fat32 8192s 524287s  # fat32分区从8192开始,到524287结束
parted raspi.img -s  -- mkpart primary ext4 524288s -1  # 系统分区一般都是ext4类型,从524288开始,到最后

0x04 挂载img并格式化

将img挂载为虚拟设备,并获取虚拟设备地址

loopdevice=`losetup -f --show raspi.img`

使用kpartx挂载为虚拟文件系统

device=`kpartx -va $loopdevice | sed '1!d' | sed -E 's/.*(loop[0-9])p.*/\1/g'`

地址拼接

device="/dev/mapper/${device}"
imgBoot="${device}p1"
imgRoot="${device}p2"

格式化

mkfs.vfat $imgBoot
mkfs.ext4 $imgRoot

0x05 备份

创建两个临时挂载目录,并挂载

mkdir tmpBoot tmpRoot
mount -t vfat $imgBoot tmpBoot
mount -t ext4 $imgRoot tmpRoot

备份Boot

cp -rfp /boot/* tmpBoot

备份系统

cd tmpRoot
dump -0uaf - / | restore -rf -
cd -

0x06 修改启动文件

因为树莓派启动需要对应分区的PARTUUID,所以需要修改cmdline.txtfstab文件

首先使用blkid命令查看分区PARTUUID

blkid -o export $imgBoot
blkid -o export $imgRoot

分别输出

DEVNAME=/dev/mapper/loop0p1
SEC_TYPE=msdos
UUID=161A-ED14
TYPE=vfat
PARTUUID=e74ab5ad-01

DEVNAME=/dev/mapper/loop0p2
UUID=20aa2e77-a211-4d43-996d-324f015e597c
TYPE=ext4
PARTUUID=e74ab5ad-02

可以看到PARTUUID分别为e74ab5ad-01(对应boot分区)和e74ab5ad-02(对应系统分区)。

将获取到的PARTUUID分别替换掉cmdline.txtfstab文件中的PARTUUID

路径:

tmpBoot/cmdline.txt   # cmdline.txt
tmpRoot/etc/fstab     # fstab

0x07 END

卸载分区

cd ~
umount tmpBoot/ tmpRoot/
rm -rf tmpBoot/ tmpRoot/

卸载虚拟设备

kpartx -d $loopdevice
losetup -d $loopdevice

至此系统备份就做好了,制作的img文件可以使用Win32DiskImagerdd刷入其他的SD卡了

Last modification:January 9, 2022
如果觉得我的文章对你有用,请随意赞赏