initrdの中でntpdateを実行する
この内容はinitrdについて最低限の知識を前提とします。不用意に行うとシステムが起動しなくなる場合があります。
概要
私は遊びサーバでALIX.2を使っているのですが、組み込みボードの悲しさでALIXは電池を持っていないため、電源を切るといちいちクロックが2000-01-01にリセットされてしまいます。まあ、起動後にntpdateで正しい時刻を入力すれば通常は特に困らないのですが、最終アクセス時刻とクロックが大幅にずれているため、ブート時にfsckがいちいち走って鬱陶しいです。fastbootをいちいち作るのも面倒ですし。そんなわけで、initrdのでntpdateが実行されるようにしてみました。
簡単にできるかと思いきや意外なほど苦戦したのでメモを残しておきます。
作成手順
展開して必要なファイルをコピー
まずはinitrd.imgを展開して作業環境の作成。ついでに必要なファイルをコピーしてきます。rootでやる方が楽かもしれません。
# cp /boot/initrd.img . # mkdir work <-- 作業ディレクトリ作成 # cd work <-- 作業ディレクトリへ # gzip -dc ../initrd.img | cpio -idmv <-- initrdを展開
必要なファイルをコピーします。
- binディレクトリへ
- /usr/sbin/ntpdate
- /sbin/hwclock
- libディレクトリへ
- /lib/ld-linux.so.2
- /lib/libc.so.6
- /lib/libnss_files.so.2
- /lib/modules/kernel-version/kernel/net/ipv6/ipv6.ko
- etcディレクトリへ
- /etc/localtime
設定ファイルの作成
ntpdateを実行する際にいくつかのファイルが参照されますので作成します。
- /etc/nsswitch.conf
services: files
- /etc/services
ntp 123/udp ntp 123/tcp
initスクリプトの修正
すべてのファイルがそろったらinitスクリプトを修正します。環境にもよりますがだいたいこんな感じ。
#!/bin/nash mount -t proc /proc /proc setquiet echo Mounted /proc filesystem echo Mounting sysfs mount -t sysfs none /sys echo "Loading ipv6.ko module" insmod /lib/ipv6.ko <-- IPv6モジュール読み込み echo "Loading ehci-hcd.ko module" ...モジュール読み込み echo Creating block devices mkdevices /dev echo Creating root device mkrootdev /dev/root echo 1 > /sys/power/suspend2/do_resume umount /sys echo Sync NTP server... ntpdate 192.168.1.1 <-- ntpdate実行 echo Setting hwclock hwclock --systohc <-- hwclock実行 echo Mounting root filesystem mount -o defaults --ro -t ext3 /dev/root /sysroot echo Switching to new root switchroot /sysroot
initrd.imgの作成
最後にinitrd.imgを作成して完成です。
# find | cpio -H newc -o | gzip -9 > initrd-ntp.img
試行錯誤ログ
試行錯誤したときのエラーメッセージなど。
ネームサービス
Looking for host 192.168.1.1 and service ntp Error : Servname not supported for ai_socktype 28 Oct 02:09:19 ntpdate[1477]: can't find host 192.168.1.1 28 Oct 02:09:19 ntpdate[1477]: no servers can be used, exiting
これは、service ntpが解決できてないようです。/etc/serviceを用意して、
ntp 123/tcp ntp 123/udp
というのを作ってもだめ。straceで見てみると、/lib/libnss_files.so.2ってのを探していました。どうやらこれが必要らしく必要なライブラリファイルに追加。ついでに/etc/nsswitch.confと/etc/localtimeも必要。
IPv6
28 Oct 11:04:41 ntpdate[289]: cannot find family compatible socket to send ntp packet
こんなエラーが。またまたstraceのログを見るとAF_INET6がどうとか書いてりました。どうやら内部的にはIPv6で処理しているようでipv6モジュールを読み込む必要がありそう(-4オプションは役に立たなかった・・・)。そんなわけで/lib/ipv6.koを用意。
ハードウェアクロック
無事にできたと思ったときの落とし穴。
28 Oct 02:21:37 ntpdate[292]: step time server 192.168.1.1 offset -32401.216735 sec ... INIT: Setting clock (localtime): Sat Jan 1 00:00:46 JST 2000 [ OK ]
で、リセットされてしまいました。ハードウェアクロックにセットしないとダメなようです。initスクリプトに、
hwclock --systohc
を追加してようやく実現できました。こんなに苦労するとは・・・