mattintosh note

どこかのエンジニアモドキの備忘録

Arch Linux ARMのディスクイメージを作成する(losetup、kpartx)

Raspberry Pi × Arch Linux ARM で勉強会をやろうと思っていて、当日は受講者にもブートディスクを作成してもらおうと思ったけど、Arch Linux ARM のディスクイメージで頒布されていない。

デモ機が Linux なら(bsdtar があれば)何も問題はないのだけど、用意されるのは恐らくすべて Windows マシン。Windows ではそもそも microSD に複数パーティションを作成することができない(と、記憶している)し、ルートパーティションに使用する ext4 ファイルシステムを作成することも怪しいため、TAR.GZ から Arch Linux ARM をインストールすることができない(と、思ってる)。

VirtualBox などの仮想マシンを用意してゲスト OS に USB デバイスを接続する…という方法も無くはないが、デモ機すべてに Linux仮想マシンを用意するのも手間がかかる。

そこで、自分の方で Arch Linux ARM のディスクイメージを作成することにした。

イメージファイルの作成

まず、Arch Linux ARM がどれくらいの容量が必要なのか確認する。今回は Raspberry Pi 1 Model B+(armv6)用を使用する。2016年2月2日時点で約 592MB だった(一応、展開して調べたところ約 614MB だったかな)。

$ curl -LO http://archlinuxarm.org/os/ArchLinuxARM-rpi-latest.tar.gz
$ gzip -l ArchLinuxARM-rpi-latest.tar.gz | numfmt --header=1 --field=1,2 --to si
compressed uncompressed ratio uncompressed_name 284M 592M 52.1% ArchLinuxARM-rpi-latest.tar

このサイズであれば 1GB もあれば足りるので 1GB のイメージファイルを作成する。1024 ではなく 1000 で作るけど、メモリ系は実表記より少ないものの方が多いみたいだ。ブートパーティションを差し引いたルートパーティションのサイズは 900MB 程度になり、パッケージを追加すると当然足りなくなるサイズだが、今の御時世 1GB の microSD を手に入れるより 4GB の microSD を入手する方が楽だろうし、resize2fs の練習もできるのでとりあえず 1GB でも十分だろう。

$ fallocate -l 1GB ArchLinuxARM_`date +%Y%m%d`.img

パーティショニング

先程作成したイメージファイルに対して fdisk を実行する。

$ fdisk ArchLinuxARM_20160202.img <<!
o
n



+100M
t
c
n




w
!
Welcome to fdisk (util-linux 2.27.1). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Command (m for help): Created a new DOS disklabel with disk identifier 0x1fd6017a. Command (m for help): Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): Using default response p. Partition number (1-4, default 1): First sector (2048-1953124, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-1953124, default 1953124): Created a new partition 1 of type 'Linux' and of size 100 MiB. Command (m for help): Selected partition 1 Partition type (type L to list all types): Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'. Command (m for help): Partition type p primary (1 primary, 0 extended, 3 free) e extended (container for logical partitions) Select (default p): Using default response p. Partition number (2-4, default 2): First sector (206848-1953124, default 206848): Last sector, +sectors or +size{K,M,G,T,P} (206848-1953124, default 1953124): Created a new partition 2 of type 'Linux' and of size 852.7 MiB. Command (m for help): The partition table has been altered. Syncing disks.

パーティションを確認する。

$ fdisk -l ArchLinuxARM_20160202.img

パーティションが作成されていることを確認する。ここの数値は後で使用する(場合もある。詳しく後述)。

Disk ArchLinuxARM_20160202.img: 953.7 MiB, 1000000000 bytes, 1953125 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: 0x1fd6017a Device Boot Start End Sectors Size Id Type ArchLinuxARM_20160202.img1 2048 206847 204800 100M c W95 FAT32 (LBA) ArchLinuxARM_20160202.img2 206848 1953124 1746277 852.7M 83 Linux

Sector 表示ではなく Byte 表示にする場合は numfmt を通してあげればよい。

$ fdisk -l ArchLinuxARM_20160202.img | numfmt --header=8 --field=2-4 --from-unit=512
Disk ArchLinuxARM_20160202.img: 953.7 MiB, 1000000000 bytes, 1953125 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: 0x6d37494e Device Boot Start End Sectors Size Id Type ArchLinuxARM_20160202.img1 1048576 105905664 104857600 100M c W95 FAT32 (LBA) ArchLinuxARM_20160202.img2 105906176 999999488 894093824 852.7M 83 Linux

メモ:パーティションテーブルはテキストファイルとして残しておくことができる。

$ sfdisk -d ArchLinuxARM_20160202.img >ArchLinuxARM_20160202.dump
$ cat ArchLinuxARM_20160202.dump
label: dos label-id: 0xd382ffcd device: ArchLinuxARM_20160202.img unit: sectors ArchLinuxARM_20160202.img1 : start= 2048, size= 204800, type=c ArchLinuxARM_20160202.img2 : start= 206848, size= 1746277, type=83

ファイルシステムの作成(フォーマット)

mkfs.vfat がなければ dosfstools をインストールしておく。

# pacman -S dosfstools

ループデバイスへのマウント

さて、fdisk でイメージファイルにパーティションを作成したが、複数パーティションの場合は losetup を使ってイメージファイルのパーティションをループデバイスとして扱えるようにする。

losetup は OS によってオプションが異なるらしいので必ず実行環境で man を参照した方がよい

Arch Linux ARM 上の losetup はイメージファイル内容のパーティションを自動的に認識してくれる(-P, --partscan オプションで強制も可能)。

# losetup -f --show ArchLinuxARM_20160202.img
/dev/loop0
# losetup -l
NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0         0      0         0  0 /home/alarm/ArchLinuxARM_20160202.img
# lsblk /dev/loop0
NAME      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0       7:0    0 953.7M  0 loop 
├─loop0p1 259:0    0   100M  0 loop 
└─loop0p2 259:1    0 852.7M  0 loop 

Ubuntu の場合(w kpartx)

Ubuntu でも kpartx を使うと Arch Linuxlosetup のように、パーティションを自動で認識してくれる。

$ sudo apt-get install kpartx
$ sudo kpartx -av ArchLinuxARM_20160202.img
$ lsblk /dev/loop0
add map loop0p1 (252:0): 0 204800 linear /dev/loop0 2048 add map loop0p2 (252:1): 0 1746277 linear /dev/loop0 206848 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 953.7M 0 loop ├─loop0p1 (dm-0) 252:0 0 100M 0 part └─loop0p2 (dm-1) 252:1 0 852.7M 0 part

kpartx はループデバイスを /dev/mapper 以下に配置する。

Ubuntu の場合(w/o kpartx)

kpartx を使わない場合、ちょっと複雑になる。例えば、Ubuntulosetupパーティションを認識してくれない。(fdisk /dev/loopX とすればテーブルは表示はできる)

$ sudo losetup -f ArchLinuxARM_20160202.img
/dev/loop0
$ lsblk /dev/loop0
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0   7:0    0 953.7M  0 loop

この場合は losetup するときに --offset--sizelimit で範囲を指定する。パーティションのサイズは sfdisk -l でユニットをセクタに指定する。

$ sfdisk -l -u S ArchLinuxARM_20160202.img 2>/dev/null | tail -n 4
ArchLinuxARM_20160202.img1 2048 206847 204800 c W95 FAT32 (LBA) ArchLinuxARM_20160202.img2 206848 1953124 1746277 83 Linux ArchLinuxARM_20160202.img3 0 - 0 0 Empty ArchLinuxARM_20160202.img4 0 - 0 0 Empty

上記の開始位置とセクタ数を losetup で指定する。1 セクタは 512 byte。

$ sudo losetup -f --offset $((512*2048)) --sizelimit $((512*204800)) ArchLinuxARM_20160202.img
$ sudo losetup -f --offset $((512*206848)) --sizelimit $((512*1746277)) ArchLinuxARM_20160202.img
$ sudo losetup -a
$ lsblk /dev/loop0 /dev/loop1
/dev/loop0: [0801]:552769 (/home/alarm/ArchLinuxARM_20160202.img), offset 1048576, sizelimit 104857600 /dev/loop1: [0801]:552769 (/home/alarm/ArchLinuxARM_20160202.img), offset 105906176, sizelimit 894093824 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 100M 0 loop loop1 7:1 0 852.7M 0 loop

開始セクタとセクタ数のバイト変換は numfmt --from-unit 512 などを組み合わせて調べることもできる。

$ sfdisk -l -u S ArchLinuxARM_20160202.img 2>/dev/null | tail -n 4 | awk '{ print $1, $2, $4 }' | numfmt --field 2 --from-unit 512 | numfmt --field 3 --from-unit 512
ArchLinuxARM_20160202.img1 1048576 104857600 ArchLinuxARM_20160202.img2 105906176 894093824 ArchLinuxARM_20160202.img3 0 0 ArchLinuxARM_20160202.img4 0 0

ファイルシステムの作成

ファイルシステムの作成は /dev/sda1 などと同じように /dev/loopX に対して実行する。

# mkfs.vfat /dev/loop0p1
# mkfs.ext4 /dev/loop0p2

あとは通常の microSD の作成と同じように進める。

$ mkdir root
$ sudo mount /dev/loop0p2
$ sudo mkdir root/boot
$ sudo mount /dev/loop0p1 root/boot
$ sudo bsdtar -xpf ArchLinuxARM-rpi-latest.tar.gz -C root
$ sudo umount /dev/loop0p1 /dev/loop0p2
$ sudo losetup -d /dev/loop0

出来上がった img を ZIP で圧縮すれば 270MB くらいまで小さくなるのでそのまま置いておいてもそれほど容量は使わない。


Raspberry Pi 1 Model B+ 上でディスクイメージを作成するためのスクリプト