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:You are not PID 1, so you are falling through into this
bb_show_usage
. The implication is that theswitch_root
command in your initramfs init script should runswitch_root
withexec
. i.e.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 withexec
, then is likely the "not found" error will go away.