Loading... # 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` 虚拟文件系统工具 安装: ```sh apt install dump -y && apt install dosfstools -y && apt install parted -y && apt install kpartx -y ``` # 0x02 创建img文件 img是用于存储系统的镜像文件 首先使用`df -h`查看实际空间大小,再生成文件,比如: ```sh 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` ```sh 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`查看树莓派分区 ```sh 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文件进行分区 ```sh 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挂载为虚拟设备,并获取虚拟设备地址 ```sh loopdevice=`losetup -f --show raspi.img` ``` 使用`kpartx`挂载为虚拟文件系统 ```sh device=`kpartx -va $loopdevice | sed '1!d' | sed -E 's/.*(loop[0-9])p.*/\1/g'` ``` 地址拼接 ```sh device="/dev/mapper/${device}" imgBoot="${device}p1" imgRoot="${device}p2" ``` 格式化 ```sh mkfs.vfat $imgBoot mkfs.ext4 $imgRoot ``` # 0x05 备份 创建两个临时挂载目录,并挂载 ```sh mkdir tmpBoot tmpRoot mount -t vfat $imgBoot tmpBoot mount -t ext4 $imgRoot tmpRoot ``` 备份`Boot` ```sh cp -rfp /boot/* tmpBoot ``` 备份系统 ```sh cd tmpRoot dump -0uaf - / | restore -rf - cd - ``` # 0x06 修改启动文件 因为树莓派启动需要对应分区的`PARTUUID`,所以需要修改`cmdline.txt`和`fstab`文件 首先使用`blkid`命令查看分区`PARTUUID` ```sh blkid -o export $imgBoot blkid -o export $imgRoot ``` 分别输出 ```sh 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` 路径: ```sh tmpBoot/cmdline.txt # cmdline.txt tmpRoot/etc/fstab # fstab ``` # 0x07 END 卸载分区 ```sh cd ~ umount tmpBoot/ tmpRoot/ rm -rf tmpBoot/ tmpRoot/ ``` 卸载虚拟设备 ```sh kpartx -d $loopdevice losetup -d $loopdevice ``` 至此系统备份就做好了,制作的img文件可以使用`Win32DiskImager`或`dd`刷入其他的SD卡了 Last modification:January 9, 2022 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 0 如果觉得我的文章对你有用,请随意赞赏