Pylone Blog
ディスクイメージのホスト側での操作方法
QEMUなどのシステムエミュレータでは、エミュレートされるシステムに対して仮想的なデバイスを見せることができます。 ハードディスクなどの記憶装置を模擬する場合、ディスクイメージをファイルとして作成して使うことが多いでしょう。
今回は、このディスクイメージを仮想環境の外側で作成/操作する手段について紹介します。
作業環境としてはLinuxを想定しています。
イメージの作成
希望の構成のディスクイメージを、ホスト環境で作成する手順を説明します。
ファイル作成
まず希望のデバイスサイズのファイルを用意します。
サイズさえ十分ならどのようにしても構いませんが、ddで作ることをおすすめします。例えば 512 MBytes のものを作りたいなら
$ dd if=/dev/zero of=FILENAME bs=1 count=1 seek=536870911
とするとよいでしょう。 (seek= の値は、512 MBytes = 524288 KBytes = 536870912 Byte なので、536870912-1 を指定しています)
素朴に /dev/zero からコピーして
$ dd if=/dev/zero of=FILENAME bs=1M count=512
としてもよいのですが、近代的な(ファイルにholeが作れる)ファイルシステムで作業しているならseek させた方が 終了が早く、実ディスク消費も抑えられます。
パーティション作成
エミュレーションされる環境を実際の環境に近付けるために、ディスクイメージ上にはパーティションが作成されている状態を用意できると便利です。そこで、ループバックデバイスを用いてファイルをブロックデバイスとして見せ、fdisk などの対象に取れるようにする方法について説明します。
パーティションを作成する必要がないなら、ディスクイメージに対してmkfsを実行すれば十分なので、この節の内容は不要です。
まず、losetupを用いてファイルをループバックデバイスに結びつけます。この操作にはroot権限が必要です。
# losetup /dev/loop0 FILENAME
losetupに成功すると、/dev/loop0がFILENAMEを内容とするブロックデバイスとして振る舞うようになります。
何らかの理由でloop0が使用中の場合は、適宜loop1などに読みかえてください。
ループバックデバイスに対してfdiskを実行します。後の作業で各パーティションの開始セクタ番号が必要になるので、-uオプションを付けておきます。
# fdisk -u /dev/loop0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xaf87fef0.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
パーティションを作成します。この例では一つだけ作ります。
Command (m for help): n
First sector (63-1048575, default 63):
Using default value 63
Last sector or +size or +sizeM or +sizeK (63-1048575, default 1048575):
Using default value 1048575
パーティションを作成したら、状態を確認します。
Command (m for help): p
Disk /dev/loop0: 536 MB, 536870912 bytes
255 heads, 63 sectors/track, 65 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0xaf87fef0
Device Boot Start End Blocks Id System
/dev/loop0p1 63 1048575 524256+ 83 Linux
Partition 1 does not end on cylinder boundary.
表示される値のうち、「Units」の値(ここでは 512 bytes)と「Start」の値(ここでは63)を覚えておきます。
作成結果に問題なければ変更をイメージに書き戻して終了します。
Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 22: Invalid argument. The kernel still uses the old table. The new table will be used at the next reboot. Syncing disks. Command (m for help): q
使いおわったらループバックデバイスを開放します。
# losetup -d /dev/loop0
イメージ内のパーティションをフォーマット
ここまでの作業でディスクイメージにパーティションを作成できましたが、まだ個々のパーティションにはファイルシステムが書かれていません。 個別のパーティションに対してmkfsを実行するための手順を説明します。
mkfsの対象とするためには、(ディスクイメージ全体ではなく)対象となるパーティションの部分を取り出す必要があります。
losetupの-oオプションを使用することで、ファイルの途中からをループバックデバイスに結びつけます。
先ほどの例では 開始位置が 63、Unit が 512 bytes だったので、パーティション#1のオフセットとして63*512=32256バイトを設定します。
# losetup -o 32256 /dev/loop0 FILENAME
losetupに成功したら、好みのファイルシステムを作成できます。
# mkfs.ext2 /dev/loop0
使いおわったらループバックデバイスを開放します。
# losetup -d /dev/loop0
イメージ内のパーティションに外からアクセス
既にファイルシステムが作られているイメージ(上記の手順で作成したものや、仮想環境で使っていたrawイメージなど)を扱う場合、 mountの"loop"オプションを使用することで、イメージ内部のパーティションを直接ホスト環境にマウントすることができます。
この例の場合、loopのoffsetに開始位置(32256)を指定する:
# mount -o loop,offset=32256 FILENAME /mnt/
と、/mnt経由で先ほど作成したパーティションの内容を操作することができるようになります。
作業が終わったら通常のmountと同じように
# umount /mnt/
します。