switch_root busybox init problems?

dtmland picture dtmland · Jun 13, 2015 · Viewed 9.3k times · Source

I'm in an embedded linux environment with busybox. I've read through several posts trying to learn how to use switch_root. I tried this:

exec switch_root -c /dev/console /mnt/newroot /bin/busybox init

The switch_root help prints and I am presented with a new login:

[root@buildroot ~]# exec switch_root -c /dev/console /mnt/newroot /bin/busybox init
BusyBox v1.21.0 (2015-04-24 18:14:40 MDT) multi-call binary.
busybox init
Usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGS]root /bin/busybox in

Free initramfs and switch to another root fs:
chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,
execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.

        -c DEV  Reopen stdio to DEV after switch


Welcome to Buildroot
buildroot login:

When I login, newroot has not been loaded, old one is still there. Is this because I am running this command directly from command line and not from some kind of init script?

I read in this article and found they perform other steps before running switch_root:

mount --move /sys /newroot/sys
mount --move /proc /newroot/proc
mount --move /dev /newroot/dev

First off, this confuses me. Why would I want to run these commands before running switch_root? Does switch_root not do this for me?

Anyways, I went ahead and tried running them first and then running my switch_root command. However, this hoses things up entirely:

[root@buildroot /]# switch_root -c /dev/console /mnt/newroot /bin/busybox init
BusyBox v1.21.0 (2015-04-24 18:14:40 MDT) multi-call binary.

Usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGS]

Free initramfs and switch to another root fs:
chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,
execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.

        -c DEV  Reopen stdio to DEV after switch

can't open /dev/ttyS0: No such file or directoryole /mnt/newroot /bin/busybox init
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
... message continues to repeat ...

So it looks like because I've moved the mount for dev that when my init runs and trys to put the getty on my serial port it can't find it? Confusion........

Am I missing something fundamental about switch_root here? Or some simply command line modifications required?

Answer

g0hl1n picture g0hl1n · Jul 13, 2016

First, as its helptext says switch_root has to be executed as PID 1. Therefore it needs to be called by an initscript using exec.

Second, moving the tmpfilesystems manually is (as you saw) a bad idea. The error you get is because your console (/dev/ttyS0) was moved away with your mount --move call. switch_root will delete those mounts automatically. Therefore your second init (which is called by switch_root) needs to mount them again.

Third, here's a short version of the init script I'm using within my initramfs which should help you:

#!/bin/sh

ROOT="/mnt/.root"
ROOT_DEV="/dev/sdb2"

echo "init from initramfs"

# mount temporary filesystems
mount -n -t devtmpfs devtmpfs /dev
mount -n -t proc     proc     /proc
mount -n -t sysfs    sysfs    /sys
mount -n -t tmpfs    tmpfs    /run

# mount new root
[ -d ${ROOT} ] || mkdir -p ${ROOT}
mount ${ROOT_DEV} ${ROOT}

# switch to new rootfs and exec init
cd ${ROOT}
exec switch_root . "/sbin/init" "$@"

Hope this helps.