ラズパイ:シャットダウンフリー tmpfs-chroot編

もし、手の届かない離島に電源ブチ切りラズパイを置くなら、私ならばoverlayもfuseも使いたくない。以下、/sbin/initでの対応を示すが、未完成である。シンボリックリンクを嫌う実装が何かあるようで、いずれ調査して解決する予定である。一方で、chrootは使わず、Stateless CentOS7でのやり方(=tmpfsでbind)で実装できている。下記でも起動はするし、SSHログインもできるが、現時点ではoverlay方式またはtmpfs-bind方式でのご利用を推奨する。

前提:準備①〜③が完了していること。fuseとoverlayは不要。

~# mkdir /tmpfsroot
~# touch /.tmpfsroot
~# dosfslabel /dev/mmcblk0p1 boot
~# e2label /dev/mmcblk0p2 rootfs

/tmpfsrootにユーザランド(rootfs)を構築し、chrootする。リードオンリーで良い領域はシンボリックリンクで対応する。アプリによっては、シンボリックリンクで対応したために正しく機能しないケースがある。/etc/fstab_tmpfsrootは、/tmpfsroot/etc/fstabにコピーされる。

/etc/fstab_tmpfsroot(rw→ro):

# tmpfsroot用の/etc/fstab
proc         /proc    proc  defaults             0 0
# 軟弱なFAT領域はroマウント
LABEL=boot   /boot    vfat  ro,defaults          0 2
# rootfsを/MicroSDへroマウント
LABEL=rootfs /MicroSD ext4  ro,defaults,noatime  0 1
# LABEL=logを刻印したext4メディアにログ保存するならコメントアウト
#LABEL=log   /var/log ext4  defaults,noatime     0 0


~# rm /sbin/init

Under Construction!
基本動作確認はしているが改善余地があり、後日フォロー予定。

/sbin/init:

#!/bin/sh
## /home, /root, /etcは、総メモリ容量の1/2を超える場合は、事前に調整すること。
## 特に/homeは要注意。確認方法: cd /; du --max-depth 1 -h 
## $DISKは定義しない(rootfsは/boot/cmdline.txtのパラメータでマウントされている)。

ramdisksize=500M
# DISK=/tmpfsroot/MicroSD

if [ -d /tmpfsroot ] && [ -e /.tmpfsroot ]; then

    ## /tmpfsrootに主要構成を構築
    mount -t tmpfs -o size=${ramdisksize} tmpfs /tmpfsroot

    ## フォルダ作成
    echo "Creating directories..."
    for d in boot dev media mnt opt proc run sys tmp usr var MicroSD; do
        mkdir /tmpfsroot/${d}
    done

    ## 微調整
    chmod 1777 /tmpfsroot/tmp
    echo > /tmpfsroot/fastboot

    ## rwエリアをコピー
    ## *** メモリの1/2容量を超えないこと! ***
    echo -n "Copying files, directories..."
    #for d in etc root home srv; do
    for d in etc root srv; do
        echo -n ".. "
        cp -a ${DISK}/${d} /tmpfsroot
    done
    # /etc/fstabを調整
    [ -e /tmpfsroot/etc/fstab_tmpfsroot ] && mv -f /tmpfsroot/etc/fstab_tmpfsroot /tmpfsroot/etc/fstab

    ## roエリアをシンボリックリンク
    for d in bin sbin lib; do
        ln -s /MicroSD/${d} /tmpfsroot/${d}
    done

    ## /usrを処置(/usr/localだけtmpfs)
    for d in bin games include lib man sbin share src; do
        ln -s /MicroSD/usr/${d} /tmpfsroot/usr/${d}
    done
    cp -a ${DISK}/usr/local /tmpfsroot/usr

    ## /varの処置:ディスクの/varの構成のみをコピー
    cd ${DISK}/var
    for d in `ls -l | awk '$1 ~ /d/ {print $9 }' `; do
        DIR_NAME=`basename ${d}`
        if [ ${DIR_NAME} = "lib" ]; then
            #ln -s /MicroSD/var/lib /tmpfsroot/var/lib
            mkdir /tmpfsroot/var/lib
        else
            find ${DIR_NAME} -type d | cpio -pdm /tmpfsroot/var/
            find ${DIR_NAME} -type l | cpio -pdm /tmpfsroot/var/
        fi
    done
    ## /var/libの処置
    cd ${DISK}/var/lib
    for d in `ls -l | awk '$1 ~ /d/ {print $9 }' `; do
        DIR_NAME=`basename ${d}`
        if [ ${DIR_NAME} = "systemd" ] || [ ${DIR_NAME} = "nfs" ]; then
            # rwフォルダはtmpfsrootにコピー
            cp -a ${DISK}/var/lib/${DIR_NAME} /tmpfsroot/var/lib/${DIR_NAME}
        else
            # 他はSymbolic Linkで対応
            ln -s /MicroSD/var/lib/${DIR_NAME} /tmpfsroot/var/lib/${DIR_NAME}
        fi 
    done
    cd

    ## fstabに/var/logの定義があればマウント
    mount -T /tmpfsroot/etc/fstab /var/log

    ## switch_root
    mount -o bind /sys /tmpfsroot/sys
    mount -o bind /dev /tmpfsroot/dev/
    mount -t proc proc /tmpfsroot/proc
    #mount -o bind / /tmpfsroot/MicroSD
    cd /tmpfsroot
    pivot_root . MicroSD
    exec chroot . /lib/systemd/systemd

    #exec switch_root /tmpfsroot /lib/systemd/systemd "$@" </tmpfsroot/dev/console >/tmpfsroot/dev/console
    #exec /usr/lib/klibc/bin/run-init /tmpfsroot /lib/systemd/systemd
    #exec /usr/lib/klibc/bin/run-init /tmpfsroot /lib/systemd/systemd "$@" </tmpfsroot/dev/console >/tmpfsroot/dev/console
    #exec chroot /tmpfsroot /lib/systemd/systemd

else
    ## 元のsystemdを起動する
    exec /lib/systemd/systemd
fi

echo "Something went badly wrong in the /sbin/init."

~# chmod +x /sbin/init