2012年10月23日
開発用のrootfsで起動後すぐにシリアルコンソールでrootで自動ログインする方法
開発ボードでカーネルをいじるときには、rootfsとしてLinaroのサイトにあるnanoやALIPを私はよく使用します。
これらの便利なところは、起動するとすぐにシリアルコンソールにrootで自動ログインしてshellのプロンプトが出るところです。しかも、rootfsの中では、明示的にシリアルコンソールのデバイス名を指定しなくても自動で判別してくれています。
これがどのような仕組みになっているのかを少し調べました。そのメモを残します。
いままで (その1)
昔のSystemV方式のinitでは、どのデバイスでgettyを動かすかは、 /etc/inittab に記述していました。 /dev/console でgettyを通さずに直接/bin/shを起動するには、そのように書くことができたと思います。
しかし、最近はこの方式を使うことがないので詳細を思い出せません。
いままで (その2)
Ubuntuでは早々にSystemV方式からupstartに移行しました。gettyを動かすデバイスを指定するためには、/etc/initの下に、デバイス名.conf のファイルを作っておく必要がありました。つまりシリアルコンソールが/dev/ttyS1ならば、ttyS1.confです。内容はtty1.confからコピーして、シリアルのボーレイトのパラメータとデバイス名だけを修正するだけで済みます。
例
/etc/init/ttyS1.conf
# ttyS1 - getty
#
# This service maintains a getty on tty1 from the point the system is
# started until it is shut down again.
start on stopped rc RUNLEVEL=[2345] and (
not-container or
container CONTAINER=lxc or
container CONTAINER=lxc-libvirt)
stop on runlevel [!2345]
respawn
exec /sbin/getty -8 115200 ttyS1
とりあえずこれでシリアルコンソール/dev/ttyS1にログインプロンプトが出るようになります。
しかし、評価ボードによってはシリアルコンソールのデバイスは異なります。例えば、KZM-A9-DualボードではttyS1ですが、KZM-A9-GTボードではttySC4です。両方のボードを交互に試す場合、その度にttyS1.confとttySC4.confを作ったり消したりしなければなりません。両方をそのまま置いておくと、存在しないデバイスに対してgettyを実行することになり、エラーメッセージが繰り返しコンソールに表示されるので、わずらわしいことになります。結局ボードごとにrootfsを分けて準備しておく必要がありました。
Linaroの開発用rootfsでの仕組み
LinaroのnanoやALIPなどの開発用rootfsでは、シリアルコンソールのデバイスを自動判別します。このため、複数のボードで同じrootfsを使用可能です。ボードをとっかえひっかえしながら実験している時にはこれはありがたいことです。
シリアルコンソールのデバイスの自動判別は、カーネルに渡されたブートパラメータのconsole= の部分を見て行っていました。rootで自動ログインするには、gettyから実行するlogin用のプログラムとして、login -f root を使用するようになっていました。 -f でパスワードの入力を省略できます。
関連するファイルは以下のとおり。
- /etc/init/auto-serial-console.conf
- /bin/auto-serial-console
- /etc/default/autogetty
- /bin/auto-root-login
/etc/init/auto-serial-console.conf
# auto-serial-console - autostarts getty on serial console # # This service maintains a getty on serial port given as 'console' kernel argument. # # Last 'console' argument is used # start on runlevel [23] stop on runlevel [!23] respawn exec /bin/auto-serial-console
/bin/auto-serial-console
#!/bin/sh -e
[ -f /etc/default/autogetty ] && . /etc/default/autogetty
[ 1 -gt $ENABLED ] && exit
for arg in $(cat /proc/cmdline)
do
case $arg in
console=*)
tty=${arg#console=}
tty=${tty#/dev/}
case $tty in
tty[a-zA-Z]* )
PORT=${tty%%,*}
# check for service which do something on this port
if [ -f /etc/init/$PORT.conf ];then continue;fi
tmp=${tty##$PORT,}
SPEED=${tmp%%n*}
BITS=${tmp##${SPEED}n}
# 8bit serial is default
[ -z $BITS ] && BITS=8
[ 8 -eq $BITS ] && GETTY_ARGS="$GETTY_ARGS -8 "
[ -z $SPEED ] && SPEED='115200,57600,38400,19200,9600'
GETTY_ARGS="$AUTOGETTY_ARGS $GETTY_ARGS $SPEED $PORT"
exec /sbin/getty $GETTY_ARGS
esac
esac
done
/etc/default/autogetty
# here you can provide what to run instead of /bin/login AUTOGETTY_ARGS="-n -l /bin/auto-root-login" # Should autogetty be enabled? ENABLED=1
/bin/auto-root-login
#!/bin/sh exec /bin/login -f root
shellスクリプトの細かい技が勉強になりますね。