前序
之前复制或者备份树莓派的SD卡,都是用dd
命令全盘复制,可以用,但是这样有两大缺点:
- 慢
- 一个大的SD卡,比如
64G
,即使只用了2G
,经过dd
命令生成的img文件
也会生成一个和整个SD卡容量一样大小的文件,即64G。
于是,需要有一个可以解决上述问题的制作树莓派SD卡img映像
文件的方法。
在网上搜索了一些,做了些研究,发现还是有办法的。 如下列网址所述:(感谢作者)
http://www.cnblogs.com/haochuang/p/6066532.html
准备
- 准备一个
树莓派Raspberry Pi
和另外的Raspbian系统
,并启动,用来作为备份操作的环境。要保证这个系统所在的SD卡的空间够大(我用了64G的卡,虽然没有必要这么大),足够用来保存img
备份文件。
ps:用PC上的其他Linux
系统也可以,比如Debian 9.3
。 而且用PC
会快一些。
- 准备好要备份的SD卡,和USB读卡器。
- 将插好源SD卡的读卡器插入树莓派(或PC)。
- 首先安装必需的工具软件:
1
pi@raspberrypi:~ $ sudo apt-get install dosfstools dump parted kpartx
- 建立工作目录
1
2
3pi@raspberrypi:~ $ mkdir ~/backupimg
pi@raspberrypi:~ $ cd ~/backupimg
pi@raspberrypi:~/backupimg $
生成空白img文件
确定设备
插入装有源SD卡的读卡器到USB口后,确定源SD卡对应的设备名
1 | pi@raspberrypi:~/backupimg $ ls /dev/sd* |
如上所示/dev/sda
为源SD卡,/dev/sda1
为/boot
,/dev/sda2
为/
(根)。
不同的系统会有所不同,可能会是sdb…
或其他,例如:
1 | yang@debian:~/backupimg$ ls /dev/sd* |
挂载源SD卡
- 新建目录挂载
1
2
3pi@raspberrypi:~/backupimg $ mkdir src_boot src_Root
pi@raspberrypi:~/backupimg $ sudo mount -t vfat -o uid=pi,gid=pi,umask=0000 /dev/sda1 ./src_boot/
pi@raspberrypi:~/backupimg $ sudo mount -t ext4 /dev/sda2 ./src_Root/
请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,例如PC上的Debian,请注意uid和gid的设置,上述第2,3条命令可能会是:
1 | yang@debian:~/backupimg$ sudo mount -t vfat -o uid=yang,gid=yang,umask=0000 /dev/sdb1 ./src_boot/ |
- 查看源SD卡已用空间大小如上可以看出/dev/sda已用空间大约4G
1
2
3
4
5
6
7
8
9
10
11
12pi@raspberrypi:~/backupimg $ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 59G 6.1G 51G 11% /
devtmpfs 460M 0 460M 0% /dev
tmpfs 464M 0 464M 0% /dev/shm
tmpfs 464M 13M 452M 3% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 464M 0 464M 0% /sys/fs/cgroup
/dev/mmcblk0p1 42M 21M 21M 51% /boot
tmpfs 93M 0 93M 0% /run/user/1000
/dev/sda1 56M 21M 36M 37% /home/pi/backupimg/src_boot
/dev/sda2 15G 4.0G 9.9G 29% /home/pi/backupimg/src_Root
创建空img文件
- 创建空白img文件
因为源SD卡已用空间大约4G,那么建立一个4600M的空白img文件应该够了。(安全起见,设定5000会更好)1
2
3
4pi@raspberrypi:~/backupimg $ sudo dd if=/dev/zero of=raspberrypi.img bs=1M count=4600
4600+0 records in
4600+0 records out
4823449600 bytes (4.8 GB, 4.5 GiB) copied, 283.248 s, 17.0 MB/s
特别注意这里 bs=1M,千万不要写成1MB。1M是10241024 Bytes, 而1MB是10001000 Bytes,会造成img文件的大小不是512 bytes的整数倍,后面会报错。
这个过程大约几分钟完成。 如果比较着急,可以另开一个终端,运行如下命令,可以观察到img文件大小的变化。
1 | pi@raspberrypi:~ $ watch -d -n 5 ls -lh ~/backupimg |
- 完成后,确认一下img文件已经生成,且文件大小正确
1
2pi@raspberrypi:~/backupimg $ ls -l raspberrypi.img
-rw-r--r-- 1 root root 4823449600 Dec 15 22:00 raspberrypi.img
查看分区信息(只关注sda项中的Start与End)
1 | pi@raspberrypi:~/backupimg $ sudo fdisk -l |
给img文件分区
1 | pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img --script -- mklabel msdos |
分区的起始扇区数都是 8192 的倍数,以保证4k对齐
检查分区是否成功
1 | pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img |
在parted程序中,输入print free命令可以显示分区内容,输入quit退出
挂载img文件到系统
img文件对应的Loop device的设置
1 | pi@raspberrypi:~/backupimg $ sudo losetup -f --show raspberrypi.img |
下面的命令中相应输入/dev/loop0,如果不是 loop0 请做相应调整(以及以后的各个步骤里的loop0都要改变)
1 | pi@raspberrypi:~/backupimg $ sudo kpartx -va /dev/loop0 |
此时loop device就设置好了,loop0p1对应的是img文件分区上的 /boot,loop0p2对应的是 /(根)
给img文件中的两个分区格式化
1 | pi@raspberrypi:~/backupimg $ sudo mkfs.vfat -n boot /dev/mapper/loop0p1 |
挂载目标img文件loop device
1 | pi@raspberrypi:~/backupimg $ mkdir tgt_boot tgt_Root |
请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2,3条命令可能会是:
1 | yang@debian:~/backupimg$ sudo mount -t vfat -o uid=yang,gid=yang,umask=0000 /dev/mapper/loop0p1 ./tgt_boot/ |
备份/boot
首先备份/boot,直接拷贝即可
1 | pi@raspberrypi:~/backupimg $ sudo cp -rfp ./src_boot/* ./tgt_boot/ |
备份“/”
备份根文件系统稍微复杂些,可以用两种方法
方法一、dump/restore方法
首先对目标挂载点设置合适的权限,并清空
1 | pi@raspberrypi:~/backupimg $ sudo chmod 777 tgt_Root |
请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2条命令可能会是:
1 | yang@debian:~/backupimg$ sudo chown yang.yang tgt_Root |
然后开始备份
1 | pi@raspberrypi:~/backupimg/tgt_Root $ sudo dump -0uaf - ../src_Root/ | sudo restore -rf - |
整个dump/restore过程需要几分钟时间,看到 DUMP IS DONE 就说明备份成功了
然后返回上层目录
1 | pi@raspberrypi:~/backupimg/tgt_Root $ cd .. |
方法二、tar方法
如果上述方法一的 sudo dump … 那一步出现 Broken pipe、 Illegal instruction等错误而失败的话,可以使用方法二。
这个方法会使用tar把源SD卡的根文件系统打包,所以在本机系统空间里需要额外的和源SD卡的根文件系统已用空间大小一样的可用空间。
首先,和方法一里面一样,对目标挂载点设置合适的权限,并清空
1 | pi@raspberrypi:~/backupimg $ sudo chmod 777 tgt_Root |
请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2条命令可能会是:
1 | yang@debian:~/backupimg$ sudo chown yang.yang tgt_Root |
然后用tar把源SD卡的根文件系统打包
1 | pi@raspberrypi:~/backupimg $ cd src_Root/ |
tar的过程中可能会出现一些 socket ignored 错误,可以忽略。
此过程可能需要比较长的时间,可另外开一个终端,运行如下命令,用来观察backup.tar文件大小的变化。
1 | pi@raspberrypi:~ $ watch -d -n 5 ls -lh ~/backupimg |
上述打包过程结束后,接着将tar包解开到目标img文件的根文件系统
1 | pi@raspberrypi:~/backupimg $ cd ../tgt_Root/ |
此过程可能需要比较长的时间,可另外开一个终端,运行如下命令,用来观察目标img文件的根文件系统的已用空间大小变化
1 | pi@raspberrypi:~ $ watch -d -n 5 df -h```sh |
解包过程结束后,回到上层目录,并删除backup.tar文件
1 | pi@raspberrypi:~/backupimg/tgt_Root $ cd .. |
相应修改PARTUUID设定
这时候整个备份就已经完成了。不过此时的img文件即使写入到空白SD卡里面也是无法启动的,因为Raspbian启动要对应分区的PARTUUID,所以我们还要修改目标img文件里的如下两个文件:
1 | ./tgt_boot/cmdline.txt |
首先查看img文件对应的loop device的两个分区的PARTUUID
1
2
3
4
5
6
7
8
9pi@raspberrypi:~/backupimg $ sudo blkid
/dev/mmcblk0p1: LABEL="boot" UUID="E5B7-FEA1" TYPE="vfat" PARTUUID="ddffe93a-01"
/dev/mmcblk0p2: UUID="b4ea8e46-fe87-4ddd-9e94-506c37005ac5" TYPE="ext4" PARTUUID="ddffe93a-02"
/dev/sda2: UUID="9a7608bd-5bff-4dfc-ac1d-63a956744162" TYPE="ext4" PARTUUID="ec04fe79-02"
/dev/loop0: PTUUID="af2f8761" PTTYPE="dos"
/dev/mmcblk0: PTUUID="ddffe93a" PTTYPE="dos"
/dev/sda1: LABEL="boot" UUID="B60A-B262" TYPE="vfat" PARTUUID="ec04fe79-01"
/dev/mapper/loop0p1: SEC_TYPE="msdos" LABEL="boot" UUID="755C-C29C" TYPE="vfat" PARTUUID="af2f8761-01"
/dev/mapper/loop0p2: UUID="a174c97e-049f-4fbd-abb7-0b9098dae24a" TYPE="ext4" PARTUUID="af2f8761-02"这里可以看到/boot对应的是af2f8761-01 , / 对应的是af2f8761-02
修改 cmdline.txt 文件
1
2
3pi@raspberrypi:~/backupimg $ sudo vi ./tgt_boot/cmdline.txt
pi@raspberrypi:~/backupimg $ cat ./tgt_boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=af2f8761-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait修改 fstab 文件
1
2
3
4
5
6
7pi@raspberrypi:~/backupimg $ sudo vi ./tgt_Root/etc/fstab
pi@raspberrypi:~/backupimg $ cat ./tgt_Root/etc/fstab
proc /proc proc defaults 0 0
PARTUUID=af2f8761-01 /boot vfat defaults 0 2
PARTUUID=af2f8761-02 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that卸载各个挂载的分区
1
pi@raspberrypi:~/backupimg $ sudo umount src_boot src_Root tgt_boot tgt_Root
删除loop device
1
2pi@raspberrypi:~/backupimg $ sudo kpartx -d /dev/loop0
pi@raspberrypi:~/backupimg $ sudo losetup -d /dev/loop0删除挂载点目录
1
pi@raspberrypi:~/backupimg $ rmdir src_boot src_Root tgt_boot tgt_Root
最后剩下img文件
1
2
3pi@raspberrypi:~/backupimg $ ls -l
total 4469676
-rw-r--r-- 1 root root 4823449600 Dec 15 23:10 raspberrypi.img
大功告成
完成之后可以用dd或者Etcher烧写img文件到其他SD卡中,注意烧写到新卡中在树莓派中运行后,要先用raspi-config先把分区空间expand一下,否则可用空间会很小。
拷贝(移动)镜像
挂载windows共享磁盘
1 | sudo mount -t cifs -o username="Hello World",password="HQ" //192.168.31.141/Raspberry /home/pi/share |
将刚制作的镜像复制到windows上
1 | sudo cp ./backupimg/RPi_OpenCV.img ./share |