Busybox – Troubleshooting Busybox Switch_Root Issues

busyboxlinuxsd cardutil-linux

I'm working on an embedded ARM Linux system that boots using initramfs. (Here's some background from a couple earlier questions, if you're interested.) So far, thanks in part to help received here, I can boot the kernel via TFTP with an embedded initramfs. The MMC driver detects an SD card containing a new root filesystem, which I can then mount. However, I cannot get the final step, using busybox switch_root to switch to the filesystem on the SD card, to work.

At the initramfs shell prompt, I think this should make the kernel switch to the new filesystem:

switch_root -c /dev/console /mnt/root /sbin/init.sysvinit 

However, it just makes busybox (to which switch_root is aliased) print its man page, like this:

/ # switch_root -c /dev/console /mnt/root /sbin/init.sysvinit 
BusyBox v1.17.4 (2010-12-08 17:01:07 EST) 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.

Options:

-c DEV  Reopen stdio to DEV after switch

I think the -c option is correct, since it's the same as what is contained in the example, and /dev/console exists.

/ # ls -l /dev
total 0
crw-r--r--    1 0        0           5,   1 Jan  1 00:28 console
brw-r--r--    1 0        0           7,   0 Dec 21  2010 loop0
brw-r--r--    1 0        0         179,   0 Dec 21  2010 mmcblk0
brw-r--r--    1 0        0         179,   1 Dec 21  2010 mmcblk0p1
brw-r--r--    1 0        0         179,   2 Dec 21  2010 mmcblk0p2
brw-r--r--    1 0        0         179,   3 Dec 21  2010 mmcblk0p3
brw-r--r--    1 0        0         179,   4 Dec 21  2010 mmcblk0p4

/mnt/root also exists.

/ # ls /mnt/root
bin         etc         linuxrc     mnt         sys         var
boot        home        lost+found  proc        tmp
dev         lib         media       sbin        usr

The init executable exists:

/ # ls -lh /mnt/root/sbin/
<snip>
lrwxrwxrwx    1 0        0             19 Dec 21  2010 init -> /sbin/init.sysvinit
-rwxr-xr-x    1 0        0          22.8K Dec 21  2010 init.sysvinit

But here's something strange:

/mnt/root/sbin # pwd
/mnt/root/sbin
/mnt/root/sbin # ls -l | grep init.sysvinit
lrwxrwxrwx    1 0        0               19 Dec 21  2010 init -> /sbin/init.sysvinit
-rwxr-xr-x    1 0        0            23364 Dec 21  2010 init.sysvinit
/mnt/root/sbin # ./init.sysvinit 
/bin/sh: ./init.sysvinit: not found
/mnt/root/sbin # /mnt/root/sbin/init.sysvinit 
/bin/sh: /mnt/root/sbin/init.sysvinit: not found

That's totally mystifying. I'm not sure where I'm going wrong. I've looked at the source, which is at http://git.busybox.net/busybox/tree/util-linux/switch_root.c?id=1_17_4

It's not just the init.sysvinit executable. I can't execute anything from the SD card. For example:

/mnt/root/bin # ./busybox 
/bin/sh: ./busybox: not found
/mnt/root/bin # /mnt/root/busybox 
/bin/sh: /mnt/root/busybox: not found
/mnt/root/bin # ls -l | grep "2010 busybox"
-rwxr-xr-x    1 0        0           462028 Dec 21  2010 busybox

Anyone have a clue what's amiss here? I thought it might be some problem with mounting the card noexec, but I believe exec is the default, and I tried passing the exec option explicitly at mount with no success.

Best Answer

The reason that switch_root is not working on the command line is this code in busybox:

    if (st.st_dev == rootdev || getpid() != 1) {
        // Show usage, it says new root must be a mountpoint
        // and we must be PID 1
        bb_show_usage();
    }

You are not PID 1, so you are falling through into this bb_show_usage. The implication is that the switch_root command in your initramfs init script should run switch_root with exec. i.e.

exec switch_root ...

The other issue with your "not found" errors is likely because the shared libraries needed by the executables are not found, because the initramfs root filesystem does not have them. If you can get switch_root to work with exec, then is likely the "not found" error will go away.

Related Question