树莓派(Raspberry Pi)修改系统镜像(img)

树莓派修改系统镜像

讨论如何使用通过loop设备映射文件,挂载树莓派img中的分区,然后像普通的文件系统那样修改镜像分区中的文件。

有2个关键点

  • 如何确认分区的起始位置,以及分区的范围。
  • 不同版本的losetup支持的参数不一样,如果支持-P参数特性,则可以直接加载分区,无需再手动计算偏移量,可以像挂载普通硬盘一样直接生成分区块设备

准备工作

  • 需要一个支持linux设备,已经root了的termux,或者,一个普通的linux发行版均可。
  • 需要用到的关键命令losetup,fdisk,tun2fs,mount,请检查是否都有。
  • 大部分操作均需要root权限。
  • 去源内下载一份镜像文件。

第一步:下载镜像

首先,下载一个可以用于写入树莓派的img镜像,国内可以在清华的镜像站中下载。

清华源的地址:https://mirrors.tuna.tsinghua.edu.cn/raspberry-pi-os-images/raspbian/images/raspbian-2020-02-14/

我下载的是2020-02-13-raspbian-buster.zip,解压后得到2020-02-13-raspbian-buster.img,img文件可以直接烧录到内存卡,它实际上是个包含了mbr分区表的磁盘映像。

第二步:使用losetup命令把img文件映射成块设备

首先我们先确认losetup支持的选项,有没有-P选项:

#这是我手机版本的losetup
$losetup --help
usage: losetup [-cdrs] [-o OFFSET] [-S SIZE] {-d DEVICE...|-j FILE|-af|{DEVICE FILE}}

Associate a loopback device with a file, or show current file (if any)
associated with a loop device.

Instead of a device:
-a      Iterate through all loopback devices
-f      Find first unused loop device (may create one)
-j      Iterate through all loopback devices associated with FILE

existing:
-c      Check capacity (file size changed)
-d      Detach loopback device

new:
-s      Show device name (alias --show)
-o      Start assocation at OFFSET into FILE
-r      Read only
-S      Limit SIZE of loopback association (alias --sizelimit)

看帮助信息,它不支持-P参数,直接加载一个多分区的img文件,它不会生成/dev/loop0p1这样的分区块设备。

如果losetup支持-P参数,那么,可以这样让他/dev生成分区的块设备loop0p1

#losetup -f -P ./2020-02-13-raspbian-buster.img

再查看/dev下loop有没有生成对应分区的块设备,如果额外生成/dev/loop0p2这样的文件,则直接挂载这个设备。如果没有,继续以下步骤,手动计算分区的起始位置和大小。

注意,linux发行版的losetup如果没有-S参数,请看看是否是--sizelimit参数,没有-o的话,则看看--offset,先通过losetup --help查看

第三步:确认分区数量和分区的位置

上面的losetup有两个很重要的参数

  • -S Limit SIZE of loopback association

    • 指定映射的文件部分内容(可以用来设定分区的大小)
  • -o Start assocation at OFFSET into FILE

    • 跳过多少个字节(用这个参数可以指定分区的起始位置)

不同版本的可能losetup相关的参数有细微的不同,要以实际为准。

那么需要确定分区的起始和结束位置。先尝试把整个img映射,注意,这需要root权限

加载当前文件夹的2020-02-13-raspbian-buster.img

#losetup -f ./2020-02-13-raspbian-buster.img

映射后通过losetup命令(不带参数)得知,文件映射到了/dev/loop0这个设备

因为img包含了mbr分区表信息,我可以使用fdisk来读取分区表,获取分区信息。

#fdisk -l  /dev/loop0
Disk /dev/loop0:3.5 GiB,3787456512 字节,7397376 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0xea7d04d6

设备         启动   起点    末尾    扇区  大小 Id 类型
/dev/loop0p1        8192  532479  524288  256M  c W95 FAT32 (LBA)
/dev/loop0p2      532480 7397375 6864896  3.3G 83 Linux

通过分区表,我获得了一些信息。

  • 这个是个3.5G的映像。
  • 这个img有2个分区,一个是fat32分区(/dev/loop0p1),一个是linux的ext分区。(/dev/loop0p2)
  • 分区的具体物理位置(起点、末尾),分区大小(扇区)
  • 这个磁盘镜像每个扇区是512字节

他虽然写了/dev/loop0p2这样的设备,但是实际上,可能/dev下根本没有loop0p1 loop0p2这两个块设备文件。

此时需要换一种方式,根据分区在文件内的位置,直接映射分区到loop设备,然后再挂载。

第3.5步:计算分区位置及大小

因为img文件包含一个mbr分区表,可以通过查看分区表确认分区数量和位置,通过以上fdisk读取的分区表信息可以得知,该img有2个分区。

fat32类型那个分区应该存放内核,config.txt之类的分区,也就是我们烧录后看到内存卡只有256m的原因。

linux类型分区是树莓派的根分区,也就是进系统后,挂载在/的根分区

此时我需要计算根分区的起始位置,如果我需要改动config.txt,则计算fat32分区的位置,以下以计算根分区为例。

逻辑扇区大小为512字节,分区大小为扇区数量的512倍字节,需要乘以扇区大小(下面换算分区大小同理),根分区的起始位置则换算为

512 * 532480 = 272629760

它偏离文件起始的272629760字节,即用-o参数指定偏移的值。

分区的大小为

512  * 6864896 = 3514826752

使用-S参数限制映像文件的内容范围,记录下来以上信息后,卸载loop设备(此处为/dev/loop0),然后再重新进行映射。

卸载设备

#losetup -d /dev/loop0

再次映射

#losetup -f -o 272629760 -S 3514826752 ./2020-02-13-raspbian-buster.img

此时,我们再次losetup看看映射的loop设备

#losetup
NAME        SIZELIMIT    OFFSET AUTOCLEAR RO BACK-FILE                                                      DIO LOG-SEC
/dev/loop0 3514826752 272629760         0  0 /home/xxx/raspbian/2020-02-13-raspbian-buster.img   0     512                                                                           0     512

可以看到sizelimit字段和offset字段都有了具体的值,和我们设置的一致。/dev/loop0映射到了映像文件的根分区范围内

这是一个ext分区,我们可以通过tun2fs来读取文件系统的超级块

#tun2fs -l /dev/loop0

可以看到以下内容

tune2fs 1.44.5 (15-Dec-2018)
Filesystem volume name:   rootfs
Last mounted on:          /mnt/raspbian
Filesystem UUID:          80571af6-21c9-48a0-9df5-cffb60cf79af
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file dir_nlink extra_isize
Filesystem flags:         unsigned_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              214704
Block count:              858112
Reserved block count:     42905
Free blocks:              133541
Free inodes:              108390
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      209
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         7952
Inode blocks per group:   497
Flex block group size:    16
Filesystem created:       Fri Feb 14 00:15:48 2020
Last mount time:          Sat Aug 15 04:54:28 2020
Last write time:          Sat Aug 15 05:22:08 2020
Mount count:              3
Maximum mount count:      -1
Last checked:             Fri Feb 14 00:15:48 2020
Check interval:           0 ()
Lifetime writes:          3052 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:           256
Required extra isize:     32
Desired extra isize:      32
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      6006b686-6f27-4ca7-b7ea-d1d803c3da46
Journal backup:           inode blocks

说明正确读出了该分区下文件系统的超级快。可以挂载。

第4步:挂载文件系统

在当前文件夹下新建一个root文件夹作为分区的挂载点。

#mkdir root

挂载

#mount -t ext4 -o rw /dev/loop0 root

挂载成功后,通过当前目录下root挂载点访问img中根分区的内容。需要修改什么内容就尽情修改吧!

修改完成后使用sync命令同步写入磁盘。

#sync
#sync
#sync

退出root文件夹后,卸载当前目录下root挂载点

#umount root

取消映射关系,分离

#losetup -d /dev/loop0

插入tf卡后,用dd指令把img文件写入,假设内存卡设备为/dev/sdc

dd if=./2020-02-13-raspbian-buster.img of=/dev/sdc

镜像比较大,而且tf卡性能较差的情况下,写入的速度比较慢,需要耐心等待。

写入成功后,sync同步,即可取出tf卡。树莓派系统刷写完毕。

你可能感兴趣的:(树莓派(Raspberry Pi)修改系统镜像(img))