sstea備忘録

日々のPCライフのメモ、備忘録、及びそれに類推する何か。
記載内容に間違い等を発見された場合はコッソリ教えてください... → sstea<a>aol.jp (<a> を @ に変えてください)


ディスクイメージ

Raspberry Pi のディスクイメージを一から作る

前回カーネルも差し替えたので、以前の記事を見ながらディスクイメージのバックアップを取ろうかと思ったのですが、以前に構築した Linux Mint の仮想環境で、VirtualBox が(なぜか)ホスト側に挿した microSD カードリーダをうまく認識してくれませんでした。
仕方がないので、ディスクイメージをコネコネして、パーティションのリサイズやら何やらを行なったディスクイメージを作成することにしました。
gparted でリサイズしようと思ったんですが、アレ?イメージファイルだと、何故かリサイズ出来ないですね。。。

ちなみに、前回カーネルを差し替えたものに加えて、
NTP設定不要デーモンの停止、RAMディスクの使用、SWAPの停止、を行なっています。
SD使用量の節約のため日本語化等は見送りました。
ディスク使用量は半分弱といったところです。
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/root        3671884 1623100   1849424  47% /
devtmpfs          219996       0    219996   0% /dev
tmpfs              44836     336     44500   1% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89660       0     89660   0% /run/shm
/dev/mmcblk0p1     57288   10200     47088  18% /boot
tmpfs              32768       0     32768   0% /tmp
tmpfs              32768     112     32656   1% /var/log

◆ディスクイメージのベースの作成
"Win32 Disk Imager" を使用して、microSD のディスクイメージを Read し、仮想環境からも見える共有フォルダに入れておきます。以下、仮想環境の Linux Mint での操作になります。
(以下、ディスクイメージを rpi.img というファイル名で取得したとして記載しています。)
$ fdisk -l /media/sf_shared/rpi.img
ディスク /media/sf_shared/rpi.img: 3951 MB, 3951034368 バイト
ヘッド 255, セクタ 63, シリンダ 480, 合計 7716864 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスク識別子: 0x0009bf4f

                デバイス ブート    始点      終点  ブロック   Id  システム
/media/sf_shared/rpi.img1          8192    122879    57344    c  W95 FAT32 (LBA)
/media/sf_shared/rpi.img2        122880   7716863  3796992   83  Linux

まずは、作成するディスクイメージのサイズを決めます。
今回は4GBのmicroSDをしようしているので、半分の2GBにしてみようと思います。

まず、空のファイルをイレモノとして作ります。
元のサイズの半分にした値
  (7716863 + 1) / 2 = 3858432
をcountに指定します。
$ export IMGFILE=/media/sf_shared/new.img

$ dd if=/dev/zero of=${IMGFILE} count=3858432 bs=512
これで、単にゼロ埋めされた2GBのファイルが出来上がりました。
# ちなみに、fdisk の表示される値と単位を合わせる意味で bs=512 としていますが、
# bs を(8倍の) 4096 とかにした方が、ファイルの作成時間は短くなります。
# その場合、count は(8分の1の)482304 とする必要があります。
# 詳細は↓おまけ1参照

パーティションテーブルを作成し、パーティションを2つ作成します。
fdisk コマンドで対話モードで設定しても全然問題ないんですが、表現が難しいので下記のようなコマンドにしておきます。(凄く見にくいですが、$'\n' が改行と思ってください。)
$ echo o$'\n'w | fdisk ${IMGFILE}
$ echo n$'\n'p$'\n'$'\n'8192$'\n'122879$'\n'w | fdisk ${IMGFILE}
$ echo n$'\n'p$'\n'$'\n'122880$'\n'3858431$'\n'w | fdisk ${IMGFILE}
$ echo t$'\n'1$'\n'c$'\n'w | fdisk ${IMGFILE}

これでガワだけは出来ました。
$ fdisk -l ${IMGFILE}

ディスク /media/sf_shared/new.img: 1975 MB, 1975517184 バイト
ヘッド 255, セクタ 63, シリンダ 240, 合計 3858432 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスク識別子: 0x0177f305

                デバイス ブート    始点      終点  ブロック   Id  システム
/media/sf_shared/new.img1          8192    122879    57344    c  W95 FAT32 (LBA)
/media/sf_shared/new.img2        122880   3858431  1867776   83  Linux

# 最初はこのディスクイメージを "sudo kpartx -v -a ${IMGFILE}" して、
# "mkfs.ext4 /dev/mapper/loop0p2" とかして直接フォーマットしようとしたんですが、
# 何かうまく出来なくてmountも出来ないので、下記のような手順を踏む事にしました。

◆各パーティションイメージの作成
それぞれ
  (122879 + 1) - 8192 = 114688
  (3858431 + 1) - 122880 = 3735552
の値を指定し、各パーティションのイメージファイルを作成します。
$ dd if=/dev/zero of=boot.img count=114688 bs=512
$ dd if=/dev/zero of=rootfs.img count=3735552 bs=512
それぞれフォーマットします。
$ mkfs.vfat boot.img
$ mkfs.ext4 -F rootfs.img

元のイメージディスクをマウントします。
$ mkdir old1/ old2/ new1/ new2/
$ sudo kpartx -v -a /media/sf_shared/rpi.img
$ sudo mount /dev/mapper/loop0p1 old1/
$ sudo mount /dev/mapper/loop0p2 old2/
元のイメージディスクの中身をそれぞれ全コピーします。
$ sudo mount boot.img new1/
$ sudo mount rootfs.img new2/
$ sudo cp -a old1/* new1/
$ sudo cp -a old2/* new2/
その他変更等(.bash_history や /var/cache/* の削除等)、やりたければやって、気が済めばアンマウントします。
$ sudo umount new1/
$ sudo umount new2/
元のイメージディスクをアンマウントします。
$ sudo umount old1/
$ sudo umount old2/
$ sudo kpartx -d /media/sf_shared/rpi.img
$ rmdir old1/ old2/ new1/ new2/

◆ディスクイメージとして結合
ベースのディスクイメージの各パーティションを置き換えて出来上がりです。
$ dd if=boot.img of=${IMGFILE} seek=8192 bs=512
$ cat rootfs.img >> ${IMGFILE}
これを "Win32 Disk Imager" で microSD に書き込めば、いつでもこの環境に復帰できます。
ちなみに、このディスクイメージは圧縮したら 400MB 弱になりました。

◆おまけ1

dd コマンドでは "bs=512, count=2048" でも、"bs=1024, count =1024" でも、どちらでも 1MB (bs * count) の読み書きを行なう、という事には変わりありません。では動きとしてはどう違うのでしょうか?

dd コマンドでは、if で指定したファイルから bs 単位で read し、of で指定したファイルに bs 単位で write を行う、という操作を count 回数分繰り返します。
つまり bs 単位の read, write システムコールを count 回発行しているのです。

以下のように、strace で観察するとよく分かります。
$ strace dd if=/dev/zero of=dummy count=100 bs=512
execve("/bin/dd", ["dd", "if=/dev/zero", "of=dummy", "count=100", "bs=512"], [/* 48 vars */]) = 0
brk(0)                                  = 0x9cf4000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
            :
open("/dev/zero", O_RDONLY|O_LARGEFILE) = 3
dup2(3, 0)                              = 0
close(3)                                = 0
_llseek(0, 0, [0], SEEK_CUR)            = 0
open("dummy", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
dup2(3, 1)                              = 1
close(3)                                = 0
clock_gettime(CLOCK_MONOTONIC, {238, 286988438}) = 0
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512

            :

Raspberry Pi のディスクイメージをバックアップする

ここまで環境設定をいろいろやってきました。

しかし、機能的には何も嬉しい事をしてません。
ここからは、いろいろインストールしたりとかしようと思っていますが、一旦ここでこの環境をセーブしておきたいと思います。

何か失敗してやり直したいと思うかも知れませんし、ファイルシステム破損してしまった時とかに、再度環境構築するのは面倒くさいですし、、、

本当のところは、現在使っているclass 4のmicro SDカードからclass 10のmicro SDカードに引越してみて、起動時間がどうなるか見てみたい、というのが一番だったりするのですが。。。

単純にディスクイメージを吸い出すだけでもいいのですが、それだとmicroSDのサイズのディスクイメージが出来てしまいます。
(32GBのmicroSDを使用していると使用/未使用を問わず32GBのディスクイメージファイルになります。)
圧縮すれば未使用部分は縮むのですが、それでも個人的にはディスクイメージファイル自体に縮んでいて欲しいのです。(容量の小さいmicroSDに引越し出来ないし)

ディスクイメージの引越しについて、ディスクイメージを弄くり倒して行なう別解を用意しました。
(ホストマシンに直接カードリーダが繋げない、gparted使えない、などの環境でも引越し可能なはずです。)

◆ rootfs パーティションを縮小
まず、Linux ホストマシンに Raspberry Pi で使用していたmicroSDを挿します。
以前に Linux Mint の仮想環境をVirtualBoxで作成したので、今回はそれを使おうと思います。

Linux ホストマシンで gparted を使用します。ないならインストールします。
$ sudo apt-get install gparted

gparted を使用し、Raspberry Pi の rootfs パーティション(2個目のパーティション)を適当なサイズに縮小します。

ss_vbox_gparted

◆ ディスクイメージの出力
Raspberryp Pi 用microSD が /dev/sdb として認識されているものとして以下、記載します。

$ sudo fdisk -l /dev/sdb
とすると、
デバイス ブート      始点        終点     ブロック  Id  システム
/dev/sdb1            2048      262143      130048    6  FAT16
/dev/sdb2          262144     5439487     2588672   83  Linux
というように表示されたとします。
ここで、二個目のパーティションの終点の数値が最終セクタ番号になります。

なので、サイズとしては +1 した値を指定します。
$ sudo dd if=/dev/sdb of=/media/sf_shared/raspi.img count=5439488 bs=512
これでディスクイメージファイルが /media/sf_shared/raspi.img として出力されます。

◆ディスクイメージをマウントする
$ sudo kpartx -v -a /media/sf_shared/raspi.img
とすると、下記のような表示が出ると思います。
この時に表示された loop デバイスを使用します。(この例では loop0 を使用します)
add map loop0p1 (252:0): 0 260096 linear /dev/loop0 2048
add map loop0p2 (252:1): 0 5177344 linear /dev/loop0 262144

下記のようにすることで、Raspberry Pi 用のディスクイメージの rootfs パーティションを /mnt/ にマウントできます。
$ sudo mount /dev/mapper/loop0p2 /mnt/
◆ディスクイメージの中身を編集
せっかくマウントしたので、中をいじってみたいと思います。

bashの履歴ファイルを削除しておきましょう。
$ rm /mnt/home/pi/.bash_history
$ touch /mnt/home/pi/.bash_history

キャッシュもたぶん消しても大丈夫と思います。
(debconf ディレクトリは残しておいた方がよさそうです。apt 時に何かワーニング出ました。。。)
$ sudo rm -rf /mnt/var/cache/*
$ sudo mkdir /mnt/var/cache/debconf/

ディスクイメージの圧縮時に圧縮率が高まるように、未使用領域をゼロ埋めしておきます。
(下記のように実行することで空き容量がなくなるまで、中身が0で埋まったdummyというファイルを作成しています)
$ sudo dd if=/dev/zero of=/mnt/dummy bs=4096
$ sudo rm /mnt/dummy

◆ディスクイメージをアンマウントする

$ sudo umount /mnt/
$ sudo kpartx -d /media/sf_shared/raspi.img

◆おまけ1

Win32DiskImager で普通にディスクイメージを吸い出してもいいと思います。
上記を参考に、応用すれば必要部分のみのディスクイメージにすることが出来ます。

gparted は、コマンドラインで起動する場合、パラメータにデバイス意外にもイメージファイルを指定することができます。(イメージファイルの場合は、リサイズは出来ませんが...)
$ sudo gparted イメージファイル

また、下記のようにすることで、イメージファイルを必要部分のみ切り出すことができます。
$ sudo dd if=イメージ1 of=イメージ2 count=必要セクタ数 bs=512

◆おまけ2

ちにみにclass 4のmicro SDカードからclass 10のmicro SDカードに変えてみましたが、起動時間は3秒ほど早くなっただけでした。(もう少し期待してたんですが。)


今回作成したディスクイメージは dd コマンド、または Win32DiskImager で microSD に書き込むことで、環境をいつでもリストア出来ます。

次回からは、心おきなく Raspberry Pi をいじくることが出来ますね。

プライバシーポリシー
当サイトでは、Googleを含む第三者配信事業者や広告ネットワークが配信する広告を掲載しています。
当サイトでは、アクセス情報に基づいた適切な広告表示、及びトラフィックデータ収集のためにCookieを使用しています。
ユーザーはCookieの無効化により、これらの情報の提供を拒否する事ができます。
スポンサーリンク
記事検索
スポンサーリンク