之前复制或者备份树莓派的SD卡,都是用dd命令全盘复制,可以用,但是这样有两大缺点:
1. 慢
2. 一个大的SD卡,比如64G,即使只用了2G,经过dd命令生成的img文件也会生成一个和整个SD卡容量一样大小的文件,即64G

于是,需要有一个可以解决上述问题的制作树莓派SD卡img映像文件的方法。

在网上搜索了一些,做了些研究,发现还是有办法的。 如下列网址所述:(感谢作者)
http://www.cnblogs.com/haochuang/p/6066532.html

但是里面的脚本我用起来有问题,也懒得研究为什么有问题,于是参照脚本里的方法,手动一步一步命令来。

 

【准备】
准备一个树莓派Raspberry Pi和另外的Raspbian系统,并启动,用来作为备份操作的环境。要保证这个系统所在的SD卡的空间够大(我用了64G的卡,虽然没有必要这么大),足够用来保存img备份文件。

用PC上的其他Linux系统也可以,比如Debian 9.3。 而且用PC会快一些。

准备好要备份的SD卡,和USB读卡器。
将插好源SD卡的读卡器插入树莓派(或PC)。

首先安装必需的工具软件:

[plain] view plain copy
  1. pi@raspberrypi:~ $ sudo apt-get install dosfstools dump parted kpartx  


建立工作目录

[plain] view plain copy
  1. pi@raspberrypi:~ $ mkdir ~/backupimg  
  2. pi@raspberrypi:~ $ cd ~/backupimg  
  3. pi@raspberrypi:~/backupimg $   


【生成空白img文件】
插入装有源SD卡的读卡器到USB口后,确定源SD卡对应的设备名

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ ls /dev/sd*  
  2. /dev/sda  /dev/sda1  /dev/sda2  


如上所示 /dev/sda 为源SD卡, /dev/sda1 为 /boot, /dev/sda2 为 / (根)。

不同的系统会有所不同,可能会是sdb… 或其他,例如:

[plain] view plain copy
  1. yang@debian:~/backupimg$ ls /dev/sd*  
  2. /dev/sda  /dev/sda1  /dev/sda2  /dev/sda5  /dev/sdb  /dev/sdb1  /dev/sdb2  


挂载源SD卡

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ mkdir src_boot src_Root  
  2. pi@raspberrypi:~/backupimg $ sudo mount -t vfat -o uid=pi,gid=pi,umask=0000 /dev/sda1 ./src_boot/  
  3. pi@raspberrypi:~/backupimg $ sudo mount -t ext4 /dev/sda2 ./src_Root/  


请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,例如PC上的Debian,请注意uid和gid的设置,上述第2,3条命令可能会是:

[plain] view plain copy
  1. yang@debian:~/backupimg$ sudo mount -t vfat -o uid=yang,gid=yang,umask=0000 /dev/sdb1 ./src_boot/  
  2. yang@debian:~/backupimg$ sudo mount -t ext4 /dev/sdb2 ./src_Root/  


查看源SD卡已用空间大小

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ df -h  
  2. Filesystem      Size  Used Avail Use% Mounted on  
  3. /dev/root        59G  6.1G   51G  11% /  
  4. devtmpfs        460M     0  460M   0% /dev  
  5. tmpfs           464M     0  464M   0% /dev/shm  
  6. tmpfs           464M   13M  452M   3% /run  
  7. tmpfs           5.0M  4.0K  5.0M   1% /run/lock  
  8. tmpfs           464M     0  464M   0% /sys/fs/cgroup  
  9. /dev/mmcblk0p1   42M   21M   21M  51% /boot  
  10. tmpfs            93M     0   93M   0% /run/user/1000  
  11. /dev/sda1        56M   21M   36M  37% /home/pi/backupimg/src_boot  
  12. /dev/sda2        15G  4.0G  9.9G  29% /home/pi/backupimg/src_Root  


如上可以看出/dev/sda已用空间大约4G

建立一个空白的img文件,因为源SD卡已用空间大约4G,那么建立一个4600M的空白img文件应该够了。(安全起见,设定5000会更好)

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo dd if=/dev/zero of=raspberrypi.img bs=1M count=4600  
  2. 4600+0 records in  
  3. 4600+0 records out  
  4. 4823449600 bytes (4.8 GB, 4.5 GiB) copied, 283.248 s, 17.0 MB/s  


特别注意这里 bs=1M,千万不要写成1MB
1M是1024*1024 Bytes, 而1MB是1000*1000 Bytes,会造成img文件的大小不是512 bytes的整数倍,后面会报错。

这个过程大约几分钟完成。 如果比较着急,可以另开一个终端,运行如下命令,可以观察到img文件大小的变化。

[plain] view plain copy
  1. pi@raspberrypi:~ $ watch -d -n 5 ls -lh ~/backupimg  


完成后,确认一下img文件已经生成,且文件大小正确

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ ls -l raspberrypi.img  
  2. -rw-r--r-- 1 root root 4823449600 Dec 15 22:00 raspberrypi.img  


然后给img文件分区

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img --script -- mklabel msdos  
  2. pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img --script -- mkpart primary fat32 8192s 122479s  
  3. pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img --script -- mkpart primary ext4 122880s -1  


分区的起始扇区数都是8的倍数,以保证4k对齐

检查分区是否成功

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo parted raspberrypi.img  
  2. GNU Parted 3.2  
  3. Using /home/pi/backupimg/raspberrypi.img  
  4. Welcome to GNU Parted! Type 'help' to view a list of commands.  
  5. (parted) print free                                                         
  6. Model:  (file)  
  7. Disk /home/pi/backupimg/raspberrypi.img: 4823MB  
  8. Sector size (logical/physical): 512B/512B  
  9. Partition Table: msdos  
  10. Disk Flags:   
  11.   
  12. Number  Start   End     Size    Type     File system  Flags  
  13.         16.4kB  4194kB  4178kB           Free Space  
  14.  1      4194kB  62.7MB  58.5MB  primary               lba  
  15.         62.7MB  62.9MB  205kB            Free Space  
  16.  2      62.9MB  4822MB  4759MB  primary  
  17.         4822MB  4823MB  1049kB           Free Space  
  18.   
  19. (parted) quit       


在parted程序中,输入print free命令可以显示分区内容,输入quit退出

【挂载img文件到系统】
img文件对应的Loop device的设置

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo losetup -f --show raspberrypi.img  
  2. /dev/loop0  


下面的命令中相应输入/dev/loop0,如果不是 loop0 请做相应调整(以及以后的各个步骤里的loop0都要改变)

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo kpartx -va /dev/loop0  
  2. add map loop0p1 (254:0): 0 114288 linear 7:0 8192  
  3. add map loop0p2 (254:1): 0 9295872 linear 7:0 122880  
  4.   
  5. pi@raspberrypi:~/backupimg $ ls /dev/mapper/loop0p*  
  6. /dev/mapper/loop0p1  /dev/mapper/loop0p2  


此时loop device就设置好了,loop0p1对应的是img文件分区上的 /boot,loop0p2对应的是 /(根)


接着给img文件中的两个分区格式化

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo mkfs.vfat -n boot /dev/mapper/loop0p1  
  2. mkfs.fat 4.1 (2017-01-24)  
  3. mkfs.fat: warning - lowercase labels might not work properly with DOS or Windows  
  4. pi@raspberrypi:~/backupimg $ sudo mkfs.ext4 /dev/mapper/loop0p2  
  5. mke2fs 1.43.4 (31-Jan-2017)  
  6. Discarding device blocks: done                              
  7. Creating filesystem with 1161984 4k blocks and 290880 inodes  
  8. Filesystem UUID: d3e5d272-7752-48b2-a10e-e0e6d217ca7e  
  9. Superblock backups stored on blocks:   
  10. 32768, 98304, 163840, 229376, 294912, 819200, 884736  
  11.   
  12. Allocating group tables: done                              
  13. Writing inode tables: done                              
  14. Creating journal (16384 blocks): done  
  15. Writing superblocks and filesystem accounting information: done   


挂载目标img文件loop device

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ mkdir tgt_boot tgt_Root  
  2. pi@raspberrypi:~/backupimg $ sudo mount -t vfat -o uid=pi,gid=pi,umask=0000 /dev/mapper/loop0p1 ./tgt_boot/  
  3. pi@raspberrypi:~/backupimg $ sudo mount -t ext4 /dev/mapper/loop0p2 ./tgt_Root/  


请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2,3条命令可能会是:

[plain] view plain copy
  1. yang@debian:~/backupimg$ sudo mount -t vfat -o uid=yang,gid=yang,umask=0000 /dev/mapper/loop0p1 ./tgt_boot/  
  2. yang@debian:~/backupimg$ sudo mount -t ext4 /dev/mapper/loop0p2 ./tgt_Root/  


【备份/boot】
首先备份/boot,直接拷贝即可

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo cp -rfp ./src_boot/* ./tgt_boot/  


【备份“/”】
备份根文件系统稍微复杂些,可以用两种方法

(方法一),dump/restore方法

首先对目标挂载点设置合适的权限,并清空

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo chmod 777 tgt_Root  
  2. pi@raspberrypi:~/backupimg $ sudo chown pi.pi tgt_Root  
  3. pi@raspberrypi:~/backupimg $ sudo rm -rf ./tgt_Root/*  
  4. pi@raspberrypi:~/backupimg $ cd tgt_Root/  


请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2条命令可能会是:

[plain] view plain copy
  1. yang@debian:~/backupimg$ sudo chown yang.yang tgt_Root  


然后开始备份

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg/tgt_Root $ sudo dump -0uaf - ../src_Root/ | sudo restore -rf -  
  2.   DUMP: Date of this level 0 dump: Fri Dec 15 22:22:34 2017  
  3.   DUMP: Dumping /dev/sda2 (/home/pi/backupimg/src_Root) to standard output  
  4.   DUMP: Label: none  
  5.   DUMP: Writing 10 Kilobyte records  
  6.   DUMP: mapping (Pass I) [regular files]  
  7.   DUMP: mapping (Pass II) [directories]  
  8.   DUMP: estimated 4241064 blocks.  
  9.   DUMP: Volume 1 started with block 1 at: Fri Dec 15 22:22:35 2017  
  10.   DUMP: dumping (Pass III) [directories]  
  11.   DUMP: dumping (Pass IV) [regular files]  
  12.   DUMP: 62.53% done at 8780 kB/s, finished in 0:03  
  13.   DUMP: Volume 1 completed at: Fri Dec 15 22:30:36 2017  
  14.   DUMP: Volume 1 4242680 blocks (4143.24MB)  
  15.   DUMP: Volume 1 took 0:08:01  
  16.   DUMP: Volume 1 transfer rate: 8820 kB/s  
  17.   DUMP: 4242680 blocks (4143.24MB)  
  18.   DUMP: finished in 481 seconds, throughput 8820 kBytes/sec  
  19.   DUMP: Date of this level 0 dump: Fri Dec 15 22:22:34 2017  
  20.   DUMP: Date this dump completed:  Fri Dec 15 22:30:36 2017  
  21.   DUMP: Average transfer rate: 8820 kB/s  
  22.   DUMP: DUMP IS DONE  


整个dump/restore过程需要几分钟时间,看到 DUMP IS DONE 就说明备份成功了

然后返回上层目录

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg/tgt_Root $ cd ..  
  2. pi@raspberrypi:~/backupimg $   


(方法二),tar方法
如果上述方法一的 sudo dump … 那一步出现 Broken pipe、 Illegal instruction等错误而失败的话,可以使用方法二。
这个方法会使用tar把源SD卡的根文件系统打包,所以在本机系统空间里需要额外的和源SD卡的根文件系统已用空间大小一样的可用空间。

首先,和方法一里面一样,对目标挂载点设置合适的权限,并清空

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo chmod 777 tgt_Root  
  2. pi@raspberrypi:~/backupimg $ sudo chown pi.pi tgt_Root  
  3. pi@raspberrypi:~/backupimg $ sudo rm -rf ./tgt_Root/*  


请注意,我用的是另一个raspberry系统做备份操作的,如果是用其他linux系统,请注意uid和gid的设置,上述第2条命令可能会是:

[plain] view plain copy
  1. yang@debian:~/backupimg$ sudo chown yang.yang tgt_Root  


然后用tar把源SD卡的根文件系统打包

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ cd src_Root/  
  2. pi@raspberrypi:~/backupimg/src_Root $ sudo tar pcf ../backup.tar .  


tar的过程中可能会出现一些 socket ignored 错误,可以忽略。

此过程可能需要比较长的时间,可另外开一个终端,运行如下命令,用来观察backup.tar文件大小的变化。

[plain] view plain copy
  1. pi@raspberrypi:~ $ watch -d -n 5 ls -lh ~/backupimg  


上述打包过程结束后,接着将tar包解开到目标img文件的根文件系统

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ cd ../tgt_Root/  
  2. pi@raspberrypi:~/backupimg/tgt_Root $ sudo tar pxf ../backup.tar  


此过程可能需要比较长的时间,可另外开一个终端,运行如下命令,用来观察目标img文件的根文件系统的已用空间大小变化

[plain] view plain copy
  1. pi@raspberrypi:~ $ watch -d -n 5 df -h  


解包过程结束后,回到上层目录,并删除backup.tar文件

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg/tgt_Root $ cd ..  
  2. pi@raspberrypi:~/backupimg $ sudo rm backup.tar   
  3. pi@raspberrypi:~/backupimg $   


【相应修改PARTUUID设定】
这时候整个备份就已经完成了。不过此时的img文件即使写入到空白SD卡里面也是无法启动的,因为Raspbian启动要对应分区的PARTUUID,所以我们还要修改目标img文件里的如下两个文件:

[plain] view plain copy
  1. ./tgt_boot/cmdline.txt   
  2. ./tgt_Root/etc/fstab   

 

首先查看img文件对应的loop device的两个分区的PARTUUID

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo blkid  
  2. /dev/mmcblk0p1: LABEL="boot" UUID="E5B7-FEA1" TYPE="vfat" PARTUUID="ddffe93a-01"  
  3. /dev/mmcblk0p2: UUID="b4ea8e46-fe87-4ddd-9e94-506c37005ac5" TYPE="ext4" PARTUUID="ddffe93a-02"  
  4. /dev/sda2: UUID="9a7608bd-5bff-4dfc-ac1d-63a956744162" TYPE="ext4" PARTUUID="ec04fe79-02"  
  5. /dev/loop0: PTUUID="af2f8761" PTTYPE="dos"  
  6. /dev/mmcblk0: PTUUID="ddffe93a" PTTYPE="dos"  
  7. /dev/sda1: LABEL="boot" UUID="B60A-B262" TYPE="vfat" PARTUUID="ec04fe79-01"  
  8. /dev/mapper/loop0p1: SEC_TYPE="msdos" LABEL="boot" UUID="755C-C29C" TYPE="vfat" PARTUUID="af2f8761-01"  
  9. /dev/mapper/loop0p2: UUID="a174c97e-049f-4fbd-abb7-0b9098dae24a" TYPE="ext4" PARTUUID="af2f8761-02"  


这里可以看到/boot对应的是af2f8761-01 , / 对应的是af2f8761-02

修改 cmdline.txt 文件

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo vi ./tgt_boot/cmdline.txt   
  2. pi@raspberrypi:~/backupimg $ cat ./tgt_boot/cmdline.txt   
  3. dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=af2f8761-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait  


修改 fstab 文件

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo vi ./tgt_Root/etc/fstab   
  2. pi@raspberrypi:~/backupimg $ cat ./tgt_Root/etc/fstab   
  3. proc            /proc           proc    defaults          0       0  
  4. PARTUUID=af2f8761-01  /boot           vfat    defaults          0       2  
  5. PARTUUID=af2f8761-02  /               ext4    defaults,noatime  0       1  
  6. # a swapfile is not a swap partition, no line here  
  7. #   use  dphys-swapfile swap[on|off]  for that  


卸载各个挂载的分区

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo umount src_boot src_Root tgt_boot tgt_Root  


删除loop device

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ sudo kpartx -d /dev/loop0  
  2. pi@raspberrypi:~/backupimg $ sudo losetup -d /dev/loop0  


删除挂载点目录

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ rmdir src_boot src_Root tgt_boot tgt_Root  

最后剩下img文件

[plain] view plain copy
  1. pi@raspberrypi:~/backupimg $ ls -l  
  2. total 4469676  
  3. -rw-r--r-- 1 root root 4823449600 Dec 15 23:10 raspberrypi.img  


【大功告成】
完成之后可以用dd或者Etcher烧写img文件到其他SD卡中,注意烧写到新卡中在树莓派中运行后,要先用raspi-config先把分区空间expand一下,否则可用空间会很小。

虽然步骤比较多,但是赤手空拳的一步一步命令来的更清晰明了,也能了解其中的技术细节。

转自网络

posted on 2018-05-04 11:46  劳斯机要开车了  阅读(267)  评论(0)    收藏  举报