在 Linux 下掛載 SD 卡映像檔

最近有需求是要將 Raspbian 之類提供的 SD 卡映像檔 (.img) 裡面的 rootfs 給提出來,因此找了一下不需要將該映像檔燒到實體 SD 卡,而是將其掛載到目錄後再將需要的檔案複製出來的方法。

這邊以我下載的 Raspbian 檔案為例,本文收集了三種方式,分別為透過 fdisk 計算 offset 後掛載、使用 kpartx 進行掛載、使用 losetup 進行掛載等。

在進行之前,先確認下載的 sdcard image 的類型, 2018-06-27-raspbian-stretch.zip 解壓縮後的檔案,用 file 命令看會是這樣:

coldnew@gentoo ~ $ file 2018-06-27-raspbian-stretch.img
2018-06-27-raspbian-stretch.img: DOS/MBR boot sector; partition 1 : ID=0xc, start-CHS (0x0,130,3), end-CHS (0x6,4,22), startsector 8192, 88472 sectors; partition 2 : ID=0x83, start-CHS (0x6,30,25), end-CHS (0x24a,106,32), startsector 98304, 9322496 sectors

那就讓我們來看看要怎樣掛載這個 2018-06-27-raspbian-stretch.img 的某些分割區吧!

fdisk

最基本的方式,就是透過 fdisk 去查看這個映像檔(.img) 的內容,我們可以看到這個映像檔有兩個分割區以及其格式

coldnew@gentoo ~ $ sudo fdisk -u -l 2018-06-27-raspbian-stretch.img
Disk 2018-06-27-raspbian-stretch.img: 4.5 GiB, 4823449600 bytes, 9420800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xbd98648d

Device                           Boot Start     End Sectors  Size Id Type
2018-06-27-raspbian-stretch.img1       8192   96663   88472 43.2M  c W95 FAT32 (LBA)
2018-06-27-raspbian-stretch.img2      98304 9420799 9322496  4.5G 83 Linux

接下來注意到了 2018-06-27-raspbian-stretch.img2 (分割區 2) 的起始位址是 98304 ,因為每一個 sector 是 512 bytes ,所以我們可以算出 offset 為 98304 * 512 = 50331648

coldnew@gentoo ~ $ echo $((98304 * 512))
50331648

知道了 offset 後,我們就可以用掛載 loop 設備的方式來掛載這個 .img 的分割區 2 到 rootfs 資料夾去

coldnew@gentoo ~ $ mkdir -p rootfs
coldnew@gentoo ~ $ sudo mount -o loop,offset=$((98304 * 512)) 2018-06-27-raspbian-stretch.img rootfs

這樣 rootfs 就有 2018-06-27-raspbian-stretch.img 的分割區 2 內的檔案囉~

如果想要現成的腳本做這件事的話,可以試試看 https://github.com/AlexanderAmelkin/mountimg/blob/master/mountimg 這份腳本

kpartx

對於 Gentoo 的使用者來說,要使用 kpartx 命令的話,需要先安裝 multipath-tools 這個工具

coldnew@gentoo ~ $ sudo emerge sys-fs/multipath-tools

接下來,就透過 kpartx 這工具來掛載 .img 檔案

coldnew@gentoo ~ $ sudo kpartx -av 2018-06-27-raspbian-stretch.img
add map loop0p1 (254:0): 0 88472 linear /dev/loop0 8192
add map loop0p2 (254:1): 0 9322496 linear /dev/loop0 98304

使用上面的命令後,會將檔案掛載到 /dev/mapper/loop0p1/dev/mapper/loop0p2 這兩個位置,如果我們想要掛載 /dev/mapper/loop0p2rootfs 資料夾的話,則這樣

coldnew@gentoo ~ $ mkdir -p rootfs
coldnew@gentoo ~ $ sudo mount /dev/mapper/loop0p2 rootfs

要解除掛載的話,則是這樣

coldnew@gentoo ~ $ sudo umount rootfs
coldnew@gentoo ~ $ sudo kpartx -d 2018-06-27-raspbian-stretch.img
loop deleted : /dev/loop0

losetup

losetup 是位於 util-linux 的命令,正常的 Linux 發行板都會內建安裝,我們可以透過這個命令對 loop 設備進行管理。

首先先透過 losetup 找出合適的 /dev/loop* 節點,並將映像檔弄上去:

coldnew@gentoo ~ $ sudo losetup --show -f -P 2018-06-27-raspbian-stretch.img
/dev/loop0

接下來,你可以透過 ls 命令發現到 /dev/loop0 多出了兩個分割區

coldnew@gentoo ~ $ ls -l /dev/loop0*
brw-rw---- 1 root disk   7, 0  8 月 25 11:26 /dev/loop0
brw-rw---- 1 root disk 259, 0  8 月 25 11:26 /dev/loop0p1
brw-rw---- 1 root disk 259, 1  8 月 25 11:26 /dev/loop0p2

然後我們就可以透過一般的 mount 命令來進行掛載了,這邊一樣以第二個分割區為例:

coldnew@gentoo ~ $ mkdir -p rootfs
coldnew@gentoo ~ $ sudo mount /dev/loop0p2 rootfs

事情都搞定後記得將掛載到 loop device 的位置給 deatch 掉:

coldnew@gentoo ~ $ sudo umount rootfs
coldnew@gentoo ~ $ sudo losetup -d /dev/loop0