カスタムDVDのISOファイルを作成する

ここからの作業はシェルスクリプト(mkudvd:Make Ubuntu DVD)にまとめておいた。*1 このシェルスクリプトを動かせばDVDのISOイメージが作成できる。このプログラム(“mkudvdプログラムリスト”にリストをおいてある)をコピー&ペーストしてファイルに落として実行すればいい。

# bash mkudvd

問題なく終了すれば作業用ディレクトリに ubuntu-8.10-desktop-amd64-custom.iso というISOファイルが出来上がる。

では、シェルスクリプト mkudvd の中ではどのようなことをしているのかを説明する。

パラメータ設定

今回はコマンドに引数などを持たせず、各種パラメータはハードコードにしてしまった。環境が違えばここを直せばいい。

################################################################################
# Parameter Settings

WORKING_DIR=/livedvd
ORIGINAL_CD_ISO="${WORKING_DIR}/ubuntu-8.10-desktop-i386.iso"
EXTENSION=custom

CUSTOM_DVD_ISO="${WORKING_DIR}/"`basename "${ORIGINAL_CD_ISO}" .iso`-${EXTENSION}.iso
TEMPLATE_ROOT="${WORKING_DIR}/filesystem"
MISC_FILES="${WORKING_DIR}/misc"
DVD_FILES="${WORKING_DIR}/live_dvd_files"
FS_TYPE=squashfs
REMOVE_999_ACCOUNT=1
  • WORKING_DIR

作業用ディレクトリへのパス。

  • ORIGINAL_CD_ISO

オリジナルCDのISOファイル。 ここでは“ubuntu-8.10-desktop-amd64.iso”で、これは先ほどの準備でコピーしておいたファイルとなる。

  • EXTENSION

これから作成するカスタムDVDのISOファイル名のための拡張文字列。

  • CUSTOM_DVD_ISO

これから作成するカスタムDVDのISOファイル。EXTENSIONが“custom”であれば“ubuntu-8.10-desktop-amd64-custom.iso”という名前のファイルが生成される。

  • TEMPLATE_ROOT

雛型ルートファイルシステムの格納されているディレクトリ。./filesystem (/livedvd/filesystem)とした。先程の準備で作成したディレクトリである。

  • MISC_FILES

casperによる起動前設定のためのプログラムとデータを格納しておく。./misc

  • DVD_FILES

オリジナルCDのファイルを展開する一時ディレクトリ。./live_dvd_files とした。

  • REMOVE_999_ACCOUNT

これは後程説明するが、雛型ルートファイルシステムを作成した際に作った“ubuntu”という名前のアカウント(uid=999)を残してライブDVDを作成するか、残さずにライブDVDを作成するかのフラグ。オリジナルのCDでは一般ユーザアカウントが一切含まれてない雛型を使っていて、ライブCDからLinuxを立ち上げる時に casper というソフトウェアが“ライブユーザ”つまり ubuntuのアカウントを自動的に生成する。その後、このプログラムで生成したDVDでは、ubuntuのホームディレクトリを復元する。従って、基本的には削除する(“1”を設定)にして使う。

    • “REMOVE_999_ACCOUNT=1”雛型を残さない場合
    • “REMOVE_999_ACCOUNT=” 雛型を残す場合

なお、DEBUGという変数もあるが、これもREMOVE_999_ACCOUNTと同様、有効する場合は“=1”、無効にする場合は“=”(何も値を代入しない)にする。

環境の確認

カスタムDVDを作成するのに必要な環境が揃っているかの確認。

################################################################################
# Check base files

	:
################################################################################
# Check utilities
	:

オリジナルCDをlive_dvd_filesディレクトリへ展開

################################################################################
echo "Copying original CD files"

	:
rsync -ax "${WORKING_DIR}/mnt/" "${DVD_FILES}/"

コピーにはrsyncを使っているので、再度コマンドを実行した場合は、修正があったファイルのみがコピーされ以前の状態に戻される。

ブートパラメータの調整

################################################################################
echo "Modifying boot menu parameter"

sed -i \
	-e 's/^timeout .*$/timeout 50/' \
	"${DVD_FILES}/isolinux/isolinux.cfg"

今回はブートして最初に現れる言語選択のメニューの表示時間を5秒にしてある(オリジナルでは30秒)。

雛型Linuxを整理する

いよいよ本格的な作業に入っていくが、まず、雛型LinuxをDVD作成へ向けて調整する。
先ずはrootとパスワードをチェックして必要であれば変更する。

################################################################################
echo "Triming base filesystem"

### Changing root password character

sed -i -e 's/^root:!:/root:*:/' "${TEMPLATE_ROOT}/etc/shadow"

Ubuntudebian?)の“/usr/lib/user-setup/functions.sh”にバグがある。このスクリプトの中のroot_passwordという関数の中でrootのパスワードをshadowファイルから拾う部分がある。

	if [ -e $ROOT/etc/shadow ] && \
	   [ "`grep ^root: $ROOT/etc/shadow | cut -d : -f 2`" ] && \
	   [ "`grep ^root: $ROOT/etc/shadow | cut -d : -f 2`" != '*' ]; then
		return 0
	fi

もしrootのパスワードフィールドが“!”となっていると、この式の評価結果は

	if [ ! != * ]; then

となってしまい、testコマンドの引数として不整合を起こしスクリプトが失敗する。
rootのパスワードフィールが“!”以外(例えば“*”とか)であれば良いのだが。何故かUbuntuクリーンインストール直後の状態はrootだけ“!”になっている。これはわざとか?

次にライブブートの妨げとなるファイルを削除しておく。

### Removing trouble-making files
		:
	rm -rf "${TEMPLATE_ROOT}/etc/blkid.tab"*
		:
	rm -rf "${TEMPLATE_ROOT}/etc/resolv.conf"
		:
echo "# UNCONFIGURED FSTAB FOR BASE SYSTEM" \
	> "${TEMPLATE_ROOT}/etc/fstab"
		:
rm -rf "${TEMPLATE_ROOT}/etc/mtab"
		:
ln -s "/var/lib/initscripts/nologin" "${TEMPLATE_ROOT}/etc/nologin"

これらのファイルが残っているとファイルシステムを正常にマウント出来ないなどの問題が起きる可能性がある。(一見正常に動作しているように見えるのだがDVDではなく/dev/sda1をマウントしていたりする。)nologinに関しては必要ないと思うが、オリジナルCDの内容と合わせるために再設定している。

次に、/tmp や /var の下のゴミファイルをクリアしておく。

### Removing garbage files

rm -rf "${TEMPLATE_ROOT}/tmp/"*
rm -rf "${TEMPLATE_ROOT}/tmp/".??*
		:
		:
if [ -d "${TEMPLATE_ROOT}/root" ]; then
        echo "Cleaning root directory up...."
        ( cd "${TEMPLATE_ROOT}/root"; rm -rf ${REMOVE_LIST} )
fi

DVDに焼くことを前提すれば、これらのゴミが入っていても容量的には余裕だが、DVDを作るまでにどのようなことをしたのか等の情報まで永久に焼き込まれ事になる。もっとも、よく使うコマンドをhistoryとして残しておきライブ環境で使うと言う方法もあるが。

ubuntuのホームの保存と削除

ライブDVDには一般ユーザの情報が /etc/passwdなどに入っていない状態で作成される。そこでubuntuのアカントとホームディレクトリを削除するが、その前に(もし、ホームディレクトリのアーカイブファイルが存在しなければ)ホームディレクトリをアーカイブして保存してから削除する。

if [ -d "${TEMPLATE_ROOT}/home/ubuntu" ]; then
        (
        echo "Cleaning ubuntu directory up...."
        cd "${TEMPLATE_ROOT}/home/ubuntu"
        rm -rf ${REMOVE_LIST}
        if [ ! -f "${MISC_FILES}/ubuntu_home.cpio.gz" ]; then
                echo "Backing ubuntu home up...."
                find . | cpio -o -H newc | gzip > "${MISC_FILES}/ubuntu_home.cpio.gz"
        fi
        )

fi

###
# remove pre-configured user account, ubuntu

if [ ${REMOVE_999_ACCOUNT} ]; then
        echo "Removing ubuntu account and home...."
        (chroot "${TEMPLATE_ROOT}" userdel -f -r ubuntu ) &> /dev/null
        rm -rf "${TEMPLATE_ROOT}/home/ubuntu/"
        (chroot "${TEMPLATE_ROOT}" groupdel ubuntu ) &> /dev/null
        if [ -f "${TEMPLATE_ROOT}/etc/gdm/gdm.conf" ]; then
                sed -i \
                        -e "s/^AutomaticLoginEnable=.*\$/AutomaticLoginEnable=false/" \
                        -e "s/^AutomaticLogin=.*\$/AutomaticLogin=/" \
                        -e "s/^TimedLoginEnable=.*\$/TimedLoginEnable=false/" \
                        -e "s/^TimedLogin=.*\$/TimedLogin=/" \
                        -e "s/^TimedLoginDelay=.*\$/TimedLoginDelay=/" \
                        "${TEMPLATE_ROOT}/etc/gdm/gdm.conf"
        fi
fi

ユーザの介入なくシステムをシャットダウンするようにする

オリジナルCDではライブ環境をシャットダウンする際、CDをトレイから出したことを確認するために、最後に“Enter”キーを押す必要があるが、リモート環境にあるキーボードが接続されていないマシンではいつまでもシャットダウンできなくなってしまう。そこで、その部分をキーボードの入力無しに電源オフまでたどり着くように変更する。

################################################################################
# Triming casper for maitainance works

if [ -f "${TEMPLATE_ROOT}/etc/init.d/casper" ]; then
        echo "Modifying /etc/init.d/casper ...."
        sed -i \
                -e 's/TIMEOUT 86400/TIMEOUT 5/' \
                -e '/^[ ]*read x /s/^ /#/' \
                "${TEMPLATE_ROOT}/etc/init.d/casper"
fi

雛型からカーネルとinitrdイメージをコピーする

ライブDVDで使うカーネル(vmlinuz)とinitrdイメージを雛型からコピーしておく。
その際に initrd.imgの中にあるcasper関連のファイルを変更したり、追加うる。理由は以下の通り。

  • オリジナルCDのkernel/initrdにはロジカルボリュームを扱うパッケージ(lvm)が入っていない。従ってライブLinuxを立ち上げようとするシステムに既にロジカルボリュームがあっても別に問題はなかった。しかし、カスタムDVDを作成する過程で lvm2パッケージをインストールした場合、ライブ環境でもロジカルボリュームを認識できるようになってしまう。これは保守作業には嬉しいのだが、casperはロジカルボリュームがあると正しく動作しなくなってしまう。casperがlive media(ライブ環境のデバイス、ここではCDやDVD)を探すロジックがいま一つのようだ。仕方ないので、casperがlive mediaを探し出す対象としてロジカルボリュームデバイス(dm-0等)を除外するようにスクリプトをちょっとだけ変更する。
  • ライブ環境で立ち上げる時casperは“ubuntu”というユーザアカウントを作りだすが、当然、システム標準の環境である。それに保存しておいたubuntuのホームディレクトリを展開しておいて、カスタマイズされたGUI環境を利用出来るようにする。
  • SSHNFSなどの各種サーバがシステム起動完了時に使える(外部からネットワークを通してアクセスできる)ように環境を整える。
################################################################################
echo "Modifying initrd and copy initrd and kernel"

INITRD_ROOT="${WORKING_DIR}/initrd"

rm -rf "${WORKING_DIR}/initrd.img"
rm -rf "${INITRD_ROOT}"; mkdir "${INITRD_ROOT}"
(
        cd "${INITRD_ROOT}"
        gzip -dc "${TEMPLATE_ROOT}/initrd.img" | cpio -i --quiet

        # Casper can not handle lvm device properly, then modify casper script
        # But modifying just initrd script, not usr/share/initramfs-tools/scripts/casper
        sed -i -e 's/(loop|ram|fd)/(loop|ram|fd|dm-)/' \
                "${INITRD_ROOT}/scripts/casper"

        # Change ubuntu default password to "ubuntu", from "\n"
        sed -i -e 's/U6aMy0wojraho/kBzYzm5JjWKPA/' \
                "${INITRD_ROOT}/scripts/casper-bottom/10adduser"

        # Copy add_ubuntu_home_directory script
        if [ -f "${MISC_FILES}/11adduserhome" ]; then
                cp "${MISC_FILES}/11adduserhome" \
                        "${INITRD_ROOT}/scripts/casper-bottom/"
        fi

        # Copy server setup scripts
        cp -f "${MISC_FILES}/"6[0-9]* "${INITRD_ROOT}/scripts/casper-bottom/"

        # Copy ubuntu home directory archive, if exist
        if [ -f "${MISC_FILES}/ubuntu_home.cpio.gz" ]; then
                mkdir -p "${INITRD_ROOT}/var/backups"
                cp -f "${MISC_FILES}/ubuntu_home.cpio.gz" \
                        "${INITRD_ROOT}/var/backups/"
        fi

        find . | cpio -o --quiet -H newc | gzip > "${WORKING_DIR}/initrd.img"
)
cp -f "${WORKING_DIR}/initrd.img" "${DVD_FILES}/casper/initrd.gz"

rm -rf "${WORKING_DIR}/initrd.img"
rm -rf "${INITRD_ROOT}"

cp -f "${TEMPLATE_ROOT}/vmlinuz" "${DVD_FILES}/casper/vmlinuz"

最新版のカーネルとinitrdをコピーすることで、オリジナルCDよりも最新版のライブDVD(インストールDVD)を作成できる。

雛型からsquashFSを作成する

雛型のルートファイルシステムの調整が終わったので、これを元にsquashFSのイメージファイルを作成する。これはmksquashfsというコマンドがやってくれるが数分時間がかかる。また、CDやDVD用のISOではなく、ネットワークブートするディスクレスクライアント用のISOを作成する際にsquashfsではなくext2としてイメージファイルを作成することのできるようになっている。(“mkext2fs”というコマンドもあるようだが、ここでは標準で使えるddやmkfsを使ってイメージファイルを作成している。)

SQUASH_FILE="${DVD_FILES}/casper/filesystem.squashfs"
EXT2_FILE="${DVD_FILES}/casper/filesystem.ext2"
rm -rf "${SQUASH_FILE}" "${EXT2_FILE}"

case "${FS_TYPE}" in
squashfs|squash)
	FS_FILE="${SQUASH_FILE}"
	mksquashfs "${TEMPLATE_ROOT}" "${SQUASH_FILE}"
	;;
ext2|ext)
	FS_FILE="${EXT2_FILE}"
	FS_SIZE=`du -s "${TEMPLATE_ROOT}/" | awk '{print $1}'`
	FS_SIZE=`expr "${FS_SIZE}" + "${FS_SIZE}" / 10`
	dd if=/dev/zero of="${EXT2_FILE}" bs="${FS_SIZE}" count=1024 2>/dev/null
	mkfs -F -q -t ext2 "${EXT2_FILE}"
	rm -rf mnt ; mkdir mnt
	mount -o loop "${EXT2_FILE}" mnt
	rsync -ax "${TEMPLATE_ROOT}/" mnt/
	umount mnt
	rm -rf mnt
	;;
*)
	echo "Filesystem Type is incorrect."
	echo "exit."
	exit 1
	;;
esac
chmod 444 "${FS_FILE}"

次に“manifest”というsquashFSの中にどんなdebパッケージが入っているかを表すリストを作成する必要がある。リストには2つあって一つはライブ環境で使うsquashFSの中の全てのパッケージリスト(filesystem.manifest)。もう一つはHDDにインストールするパッケージのリスト(filesystem.manifest-desktop)である。オリジナルのminifestから2つの差分を作っておく。

MANIFEST_1="${DVD_FILES}/casper/filesystem.manifest"
MANIFEST_2="${DVD_FILES}/casper/filesystem.manifest-desktop"

ORIGINAL_DIFFS=` \
        diff "${MANIFEST_1}" "${MANIFEST_2}" | \
        sed -e '/^[^<]/d' -e 's/^< //' -e 's/ .*//' \
        `

次に雛型ファイルシステムのパッケージリスト(filesystem.manifest)を作成し、これに上で求め差分を適用してHDDインストール用のmanifest(filesystem.manifest-desktop)を作りだす。

rm -rf "${MANIFEST_1}"
rm -rf "${MANIFEST_2}"

dpkg-query -W --showformat='${Package} ${Version}\n' \
         --admindir="${TEMPLATE_ROOT}/var/lib/dpkg/" \
        > "${MANIFEST_1}"

cp -f "${MANIFEST_1}" "${MANIFEST_2}"
for REMOVE_PKG in ${ORIGINAL_DIFFS}; do
        sed -i -e "/^${REMOVE_PKG} /d" "${MANIFEST_2}"
done

DVDコンテンツのMD5チェエクリストを作る

以上で大体DVDを作成する準備が出来た。最後に(live_dvd_filesディレクトリの下にある)DVDに収められる各ファイルのMD5リストを作成しておく。このリストが“CDの異常をチェック”で使われる。(CDをチェックする気が無ければ、無くても構わない。)オリジナルCDでは、なぜかisolinuxのディレクトリだけはチェック対象から外れていたので、ここでもisolinuxのディレクトリは除外した。(ブートにライブCDではisolinux、ライブUSBではsyslinuxを使うのでこの部分が入れ替わることがあるのが原因らしい。)

################################################################################
echo "Making md5 check file"

touch "${DVD_FILES}/CUSTOM"

(
        cd "${DVD_FILES}"
        rm -f md5sum.txt
        find . -xdev -path ./isolinux -prune -o -type f -print0 \
                | xargs -0 md5sum \
                | sort -k 2 > ../md5sum.txt
        mv ../md5sum.txt .
)

ISOファイルを生成する

準備終わったのでISOファイルを生成する。genisoimageで。

################################################################################
echo "Generating custom DVD iso image"

genisoimage -quiet -J -R -D -V "CUSTOM_LIVE_DVD" \
	-o "${CUSTOM_DVD_ISO}" -b isolinux/isolinux.bin -c isolinux/boot.cat \
	-no-emul-boot -boot-load-size 4 -boot-info-table \
	"${CD_FILES}" 2> /dev/null

################################################################################

あとはDVDソフトなどでDVDに焼いて使えばいい。

*1: なお、casperパッケージにはcasper-snapshotというシェルスクリプト作られたsquashfsext2でファイルイメージを作成するプログラムがあるが、ファイルイメージの作成までしかやってくれないのと、イメージの元になる雛型ファイルシステムに関してもほとんど何もやっていないので、はcasper-snapshotは使っていない。