0x00 前言
一般常见简单的备份方式是是使用Win32DiskImager备份,但是有几个缺点:
- 整卡备份,Win32DiskImager会将SD卡内的所有区块都会备份下来,就类似Linux的
dd
命令。一个SD卡是16G但里面的数据只有100M,那么备份下来的文件就是16G,生成的备份文件大小就是SD的大小,这无疑浪费了空间 - 备份时间长,前面提到Win32DiskImager会将SD卡的所有块都备份下来,因此备份时间也就长了。
- 恢复时卡的容量必须要和备份文件大小一致或更大,这样就会造成一个问题,原本一张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}$字节)。
GB
和GiB
是两个有严格区别的单位,GB
是方便10进制计算,GiB
是方便2进制计算。
(插个题外话,Windows中默认的大小单位显示的是KB
、MB
、GB
实际上计算的是KiB
、MiB
、GiB
)
因此需要生成的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
大小的系统。
因为bs
是M
,所以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卡有两个分区,其中关键信息为:
/dev/mmcblk0p1
是引导分区(boot),分区类型是fat32
,从8192
柱面开始,到524287
柱面结束。/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.txt
和fstab
文件
首先使用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.txt
和fstab
文件中的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文件可以使用Win32DiskImager
或dd
刷入其他的SD卡了