QEMUのrawディスクイメージに関する覚え書きの追加
「QEMUのrawディスクイメージに関する覚え書き(後半)」でホストOSからハードディスクのrawイメージファイル内のパーティションにアクセスしているが、幾つかの内容を追加。
マウントとマウント解除を自動化
「QEMUのrawディスクイメージに関する覚え書き(後半)」の「rawイメージの中にアクセスする」でホストOSからrawディスクイメージ内のパーティションをマウントする作業は、開始位置やマウントポイント、LVMのボリュームグループや論理ボリューム名といった情報があれば決まった流れとなるため、中身にアクセスすることが多ければスクリプトで自動化してしまうと楽。
下のスクリプトを使用する場合、上のほうにある幾つかの変数を環境とディスクイメージの内容に合わせて設定して使う。
LVMを使用しない場合のスクリプト例
[任意]ファイル名: mount-rawdisk.sh
#! /bin/bash # rawファイル RAWFILE=~/image.raw # マウントしたいパーティションの情報 MOUNTPOINT=/media/rawdisk MOUNTOPT="-o ro,loop" #MOUNTOPT="-o loop" TYPE=ext2 # 「/sbin/fdisk -lu [デバイス名]」で見たときの開始位置を記述 START=63 if [[ ! -d "${MOUNTPOINT}" ]]; then zenity --error --title "マウントポイントが存在しません" --text "ディレクトリ \"${MOUNTPOINT}\" が 存在しないため、マウントすることができません" exit 1 fi start() { local loopdev=$(/sbin/losetup -f) if [[ ${?} -ne 0 ]]; then zenity --error --title "ループバックデバイスが使用できません" --text "使用できるループバックデバイスがないため イメージの中身にアクセスできません" exit 1 fi # fdiskを実行するために先頭から接続 sudo /sbin/losetup ${loopdev} "${RAWFILE}" # 単位の取得(512など) UNIT=$(LC_ALL=C /sbin/fdisk -lu ${loopdev} | awk '/Unit/ { print $7; }') # 切断 sudo /sbin/losetup -d ${loopdev} OFFSET=$((${START} * ${UNIT})) # マウント if ! sudo mount -t ${TYPE} ${MOUNTOPT},offset=${OFFSET} "${RAWFILE}" "${MOUNTPOINT}"; then zenity --error --title "マウント失敗" --text "マウントに失敗しました" exit 1 fi exit 0 } stop() { # マウント解除 if ! sudo umount "${MOUNTPOINT}"; then zenity --error --title "マウント解除失敗" --text "マウント解除に失敗しました" exit 1 fi } case "${1}" in start) start ;; stop) stop ;; *) echo "Usage: $(basename "${0}") {start|stop}" exit 1 esac
LVMを使用した場合のスクリプト例
[任意]ファイル名: mount-rawdisk-lvm.sh
#! /bin/bash # rawファイル RAWFILE=~/image.raw # マウントしたいパーティションの情報 LOGVOL=LogVol VOLGROUP=VolGroup MOUNTPOINT=/media/rawdisk MOUNTOPT="-o ro" #MOUNTOPT="" TYPE=ext3 # 「/sbin/fdisk -lu [デバイス名]」で見たときの開始位置を記述 START=208845 if [[ ! -d "${MOUNTPOINT}" ]]; then zenity --error --title "マウントポイントが存在しません" --text "ディレクトリ \"${MOUNTPOINT}\" が 存在しないため、マウントすることができません" exit 1 fi start() { local loopdev=$(/sbin/losetup -f) if [[ ${?} -ne 0 ]]; then zenity --error --title "ループバックデバイスが使用できません" --text "使用できるループバックデバイスがないため イメージの中身にアクセスできません" exit 1 fi # fdiskを実行するために先頭から接続 sudo /sbin/losetup ${loopdev} "${RAWFILE}" # 単位の取得(512など) UNIT=$(LC_ALL=C /sbin/fdisk -lu ${loopdev} | awk '/Unit/ { print $7; }') # 一旦切断 sudo /sbin/losetup -d ${loopdev} # 再び接続 loopdev=$(/sbin/losetup -f) if [[ ${?} -ne 0 ]]; then zenity --error --title "ループバックデバイスが使用できません" --text "ループバックデバイスが使用できないため イメージの中身にアクセスできません" exit 1 fi OFFSET=$((${START} * ${UNIT})) sudo /sbin/losetup -o ${OFFSET} ${loopdev} "${RAWFILE}" sudo /sbin/pvscan >/dev/null if ! sudo /sbin/lvscan | grep "/dev/${VOLGROUP}/${LOGVOL}" >/dev/null; then # 論理ボリュームが見つからない zenity --error --title "論理ボリュームが見つかりません" --text "デバイス \"/dev/${VOLGROUP}/${LOGVOL}\" が見つからないため、マウントできません" exit 1 fi # アクティブ化 sudo /sbin/lvchange -a y "/dev/${VOLGROUP}/${LOGVOL}" # マウント if ! sudo mount -t ${TYPE} ${MOUNTOPT} "/dev/${VOLGROUP}/${LOGVOL}" "${MOUNTPOINT}"; then zenity --error --title "マウント失敗" --text "マウントに失敗しました" exit 1 fi exit 0 } stop() { local loopdev=$(/sbin/losetup -a | grep ${RAWFILE} | awk -F : '{ print $1; }' | head -n 1) # マウント解除 if ! sudo umount "${MOUNTPOINT}"; then zenity --error --title "マウント解除失敗" --text "マウント解除に失敗しました" exit 1 fi # 非アクティブ化 sudo /sbin/lvchange -a n "/dev/${VOLGROUP}/${LOGVOL}" # ループバックデバイスとイメージを切断 sudo /sbin/losetup -d ${loopdev} } case "${1}" in start) start ;; stop) stop ;; *) echo "Usage: $(basename "${0}") {start|stop}" exit 1 esac
ホストOSからパーティションを操作することはできるか?
GPartedの引数に/dev/loop[番号]を渡して起動すると、ホストOS上でグラフィカルにパーティション構成を確認することはできるが
/dev/loop[番号]p[番号]というデバイスは/dev/以下には存在しないため、操作を行うと失敗することがある。
スワップパーティションを一度消して(これは成功)、同じ領域をスワップとして初期化しようとしたところ失敗した。
一方で、losetupでパーティションをoffset指定で接続して手動でmkswapした場合はどうなるかを実験したところ
$ LOOPDEV=$(/sbin/losetup -f); [[ ${?} -eq 0 ]] && sudo /sbin/losetup ${LOOPDEV} [rawファイル] $ /sbin/fdisk -lu ${LOOPDEV} Disk /dev/loop4: 6442 MB, 6442450944 bytes 255 heads, 63 sectors/track, 783 cylinders, total 12582912 sectors Units = セクタ数 of 1 * 512 = 512 bytes Disk identifier: 0x000836ef デバイス Boot Start End Blocks Id System /dev/loop4p1 * 63 11743514 5871726 83 Linux /dev/loop4p2 11743515 12578894 417690 5 拡張領域 /dev/loop4p5 11743578 12578894 417658+ 82 Linux swap / Solaris
このような構成で
$ /sbin/losetup -d ${LOOPDEV} $ LOOPDEV=$(/sbin/losetup -f); [[ ${?} -eq 0 ]] && sudo /sbin/losetup -o $((11743578 * 512)) ${LOOPDEV} [rawファイル]
5番のパーティションに接続後
$ sudo mkswap -L sw ${LOOPDEV} Setting up swapspace version 1, size = 429731 kB LABEL=sw, UUID=db5864ec-365c-4e85-9b44-c45de796f336 $ sudo /sbin/losetup -d ${LOOPDEV}; unset ${LOOPDEV}
スワップの初期化を行ったのだが、ゲストOS上で有効にしようとしたところ
guest# swapon /dev/sda5 swapon: /dev/sda5: Invalid argument
失敗してしまった。スワップの代わりにmkfs.ext2をこの領域に対して(/dev/loop[番号]に対して)実行したところ、ゲストOS上でマウントができ、データのやりとりもできた(作業内容は省略)。
しかし、このような作業は危険な上にメリットも少ないため、操作を確実に行いたいのであれば、ライブCDを使用して仮想マシン上で作業を行うのが無難。
関連記事: