Mac OS X 10.x (Server) for VirtualBox on Mac

2013/12/11新規 | 2013/12/18更新 | 2013/12/21更新 | 2013/12/25更新 | 2014/10/24更新
Back

Contents

はじめに

Mac OS X Server Leopard (Server) 以降、Mac 実機での VirtualBox の Mac OS X 仮想化は、可能だと言われているが、実機への依存性などでその実現性は困難な場合がある。

ここでは、ひとつ MacBook Pro (15-inch, Late 2011) で以下の Mac OS X 仮想化を試みた備忘録を残しておく。

ところで、筆者のこの試みの動機は、開発物の過去の OS のバージョンでの動作確認が主な目的であり、新旧の Mac OS X を比べてみて初めて学ぶことも多い。だからと言って、実機を名残惜しく古いバージョンの OS のまま使っていくのも勿体ない。であるならば、古いバージョンの OS とその個人の資源は、仮想化された Mac OS X に追いやってしまいつつ、いつでも触れるようにしておければ、実機のホスト OS はなるべく最新バージョンの OS で事足りるであろう、というのがここでの主目的である。

では、できるだけ古い Mac OS X 10.5 Leopard (Server) を実機 MacBook Pro, Lion で VirtualBox にインストールする方法を紹介する。ちなみに、VirtualBox のマシンの設定は、結果的に VirtualBox の規定値で構わない(但し、実運用の段階では、VirtualBox ネットワーキングの規定値が「NAT」なので、OS X のソフトウェア・アップデートで NAT が多段であると「信用できないネットワーク」として App Store 等に接続できない可能性があるので、ネットワーク設定のアダプタ1は「ブリッジ」にしておいた方が良いかもしれない。そして、アダプタ2に「NAT」を加えると良いだろう)。

しかし、その前に、現時点では未成功な Mac OS X 10.4 Tiger (Server) を実機 MacBook Pro で VirtualBox にインストールする試みを紹介する。

Mac OS X 10.4 Tiger (Server) for VirtualBox on Mac

実機に付属の「Mac OS X Install Disc 1」のイメージそのままでは起動せず、以下のような状態で停滞する。

カーネルパニックなので、期待を込めて次節の方法でビルドした最新のカーネルに差し替えたところ、以下のように状況に変化があった。

なんか大変そうなので、ここまでで諦めた。

現時点で失敗しているが、インストール Disc のディスクイメージを作成する為のシェルスクリプトを以下に紹介しておく。

tiger-mk-install-dmg_for-vm.sh
#!/bin/bash
echo_eval(){
  echo "$@"
  eval "$@"
}

T="./tiger_for-vm"	&&
C="$T/../tiger/i386"	&&
V='/Volumes'	&&
D="$V/Mac OS X Install Disc 1"	&&

kextcache_no_authenticate='-z'	&&
kextcache_arch_flags='-a i386'	&&
#kextcache_verbose_flags='-v 0'	&&
kextcache_volume_root="-volume-root '$D'"	&&

if :; then
echo_eval hdiutil convert -format UDRW -ov -o "'$T/InstallDisc1 rw.dmg'" "'$C/Mac OS X Install Disc 1.dmg'"	&&
size=$(hdiutil resize -limits "$C/Mac OS X Install Disc 1.dmg" | tail -n 1 | cut -f 1)	&&
size=$(($size + 2**18))	&&
echo_eval hdiutil resize -sectors "$size" "'$T/InstallDisc1 rw.dmg'"	&&
:
fi	&&
echo_eval hdiutil attach -owners on -nobrowse -mountpoint "'$D'" "'$T/InstallDisc1 rw.dmg'"	&&
{
if :; then
echo_eval sudo cp -p "'$T/used/mach_kernel.debug'" "'$D/mach_kernel'"	&&
echo_eval sudo chown -R root:wheel	"'$D/mach_kernel'"	&&
echo_eval sudo chflags hidden "'$D/mach_kernel'"	&&
:
fi	&&
:
}	&&
{
echo_eval sudo rm -f "'$D/kernelcache'*" "'$D/System/Library/Extensions.mkext'*"	;
}	&&
if :; then
echo_eval sudo kextcache $kextcache_verbose_flags $kextcache_no_authenticate $kextcache_arch_flags -mkext1 "'$D/System/Library/Extensions.mkext'" -K "'$D/mach_kernel'" $kextcache_volume_root -- "'$D/System/Library/Extensions'"	&&
{
echo_eval sudo test -f "'$D/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist~'"	||
echo_eval sudo mv "'$D/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist'" "'$D/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist~'"	&&
:
}	&&
sudo sed -e 's|^\([	 ]*function checkSupportedMachine(machineType){[	 ]*\)$|\1 return true;|' "$D/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist~" |
echo_eval sudo dd of="'$D/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist'"	&&
:
fi	&&
if :; then
echo_eval sudo dd of="'$D/Library/Preferences/SystemConfiguration/com.apple.Boot.plist'" <<'EOF'	&&
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Kernel</key>
	<string>mach_kernel</string>
	<key>Kernel Flags</key>
	<string>-v rd=disk1</string>
	<key>Timeout</key>
	<string>10</string>
</dict>
</plist>
EOF
:
fi	&&

echo_eval hdiutil detach "'$D'"	&&
echo_eval hdiutil convert -format UDZO -ov -o "'$T/InstallDisc1-for_vm.dmg'" "'$T/InstallDisc1 rw.dmg'"	&&

echo ok ||
echo ng

以上のシェルスクリプトは以下のように使用する。

$ ls tiger/i386/
Mac OS X Install Disc 1.dmg
$ mkdir tiger_for-vm
$ bash tiger-mk-install-dmg_for-vm.sh
	:
ok
$ ls tiger_for-vm/
InstallDisc1-for_vm.dmg

ここでは、「/System/Installation/Packages/OSInstall.mpkg/Contents/OSInstall.dist」のサポート対象マシンのチェックを無効化しつつ、「/Library/Preferences/SystemConfiguration/com.apple.Boot.plist」に「rd=disk1」を指定するようなインストーラ Disc のディスクイメージを作成している。

しかし、これでは動作しないので、今後の課題である。

Mac OS X 10.4 Tiger のカーネル再構築

この例のように、標準の mach_kernel では動作せず、ハックしたカーネルが必要になるので、カーネル再構築の為の /usr/local の整備とカーネル再構築をしておこう。

まずは、カーネル再構築の為の /usr/local の整備であるが、以降で説明する 10.5 Leopard のカーネル再構築の為の整備をそのまま流用したので、そちらを参照のこと。

そして、いよいよカーネルの再構築である。

10.4.11_i386_xnu-localhost-{prepare,build}.sh

そして、以上のシェルスクリプトを以下のように使えば、10.4.11_i386_xnu/xnu-1228.15.4/obj/RELEASE_*/mach_kernel にカーネル再構築がなされる。

$ ksh 10.4.11_i386_xnu-localhost-prepare.sh
$ cd 10.4.11_i386_xnu
$ ksh ../10.4.11_i386_xnu-localhost-build.sh

Mac OS X 10.5 Leopard (Server) for VirtualBox on Mac

購入した「Mac OS X Install DVD」のイメージそのままでは起動せず、以下のような状態で停滞する。

カーネルパニックの原因が「AppleIntelCPUPowerManagement」とあることから、ネット情報と照らし合わせて、「AppleIntelCPUPowerManagement.kext」というカーネル拡張が起動を妨げているらしい。

そこで、後述するが、インストール DVD のディスクイメージを作成するにあたり、「AppleIntelCPUPowerManagement.kext」を消しておくと、次のように多少状況が変化した。

ここで手掛かりは「Still waiting for root device」であるので、ネット情報によるといろいろあるのだが、結論としてはインストール DVD の「/Library/Preferences/SystemConfiguration/com.apple.Boot.plist」にて、カーネルフラッグ「rd=disk1」を指定すれば、インストーラが無事起動することがわかった。

よって、インストーラの起動とともに、インストーラのインストールが上記に整合的であるようなインストール DVD のディスクイメージを作成するには、以下のようなスクリプトで実現でき、インストーラが起動する。

leopard-mk-install-dmg_for-vm.sh
#!/bin/bash
echo_eval(){
  echo "$@"
  eval "$@"
}

T="./leopard_for-vm"	&&
C="$T/../leopard"	&&
V='/Volumes'	&&
D="$V/Mac OS X Install DVD"	&&

kextcache_no_authenticate='-z'	&&
kextcache_arch_flags='-a i386 -a x86_64'	&&
#kextcache_verbose_flags='-v 0'	&&
kextcache_volume_root="-volume-root '$D'"	&&

echo_eval hdiutil convert -format UDRW -ov -o "'$T/InstallDVD rw.dmg'" "'$C/Mac OS X Install DVD.cdr'"	&&
size=$(hdiutil resize -limits "$C/Mac OS X Install DVD.cdr" | tail -n 1 | cut -f 1)	&&
size=$(($size + 2**18))	&&
echo_eval hdiutil resize -sectors "$size" "'$T/InstallDVD rw.dmg'"	&&
echo_eval hdiutil attach -owners on -nobrowse -mountpoint "'$D'" "'$T/InstallDVD rw.dmg'"	&&
{
echo_eval sudo rm -rf "'$D/System/Library/Extensions/AppleIntelCPUPowerManagement.kext'"	;
}	&&
{
echo_eval sudo rm -f "'$D/kernelcache'" "'$D/System/Library/Extensions.mkext'"	;
}	&&
echo_eval sudo kextcache $kextcache_verbose_flags $kextcache_no_authenticate $kextcache_arch_flags -mkext1 "'$D/System/Library/Extensions.mkext'" -K "'$D/mach_kernel'" $kextcache_volume_root -- "'$D/System/Library/Extensions'"	&&
{
echo_eval rm -rf "'$T/OSInstall'"	;
}	&&
echo_eval pkgutil --expand "'$D/System/Installation/Packages/OSInstall.pkg'" "'$T/OSInstall'"	&&
echo_eval touch "'$T/OSInstall/Scripts/postinstall_actions/kext.tool'"	&&
echo_eval chmod a+x "'$T/OSInstall/Scripts/postinstall_actions/kext.tool'"	&&
echo_eval dd of="'$T/OSInstall/Scripts/postinstall_actions/kext.tool'" <<'EOF'	&&
#!/bin/sh

logger -p install.info 'Uninstalling AppleIntelCPUPowerManagement.kext'
/bin/rm -rf "$3/System/Library/Extensions/AppleIntelCPUPowerManagement.kext"

exit 0
EOF
echo_eval sudo pkgutil --flatten "'$T/OSInstall'" "'$D/System/Installation/Packages/OSInstall.pkg'"	&&

echo_eval sudo dd of="'$D/Library/Preferences/SystemConfiguration/com.apple.Boot.plist'" <<'EOF'	&&
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Kernel</key>
	<string>mach_kernel</string>
	<key>Kernel Flags</key>
	<string>-v rd=disk1</string>
	<key>Timeout</key>
	<string>10</string>
</dict>
</plist>
EOF

echo_eval hdiutil detach "'$D'"	&&
echo_eval hdiutil convert -format UDZO -ov -o "'$T/InstallDVD.dmg'" "'$T/InstallDVD rw.dmg'"	&&

echo ok ||
echo ng

以上のシェルスクリプトは以下のように使用する。

$ ls leopard
Mac OS X Install DVD.cdr
$ mkdir leopard_for-vm
$ bash leopard-mk-install-dmg_for-vm.sh
	:
ok
$ ls leopard_for-vm/
InstallDVD.dmg

つまりここで、「/System/Library/Extensions/AppleIntelCPUPowerManagement.kext」を削除しつつ(「OSInstall.pkg」でもそれを削除しつつ)、「/Library/Preferences/SystemConfiguration/com.apple.Boot.plist」に「rd=disk1」を指定するようなインストーラ DVD のディスクイメージを作成している。

ここまで成功すれば、インストールは実機と同様に行えばよい。

Mac OS X 10.5 Leopard のカーネル再構築

この場合、標準の mach_kernel で事足りたが、本家カーネルが更新され VirtualBox がそれに対応してなかったりすれば自前でカーネルを再構築しなければならないかもしれない。それに備えて、カーネル再構築の為の /usr/local の整備とカーネル再構築をしておこう。

まずは、カーネル再構築の為の /usr/local の整備である。

10.5.8_ppc+x86_xnu_stage_00-localhost-{prepare,build,install}.sh
10.5.8_ppc+x86_xnu_stage_01-localhost-{prepare,build,install}.sh

以上のシェルスクリプトはを下のように使えば、/usr/local にカーネル再構築の為のツール群が整備される。

$ ksh 10.5.8_ppc+x86_xnu_stage_00-localhost-prepare.sh
$ cd 10.5.8_ppc+x86_xnu_stage_00
$ ksh ../10.5.8_ppc+x86_xnu_stage_00-localhost-build.sh
$ sudo ksh ../10.5.8_ppc+x86_xnu_stage_00-localhost-install.sh
$ ksh 10.5.8_ppc+x86_xnu_stage_01-localhost-prepare.sh
$ cd 10.5.8_ppc+x86_xnu_stage_01
$ ksh ../10.5.8_ppc+x86_xnu_stage_01-localhost-build.sh
$ sudo ksh ../10.5.8_ppc+x86_xnu_stage_01-localhost-install.sh

上記が成功すれば、いよいよカーネルの再構築である。

10.5.8_ppc+x86_xnu-localhost-{prepare,build}.sh

そして、以上のシェルスクリプトを以下のように使えば、10.5.8_ppc+x86_xnu/xnu-1228.15.4/obj/RELEASE_*/mach_kernel にカーネル再構築がなされる。

$ ksh 10.5.8_ppc+x86_xnu-localhost-prepare.sh
$ cd 10.5.8_ppc+x86_xnu
$ ksh ../10.5.8_ppc+x86_xnu-localhost-build.sh

最後に、ユニバーサルバイナリを作成するには以下のようにすればよい。

$ lipo -create 10.5.8_ppc+x86_xnu/xnu-1228.15.4/obj/RELEASE_PPC/mach_kernel 10.5.8_ppc+x86_xnu/xnu-1228.15.4/obj/RELEASE_I386/mach_kernel -o mach_kernel

Mac OS X 10.6 Snow Leopard (Server) for VirtualBox on Mac

購入した「Mac OS X Install DVD」のイメージそのままでは起動せず、以下のように緊急停止する。

これは全く手掛かりがなく困ったが、結局カーネル拡張ではなく、カーネルそのものと私の実機のマイクロアーキテクチャとの相性に問題があることが結論だった。

よって、ivy bridge に対応した mach_kernel (参考文献[2])に差し替えた DVD を作成すると緊急停止は避けることが出来たが、先の「Still waiting for root device」の問題は残されており、同様の対処が必要だった。

結局、以上の不具合と、インストーラのインストールが上記に整合的であるようなインストール DVD のディスクイメージを作成するには、以下のようなスクリプトで実現でき、インストーラが起動する。

snow-leopard-mk-install-dmg_for-vm.sh
#!/bin/bash
echo_eval(){
  echo "$@"
  eval "$@"
}

T="./snow-leopard_for-vm"	&&
C="$T/../snow-leopard"	&&
V='/Volumes'	&&
D="$V/Mac OS X Install DVD"	&&

kextcache_no_authenticate='-z'	&&
kextcache_arch_flags='-a i386 -a x86_64'	&&
#kextcache_verbose_flags='-v 0'	&&
kextcache_volume_root="-volume-root '$D'"	&&

echo_eval hdiutil convert -format UDRW -ov -o "'$T/InstallDVD rw.dmg'" "'$C/Mac OS X Install DVD.cdr'"	&&
size=$(hdiutil resize -limits "$T/InstallDVD rw.dmg" | tail -n 1 | cut -f 1)	&&
size=$(($size + 2**18))	&&
echo_eval hdiutil resize -sectors "$size" "'$T/InstallDVD rw.dmg'"	&&
echo_eval hdiutil attach -owners on -nobrowse -mountpoint "'$D'" "'$T/InstallDVD rw.dmg'"	&&
{
echo_eval sudo cp -fp "'$T/used/mach_kernel'" "'$D/mach_kernel'"	;
}	&&
echo_eval sudo chflags hidden "'$D/mach_kernel'"	&&
{
echo_eval sudo rm -f "'$D/kernelcache'" "'$D/System/Library/Extensions.mkext'"	;
}	&&
echo_eval sudo /usr/sbin/kextcache $kextcache_verbose_flags $kextcache_no_authenticate $kextcache_arch_flags -c "'$D/kernelcache'" -K "'$D/mach_kernel'" -mkext2 "'$D/System/Library/Extensions.mkext'" $kextcache_volume_root -- "'$D/System/Library/Extensions'"	&&
echo_eval sudo chflags hidden "'$D/kernelcache'"	&&
{
echo_eval rm -rf "'$T/OSInstall'"	;
}	&&
echo_eval pkgutil --expand "'$D/System/Installation/Packages/OSInstall.pkg'" "'$T/OSInstall'"	&&
echo_eval touch "'$T/OSInstall/Scripts/postinstall_actions/kext.tool'"	&&
echo_eval chmod a+x "'$T/OSInstall/Scripts/postinstall_actions/kext.tool'"	&&
echo_eval dd of="'$T/OSInstall/Scripts/postinstall_actions/kext.tool'" <<'EOF'	&&
#!/bin/sh

logger -p install.info 'Installing mach_kernel'
/bin/cp -fp -R '/mach_kernel' "$3/mach_kernel"

exit 0
EOF
echo_eval sudo pkgutil --flatten "'$T/OSInstall'" "'$D/System/Installation/Packages/OSInstall.pkg'"	&&

echo_eval sudo dd of="'$D/Library/Preferences/SystemConfiguration/com.apple.Boot.plist'" <<'EOF'	&&
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Kernel</key>
	<string>mach_kernel</string>
	<key>Kernel Flags</key>
	<string>-v rd=disk1</string>
	<key>Timeout</key>
	<string>10</string>
</dict>
</plist>
EOF

echo_eval hdiutil detach "'$D'"	&&
echo_eval hdiutil convert -format UDZO -ov -o "'$T/InstallDVD.dmg'" "'$T/InstallDVD rw.dmg'"	&&

echo ok ||
echo ng

以上のシェルスクリプトは以下のように使用する。

$ ls snow-leopard
Mac OS X Install DVD.cdr
$ ls snow-leopard_for-vm/used/
mach_kernel
$ bash snow-leopard-mk-install-dmg_for-vm.sh
	:
ok
$ ls snow-leopard_for-vm/
InstallDVD.dmg

つまりここで、新しい「mach_kernel」を複製しつつ(「OSInstall.pkg」でもそれを複製しつつ)、「/Library/Preferences/SystemConfiguration/com.apple.Boot.plist」に「rd=disk1」を指定するようなインストーラ DVD のディスクイメージを作成している。

ここまで成功すれば、インストールは実機と同様に行なえばよい。

Mac OS X 10.6 Snow Leopard のカーネル再構築

この例のように、標準の mach_kernel では動作せず、たまたまビルド済みのバイナリがあるのでそれを取得すれば事足りたが、本家カーネルが更新されたりすれば自前でカーネルを再構築しなければならないかもしれない。それに備えて、カーネル再構築の為の /usr/local の整備とカーネル再構築をしておこう。

まずは、カーネル再構築の為の /usr/local の整備である。

10.6.8_x86_xnu_stage_00-localhost-{prepare,build,install}.sh
10.6.8_x86_xnu_stage_01-localhost-{prepare,build,install}.sh

以上のシェルスクリプトはを下のように使えば、/usr/local にカーネル再構築の為のツール群が整備される。

$ ksh 10.6.8_x86_xnu_stage_00-localhost-prepare.sh
$ cd 10.6.8_x86_xnu_stage_00
$ ksh ../10.6.8_x86_xnu_stage_00-localhost-build.sh
$ sudo ksh ../10.6.8_x86_xnu_stage_00-localhost-install.sh
$ ksh 10.6.8_x86_xnu_stage_01-localhost-prepare.sh
$ cd 10.6.8_x86_xnu_stage_01
$ ksh ../10.6.8_x86_xnu_stage_01-localhost-build.sh
$ sudo ksh ../10.6.8_x86_xnu_stage_01-localhost-install.sh

上記が成功すれば、いよいよカーネルの再構築である。

10.6.8_x86_xnu-localhost-{prepare,build}.sh

そして、以上のシェルスクリプトを以下のように使えば、10.6.8_x86_xnu/xnu-1504.15.3/obj/RELEASE_*/mach_kernel にカーネル再構築がなされる。

$ ksh 10.6.8_x86_xnu-localhost-prepare.sh
$ cd 10.6.8_x86_xnu
$ ksh ../10.6.8_x86_xnu-localhost-build.sh

最後に、ユニバーサルバイナリを作成するには以下のようにすればよい。

$ lipo -create 10.6.8_x86_xnu/xnu-1504.15.3/obj/RELEASE_I386/mach_kernel 10.6.8_x86_xnu/xnu-1504.15.3/obj/RELEASE_X86_64/mach_kernel -o mach_kernel

Mac OS X 10.7 Lion (Server) for VirtualBox on Mac

購入した「Mac OS X Install ESD」のイメージ「InstallESD.dmg」そのままで起動し、そのままインストーラが起動するはずである。

Mac OS X 10.7 Lion のカーネル再構築

この場合、標準の mach_kernel で事足りたが、本家カーネルが更新され VirtualBox がそれに対応してなかったりすれば自前でカーネルを再構築しなければならないかもしれない。それに備えて、カーネル再構築の為の /usr/local の整備とカーネル再構築をしておこう。

まずは、カーネル再構築の為の /usr/local の整備である。

10.7.5_x86_xnu_stage_00-localhost-{prepare,build,install}.sh

以上のシェルスクリプトはを下のように使えば、/usr/local にカーネル再構築の為のツール群が整備される。

$ ksh 10.7.5_x86_xnu_stage_00-localhost-prepare.sh
$ cd 10.7.5_x86_xnu_stage_00
$ ksh ../10.7.5_x86_xnu_stage_00-localhost-build.sh
$ sudo ksh ../10.7.5_x86_xnu_stage_00-localhost-install.sh

上記が成功すれば、いよいよカーネルの再構築である。

10.7.5_x86_xnu-localhost-{prepare,build}.sh

そして、以上のシェルスクリプトを以下のように使えば、10.7.5_x86_xnu/xnu-1504.15.3/obj/RELEASE_*/mach_kernel にカーネル再構築がなされる。

$ ksh 10.7.5_x86_xnu-localhost-prepare.sh
$ cd 10.7.5_x86_xnu
$ ksh ../10.7.5_x86_xnu-localhost-build.sh

最後に、ユニバーサルバイナリを作成するには以下のようにすればよい。

$ lipo -create 10.7.5_x86_xnu/xnu-1504.15.3/obj/RELEASE_I386/mach_kernel 10.7.5_x86_xnu/xnu-1504.15.3/obj/RELEASE_X86_64/mach_kernel -o mach_kernel

Mac OS X 10.8 Mountain Lion (Server) for VirtualBox on Mac

購入した「OS X Install ESD」のイメージ「InstallESD.dmg」そのままで起動し、そのままインストーラが起動するはずである。

Mac OS X 10.9 Mavericks (Server) for VirtualBox on Mac

ダウンロードした「Install OS X Mavericks.app」内にある「Contents/Resources/createinstallmedia」は USB メモリ等のデバイスにインストーラ ESD を作成するプログラムなので、それを経由してそのディスクイメージを作成することも可能だが、ここでは別の方法を採ろう。

ダウンロードした「Install OS X Mavericks.app」内にあるイメージ「Contents/SharedSupport/InstallESD.dmg」そのままでは起動しない。よって、以下のシェルスクリプトでインストーラ ESD のディスクイメージを作成する。

mavericks-mk-install-dmg_for-vm.sh
#!/bin/bash
echo_eval(){
  echo "$@"
  eval "$@"
}

T="./mavericks_for-vm"	&&
C="$T/../mavericks"	&&
V='/Volumes'	&&
D="$V/OS X Install ESD"	&&
B="$V/OS X Base System"	&&

echo_eval hdiutil attach -nobrowse -noverify -mountpoint "'$D'" "'$C/Install OS X Mavericks.app/Contents/SharedSupport/InstallESD.dmg'"	&&
echo_eval hdiutil convert -format UDRW -ov -o "'$T/BaseSystem rw.dmg'" "'$D/BaseSystem.dmg'"	&&
size=$(hdiutil resize -limits "$C/Install OS X Mavericks.app/Contents/SharedSupport/InstallESD.dmg" | tail -n 1 | cut -f 1)	&&
size="$size +"$(hdiutil resize -limits "$D/BaseSystem.dmg" | tail -n 1 | cut -f 1)	&&
size=$(($size))	&&
echo_eval hdiutil resize -sectors "$size" "'$T/BaseSystem rw.dmg'"	&&
echo_eval hdiutil attach -owners on -nobrowse -mountpoint "'$B'" "'$T/BaseSystem rw.dmg'"	&&

echo_eval sudo rm -f "'$B/System/Installation/Packages'"	&&
echo_eval sudo cp -fp -R "'$D/Packages'" "'$B/System/Installation/Packages'"	&&

echo_eval hdiutil detach "'$D'"	&&
echo_eval hdiutil detach "'$B'"	&&
echo_eval hdiutil convert -format UDZO -ov -o "'$T/InstallESD.dmg'" "'$T/BaseSystem rw.dmg'"	&&
echo ok	||
echo ng

以上のシェルスクリプトは以下のように使用する。

$ ls mavericks/'Install OS X Mavericks.app'/Contents/SharedSupport/InstallESD.dmg 
mavericks/Install OS X Mavericks.app/Contents/SharedSupport/InstallESD.dmg
$ mkdir mavericks_for-vm
$ bash mavericks-mk-install-dmg_for-vm.sh
	:
ok
$ ls mavericks_for-vm/
InstallESD.dmg

つまりここで、「InstallESD.dmg」内の「BaseSystem.dmg」をベースとしつつ、その System/Installation/Packages を「InstallESD.dmg」内の Package に置き換えたインストーラ ESD のディスクイメージを作成している。

ここまで成功すれば、インストールは実機と同様に行なえばよい。

つづく。。。

Mac OS X 10.9 Yosemite (Server) for VirtualBox on Mac

ダウンロードした「Install OS X Yosemite.app」内にある「Contents/Resources/createinstallmedia」は USB メモリ等のデバイスにインストーラ ESD を作成するプログラムなので、それを経由してそのディスクイメージを作成することも可能だが、ここでは別の方法を採ろう。

ダウンロードした「Install OS X Yosemite.app」内にあるイメージ「Contents/SharedSupport/InstallESD.dmg」そのままでは起動しない。よって、以下のシェルスクリプトでインストーラ ESD のディスクイメージを作成する。

yosemite-mk-install-dmg_for-vm.sh
#!/bin/bash
echo_eval(){
  echo "$@"
  eval "$@"
}

T="./yosemite_for-vm"	&&
C="$T/../yosemite"	&&
V='/Volumes'	&&
D="$V/OS X Install ESD"	&&
B="$V/OS X Base System"	&&

echo_eval hdiutil attach -nobrowse -noverify -mountpoint "'$D'" "'$C/Install OS X Yosemite.app/Contents/SharedSupport/InstallESD.dmg'"	&&
echo_eval hdiutil convert -format UDRW -ov -o "'$T/BaseSystem rw.dmg'" "'$D/BaseSystem.dmg'"	&&
size=$(hdiutil resize -limits "$C/Install OS X Yosemite.app/Contents/SharedSupport/InstallESD.dmg" | tail -n 1 | cut -f 1)	&&
size="$size +"$(hdiutil resize -limits "$D/BaseSystem.dmg" | tail -n 1 | cut -f 1)	&&
size=$(($size))	&&
echo_eval hdiutil resize -sectors "$size" "'$T/BaseSystem rw.dmg'"	&&
echo_eval hdiutil attach -owners on -nobrowse -mountpoint "'$B'" "'$T/BaseSystem rw.dmg'"	&&

echo_eval sudo rm -f "'$B/System/Installation/Packages'"	&&
echo_eval sudo cp -fp -R "'$D/Packages'" "'$B/System/Installation/Packages'"	&&
echo_eval sudo cp -fp "'$D'"/BaseSystem.* "'$B'"/	&&

echo_eval hdiutil detach "'$D'"	&&
echo_eval hdiutil detach "'$B'"	&&
echo_eval hdiutil convert -format UDZO -ov -o "'$T/InstallESD.dmg'" "'$T/BaseSystem rw.dmg'"	&&
echo ok	||
echo ng

以上のシェルスクリプトは以下のように使用する。

$ ls yosemite/'Install OS X Yosemite.app'/Contents/SharedSupport/InstallESD.dmg 
yosemite/Install OS X Yosemite.app/Contents/SharedSupport/InstallESD.dmg
$ mkdir yosemite_for-vm
$ bash yosemite-mk-install-dmg_for-vm.sh
	:
ok
$ ls yosemite_for-vm/
InstallESD.dmg

つまりここで、「InstallESD.dmg」内の「BaseSystem.dmg」をベースとしつつ、その System/Installation/Packages を「InstallESD.dmg」内の Package に置き換えたインストーラ ESD のディスクイメージを作成している。

ここまで成功すれば、インストールは実機と同様に行なえばよい。

つづく。。。

補遺

実機の HDD/SDXC/SSD からディスクイメージへ変換・逆変換

実機の HDD/SDXC/SSD のデバイスのスライスの識別子を「/dev/diskXs2」だとして、そのディスクイメージを包有する VirtualBox の CD/DVD イメージとして割り当て可能なディスクイメージを作成するには、以下のようにすればよい。

$ mkdir 'Macintosh SD.dmg In'
$ hdiutil convert /dev/diskXs2 -format UDBZ -o 'Macintosh SD.dmg In/Macintosh SD.dmg'
$ hdiutil create -size $(($(du -gs 'Macintosh SD.dmg In' | cut -f 1)+1))g -srcfolder 'Macintosh SD.dmg In' 'Macintosh SD.dmg In.dmg'

dd if=/dev/diskX bs=$((1024*1024)) | VBoxManage convertfromraw stdin '/path_to/Macintosh SD.vdi' $((64*1024*1024*1024))」なども可能であるが、VDI が実サイズになってしまうので上記を採用している。しかし、これだと非常に時間が掛かる上に、同じ大容量のイメージを二つもつことになってしまうので、相当無駄である。よって、次節のように直接 HDD のデバイスを VirtualBox から読み書きできるようにすれば、その問題は回避できる。逆に、VirtualBox ディスクイメージから実機の HDD/SDXC/SSD へ変換するには、実機の HDD/SDXC/SSD のデバイスの識別子を「/dev/diskX」だとして、以下のようにすればよい。

$ export PATH="/Applications/VirtualBox.app/Contents/MacOS:$PATH"
$ VBoxManage clonehd '/path_to/Macintosh SD.vdi' 'Macintosh SD.raw' --format RAW
$ hdiutil unmount /dev/diskXs2 && dd if='/path_to/Macintosh SD.raw' of=/dev/diskX

但し、パーティションの一部を選んで書き戻すのは、これでは出来ないようだ。しかし、やはりこれも非常に時間が掛かる上に、圧縮されない生のストレージデータがファイルとして必要となり、ホストコンピュータのストレージ容量を圧迫せざるを得ない。よって、やはり次節のように直接 HDD のデバイスを VirtualBox から読み書きできるようにすれば、その問題は回避できる。

実機の HDD/SDXC/SSD を VirtualBox から直接利用

実機の HDD/SDXC/SSD のデバイスの識別子を「/dev/diskX」だとして、それを VirtualBox から直接読み書きするには、以下のようにすればよい。

$ export PATH="/Applications/VirtualBox.app/Contents/MacOS:$PATH"
$ hdiutil unmount /dev/diskXs2 && VBoxManage internalcommands createrawvmdk -filename '/path_to/Macintosh SD.vmdk' -rawdisk /dev/diskX

また、パーティションの一部を指定することも可能であるらしい。

$ VBoxManage internalcommands listpartitions -rawdisk /dev/diskX
$ VBoxManage internalcommands createrawvmdk -filename '/path_to/Macintosh SD.vmdk' -rawdisk /dev/diskX -partitions 2

注意すべきは、SD カードなどで書き込み禁止にしたいところがそれは出来ないので、しかも、こうした場合ボリューム名も同一であることが往々にしてあるので、ディスクユーティリティ等でどちらがソースと復元先か注意が必要であることである。また、用事が終わったら、VirtualBox メニューの「ファイル」「仮想メディアマネージャ」で解放&除去をしておいた方が安心だろう。但し、USB ストレージであるなら VirtualBox の USB 2.0 コントローラでリムーバブルメディアとして使えるので、転送速度が気にならないのであれば、こちらの方が便利であろう。

VirtualBox ネットワーキング

NAT

VirtualBox のネットワーキングの NAT モードは規定値で以下のようになる。

gateway:	10.0.2.2
nameserver:	10.0.2.3
host:		10.0.2.4
dhcp-client:	10.0.2.15 〜 10.0.2.254

さて、ゲストからホストへの ssh は可能である。

localguest:~$ slogin 10.0.2.4

しかし、ホストからゲストへの ssh はそのままでは不可能だ。そこで、NAT ポートフォワーディングの設定を行う。


そして、以下のように ssh が可能となる。

localhost:~$ slogin -p 8822 localhost

ブリッジ

VirtualBox のネットワーキングのブリッジモードは、ホストのネットワークインターフェースに従う。NAT のようにポートフォワーディングせずともホストとゲスト間で直接通信できるのだが、欠点は、ホストがオフラインだとホストとゲスト間の通信さえも出来なくなってしまうことである。

ともあれ、ホスト・ゲスト相互がサブネットのネットワーキングになるので、Bonjour サービスがそのまま相互に受けられるのは嬉しい。

localhost:~$ slogin localguest.local

OS X バージョン表

OS X のバージョンと対応している各種バージョンや、インストーラそしてインストール先の HDD のサイズ等を表にまとめておく。

Xcode バージョン表

Xcode のバージョンと対応しているビルドターゲット OS X バージョン等を表にまとめておく。

時刻合わせ

仮想マシンで注意すべきは、ホストのスリープからの復帰時や、ゲストの状態保存からの復帰時に、ゲストの時計が遅れていることである。

オンラインであれば、ntp サーバとの時刻同期で事なきを得られるかも知れないが、オフラインのときには、ホストと時刻がずれたままになり、非常に好ましくない。せめてオフライン時も、ホストとの時刻同期はすべきである。以下のようにすればよい。

Ugazin:~ taiji$ sudo launchctl unload /System/Library/LaunchDaemons/org.ntp.ntpd.plist 
Ugazin:~ taiji$ sudo ntpdate kukunoti.local
24 Oct 13:19:22 ntpdate[175]: step time server 17.83.253.7 offset 2.186823 sec
Ugazin:~ taiji$ sudo launchctl load /System/Library/LaunchDaemons/org.ntp.ntpd.plist 

kukunoti.local がホストの名前であり、OS X 10.7 である。OS X 10.5-10.6, 10.9 のホストではそのままでは ntp サーバとはなっていないので、ひと工夫必要である。

スクリーンセーバー

仮想マシンで厄介なのは、不要なスクリーンセーバーが起動してしまい、余分な CPU 資源を浪費することである。以下、それぞれの Mac OS X バージョンでのスクリーンセーバーの軽量化と無効化の設定を記しておく。

OS X 10.5 におけるスクリーンセーバーの設定

Ugazin:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    idleTime = 300;
    moduleName = Flurry;
    modulePath = "/System/Library/Screen Savers/Flurry.saver";
}
Ugazin:~ taiji$ defaults -currentHost write com.apple.screensaver idleTime 0
Ugazin:~ taiji$ defaults -currentHost write com.apple.screensaver moduleName "Computer Name"
Ugazin:~ taiji$ defaults -currentHost write com.apple.screensaver modulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Ugazin:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    idleTime = 0;
    moduleName = "Computer Name";
    modulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
}
Ugazin:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    idleTime = 300;
    moduleName = Flurry;
    modulePath = "/System/Library/Screen Savers/Flurry.saver";
}
Ugazin:~ taiji$ sudo defaults -currentHost write com.apple.screensaver idleTime 0
Ugazin:~ taiji$ sudo defaults -currentHost write com.apple.screensaver moduleName "Computer Name"
Ugazin:~ taiji$ sudo defaults -currentHost write com.apple.screensaver modulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Ugazin:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    idleTime = 0;
    moduleName = "Computer Name";
    modulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
}

OS X 10.6 におけるスクリーンセーバーの設定

Yagami:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    PrefsVersion = 100;
    idleTime = 300;
    moduleDict =     {
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Yagami:~ taiji$ defaults -currentHost write com.apple.screensaver CleanExit -bool YES
Yagami:~ taiji$ defaults -currentHost write com.apple.screensaver idleTime 0
Yagami:~ taiji$ defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Yagami:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    CleanExit = YES;
    PrefsVersion = 100;
    idleTime = 0;
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}
Yagami:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver       
{
    moduleDict =     {
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Yagami:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0
Yagami:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowModulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Yagami:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver idleTime 0
Yagami:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Yagami:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    idleTime = 0;
    loginWindowIdleTime = 0;
    loginWindowModulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}

OS X 10.7 におけるスクリーンセーバーの設定

Kusimati:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    PrefsVersion = 100;
    idleTime = 300;
    moduleDict =     {
        moduleName = Random;
        path = "/System/Library/Screen Savers/Random.saver";
        type = 8;
    };
}
Kusimati:~ taiji$ defaults -currentHost write com.apple.screensaver CleanExit -bool YES
Kusimati:~ taiji$ defaults -currentHost write com.apple.screensaver idleTime 0
Kusimati:~ taiji$ defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Kusimati:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    CleanExit = YES;
    PrefsVersion = 100;
    idleTime = 0;
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}
Kusimati:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    moduleDict =     {
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Kusimati:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0
Kusimati:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowModulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Kusimati:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver idleTime 0
Kusimati:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Kusimati:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    idleTime = 0;
    loginWindowIdleTime = 0;
    loginWindowModulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}

OS X 10.8 におけるスクリーンセーバーの設定

Tikatoh:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    PrefsVersion = 100;
    idleTime = 300;
    moduleDict =     {
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Tikatoh:~ taiji$ defaults -currentHost write com.apple.screensaver CleanExit -bool YES
Tikatoh:~ taiji$ defaults -currentHost write com.apple.screensaver idleTime 0
Tikatoh:~ taiji$ defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Tikatoh:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    CleanExit = YES;
    PrefsVersion = 100;
    idleTime = 0;
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}
Tikatoh:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    moduleDict =     {
        displayName = Flurry;
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Tikatoh:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0
Tikatoh:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowModulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Tikatoh:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver idleTime 0
Tikatoh:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Tikatoh:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    idleTime = 0;
    loginWindowIdleTime = 10;
    loginWindowModulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}

OS X 10.9 におけるスクリーンセーバーの設定

Hisatsu:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    PrefsVersion = 100;
    idleTime = 300;
    moduleDict =     {
        displayName = Flurry;
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Hisatsu:~ taiji$ defaults -currentHost write com.apple.screensaver CleanExit -bool YES
Hisatsu:~ taiji$ defaults -currentHost write com.apple.screensaver idleTime 0
Hisatsu:~ taiji$ defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Hisatsu:~ taiji$ defaults -currentHost read com.apple.screensaver
{
    CleanExit = YES;
    PrefsVersion = 100;
    idleTime = 0;
    moduleDict =     {
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}
Hisatsu:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    moduleDict =     {
        displayName = Flurry;
        moduleName = Flurry;
        path = "/System/Library/Screen Savers/Flurry.saver";
        type = 0;
    };
}
Hisatsu:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0
Hisatsu:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowModulePath "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver"
Hisatsu:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver idleTime 0
Hisatsu:~ taiji$ sudo defaults write /Library/Preferences/com.apple.screensaver moduleDict -dict displayName "Computer Name" moduleName "Computer Name" path "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver" type 0
Hisatsu:~ taiji$ defaults read /Library/Preferences/com.apple.screensaver
{
    idleTime = 0;
    loginWindowIdleTime = 0;
    loginWindowModulePath = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
    moduleDict =     {
        displayName = "Computer Name";
        moduleName = "Computer Name";
        path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/Computer Name.saver";
        type = 0;
    };
}

参考文献

  1. http://apple2pc.blogspot.jp/2008/05/still-waiting-for-root-device.html
  2. http://www.osx86.net/files/download/940-haswell-ivy-bridge-kernel-for-snow-leopard-10-6/
  3. http://mdboom.github.io/blog/2013/08/29/virtualbox-on-mac-os-x/
  4. http://www.projectosx.com/forum/index.php?showtopic=1141
Written by Taiji Yamada