Launching Linux from Busybox (pivot_root or switch_root, or ? ) - linux

On a beaglebone hardware, I want to start on a partition with a minimalist busybox system (/dev/mmcblk0p2), run some checks on the 2 other partitions (/dev/mmcblk0p5 & /dev/mmcblk0p6) containing more complete Linux systems (Angström), then start on one or the other of the 2 Linux systems based on those tests.
The problem is that I cannot find how to start another system correctly from busybox.
What I did:
From the (perfectly working) busybox system:
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
mount -t sysfs sysfs /sys
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
mount /dev/mmcblk0p5 /mnt/root
Then I tried 2 ways:
pivot_root
cd /mnt/root
pivot_root . ./initrd
./bin/mount -n --move ./initrd/sys ./sys
./bin/mount -n --move ./initrd/proc ./proc
./bin/mount -t devtmpfs none ./dev
./bin/mount -n --move ./initrd/dev/pts ./dev/pts
exec ./usr/sbin/chroot . ./sbin/init < ./dev/ttyO0 > ./dev/ttyO0 2>&1
This gives the following error :
Couldn't find an alternative telinit implementation to spawn.
It then starts a new Angström login prompt, but after logging in, any call to "init" will return the error above, and the system doesn't work (for example, if I call "reboot", it fails; if I call "killall busybox", it triggers a reboot).
I tried without the "./usr/sbin/chroot . ", and it gives the same results.
switch_root
exec switch_root -c /dev/ttyO0 /mnt/root /mnt/root/sbin/init
This gives me a new busybox login prompt, and I am still on the busybox partition
Any idea what I've done wrong ? Have I missed a step ? Any parameter I forgot to take into account or any method to see more details about what went wrong ?

Related

Qemu. Linux doesn't write in console after init

I run Linux on QEMU with emulation whole SOC.
Linux loads successfully. Busybox is init process for Linux. But when Linux run it, there are no any out in console. And it freezes on command /dev/console::sysinit:-/bin/ash from inittab file. Also I tried to run print("Hello world") program as init process, but result is the same. There are no output in console.
I see all kernel debug output in console. Also I see, that driver for UART is loaded.
Inittab content
::sysinit:/bin/busybox --install
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -t sysfs sysfs /sys
::sysinit:/usr/local/bin/kernloglvl 4
::sysinit:/etc/init.d/rc
::sysinit:/bin/mount -t nfs -o vers=3 -o nolock share:/srv/nfs /mnt/share
/dev/console::sysinit:-/bin/ash
::shutdown:/bin/umount -a -r

Correct way to switch_root

I'm having a ton (and a half) of problems setting up booting for my embedded target; situation is:
I have an embedded target with a rather small, but reliable, Flash (16M bytes) and a possibly large (currently 8GB), but rather unreliable, SD card.
Unreliability of SD card is mainly due to hardware setup (direct connection to power supply, so NO WAY to hardware reset it if it wakes up "badly") I cannot change.
This is mainly affecting u-boot (Linux handling seems much more stable).
Since I need a relatively high reliability, even during/after software update, I opted for a dial system (update the dormant one, then reboot) with a "recovery" fallback.
Unfortunately I do not have enough space in Flash for a proper initramfs plus a full recovery system, so I'm trying to couple startup system with recovery.
I thus have a full flash system with a small /init script choosing startup mode.
/init script is something like:
#!/bin/ash
set -x
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
boot_prod() {
mount -t proc none /proc
mount -t sysfs none /sys
mount $1 /mnt && [ -x /mnt/sbin/init ] || return 1
echo "switching to $1"
cd /mnt
mount --move /sys sys
umount /proc # /proc is remounted by BusyBox /dev/inittab
mount --move /dev dev
config_set sys $2
pivot_root . mnt
umount mnt
exec chroot . sbin/init <dev/console >dev/console 2>&1
}
case $tryboot; in
A)
boot_prod /dev/mmcblk0p6 A
;;
B)
boot_prod /dev/mmcblk0p7 B
;;
R)
[ -x /mnt/sbin/init ] && exec /mnt/sbin/init
;;
*)
;;
esac
echo "Could not boot cleanly; running a shell"
mount -t proc none /proc
mount -t sysfs none /sys
exec setsid cttyhack sh
This is clearly started with bootargs containing tryboot=A/B/R.
I am not using Busybox switch_root because this is not a true initramfs, but a SquashFS living on Flash; my current u-Boot environment includes:
BOOT_A_GOOD=y
BOOT_CURRENT=B
SYSTEM_R=/dev/mtdblock5
boot_a=echo "Loading System A";part=A;run boot_x
boot_b=echo "Loading System B";part=B;run boot_x
boot_now=if test "${BOOT_CURRENT}" = A; then run boot_a; elif test "${BOOT_CURRENT}" = B; then run boot_b; fi; if env exists BOOT_A_GOOD; then run boot_a; fi; if env exists BOOT_B_GOOD; then run boot_b; fi; run boot_r
boot_r=echo "Loading Recovery";part=R;run boot_x
boot_x=setenv bootargs "${default_bootargs} mtdparts=${mtdparts} root=${part}" && bootm bc050000
bootcmd=rub boot_now
bootdelay=2
default_bootargs=earlyprintk rootwait console=ttyS2,115200
mtdids=nor0=spi0.0
mtdparts=spi0.0:312k(u-boot),4k(env),4k(factory),2368k(kernel),-(filesystem)
Current problem is system dies at exec chroot . sbin/init ... with a "Kernel panic - not syncing: Attempted to kill init !" error without printing the "culprit" + exec chroot . sbin/init <dev/console >dev/console 2>&1 line.
Note1: I made sure sbin/init exists on new root fs (it is a symlink to bin/busybox
Note2: Error persists even if I comment out previous umount mnt.
What am I doing wrong?

In Linux terminal, what would "grep -q '/dev/sda1' /proc/mounts || ..." do?

I want to make a bootable USB device by following this page.
http://planet-lab.org/node/172
It asks me to do these to steps:
umount /dev/sda*
grep -q /dev/sda1 /proc/mounts || dd if=PlanetLab-BootCD-3.3.usb of=/dev/sda1
But it makes me confused.
Since I think /dev/sda is my HDD, I thought it should be unmount /dev/sdb* in order to unmount USB device.
And I really don't understand what grep -q /dev/sda1 /proc/mounts is doing.
It seems to check whether "/dev/sda1" is mounted, but I don't exactly know what are the two parameters of grep command is doing. I know -q is for quiet.
And I also know dd can write an image to a drive.
The instructions state
assuming that the device is detected as /dev/sda
If the assumption is different from the actual mount point, you must modify the commands to match your configuration.
The grep -q is used to test for existence without cluttering the screen with the text which is found. The two parameters are
the text sought "/dev/sda1", and
the file in which the text is sought "/proc/mounts".
In other scripts, you may see something like
grep /dev/sda1 /proc/mounts >/dev/null
to achieve the same effect as the -q option.

Busybox init does not start /etc/init.d/rcS

I'm trying to build embedded system using buildroot. Everything seems to work. All modules are starting, the system is stable. The problem is that /etc/init.d/rcS does not start during initialization of the system. If I run it manually everything is OK. I have it in my inittab file.
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen#codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
# runlevels == ignored
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
null::sysinit:/bin/mount -t proc proc /proc
null::sysinit:/bin/mount -o remount,rw /
null::sysinit:/bin/mkdir -p /dev/pts
null::sysinit:/bin/mkdir -p /dev/shm
null::sysinit:/bin/mount -a
null::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
ttyFIQ0::respawn:/sbin/getty -L -n ttyFIQ0 115200 vt100 # GENERIC_SERIAL
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
null::shutdown:/etc/init.d/rcK
null::shutdown:/bin/umount -a -r
null::shutdown:/sbin/swapoff -a
Any idea what could be wrong?
/bin/init needs to be on your filesystem.
/bin/sh needs to be on your filesystem.
/etc/init.d/rcS needs to be executable and have #!/bin/sh as its first line.
Init
Are you sure you where invoking Busybox init? What was the kernel command line? If no init= option was supplied to the the kernel, the kernel will look for an executable at /init.
For instance, if your busybox binary resides in /bin/busybox, you need to create the following symlink :
ln -s /bin/busybox /init
If you want your init to reside in /sbin, to comply with the inittab, also create a symlink there. Note that the kernel will not respect init= setting if you don't mount root and your busybox only runs in an initramfs.
ln -s /bin/busybox /sbin/init
Inittab
Also, you could try not using an inittab. The things you try to run from inittab, might very well fit in rcS and any descendant scripts. From the same source you found your example inittab:
# Note: BusyBox init works just fine without an inittab. If no inittab is
# found, it has the following default behavior:
# ::sysinit:/etc/init.d/rcS
# ::askfirst:/bin/sh
# ::ctrlaltdel:/sbin/reboot
# ::shutdown:/sbin/swapoff -a
# ::shutdown:/bin/umount -a -r
# ::restart:/sbin/init
# tty2::askfirst:/bin/sh
# tty3::askfirst:/bin/sh
# tty4::askfirst:/bin/sh
rcS
Make sure /etc/init.d/rcS is executable:
chmod +x chroot chroot /bin/busybox
And try with:
#!/bin/busybox sh
echo "Hello world!"
Please note that this sentence can get buried between kernel log messages, so you might want to pass the quiet kernel command line option to see if it appears.
Busybox symlinks
Are the symlinks installed into the file system or not? If not it is not a disaster. Make sure that /etc/init.d/rcS starts with:
#!/bin/busybox sh
mkdir -pv /sbin
/bin/busybox --install -s
In addition to the scripts themselves being executable and having a correct shebang line, the kernel also needs to be compiled with the CONFIG_BINFMT_SCRIPT option enabled.
CONFIG_BINFMT_SCRIPT:
Say Y here if you want to execute interpreted scripts starting with
#! followed by the path to an interpreter.
You can build this support as a module; however, until that module
gets loaded, you cannot run scripts. Thus, if you want to load this
module from an initramfs, the portion of the initramfs before loading
this module must consist of compiled binaries only.
Most systems will not boot if you say M or N here. If unsure, say Y.
Without this option, you may receive the error message can't run '/etc/init.d/rcS': Exec format error.
From the information given, everything looks correct.
Some things to try:
Check ownership of your rcS script.
Comment out everything from rcS, and add something very simple:
echo "This worked" > /tmp/test
There might be something in your script related to a startup race condition that is causing it to exit. Also curious if your script is starting syslogd.

mount system call

I am stuck at finding the correct usage of mount() system call which should be the replacment for the command
$mount -t ext3 -oloop /test /mount
Please help.
Thanks
try:
$ strace mount -t ext3 -oloop /test /mount
And you will see that there are 2 number of system calls involved - one for setting the loopback block device and another to do the actual mount

Resources