XBian from USB with SD fallback

After the big mess I’ve previously posted about I’ve decided to get the opportunity to switch over to a better and more performing setup for my Raspberry Pi, not to mention the addition of multiple backups…

The goal I set up was to have mi Pi running off a root filesystem on my external USB hard drive while still being able to be portable, so running off the SD when needed.

I took the opportunity to switch from RaspBMC to XBian, mostly because the latter is based on Raspbian which seems to have a better support on the forums.

I started by flashing an XBian RC2 image onto my SD card from a Windows laptop using the tool provided by the community (the Linux version didn’t work for me).

After being surprised by the fact this distro doesn’t use ext3/4 but btrfs (I didn’t even know it existed) and it already includes the kernel module for my WiFi dongle I started messing with the boot sequence: I wanted to be able to drop to command line before the init sequence started and manipulate the cmdline.txt to change the rootfs location.

Because my keyboard seems to use a weird, non standard, firmware, I suddenly discover I was unable to use it to drop into rescue mode so I had to revert to a somewhat automated way to switch to SD card root fs.

I ended up with a little more complicated solution which performs fully automated fallback: if the USB disk isn’t connected at boot time then it reverts to SD card and reboots. Once the USB disk gets connected back though, you need to execute a command to restore the USB root.

To achieve this I had to create a little shell script:

#!/bin/sh

fallback() {
	$mount_bin /dev/mmcblk0p1 /mnt && echo "Boot filesystem mounted"
	if [ ! -f /mnt/cmdline.usb.txt ] && [ -f /mnt/cmdline.sd.txt ]; then
		echo "Switching back to SD card root filesystem..."
		mv /mnt/cmdline.txt /mnt/cmdline.usb.txt
		cp /mnt/cmdline.sd.txt /mnt/cmdline.txt
		umount /mnt
		exit 0
	else
		umount /mnt
		echo "Fallback procedure unavailable"
		exit 1
	fi 
}

restore() {
	if [ -f /boot/cmdline.usb.txt ]; then
		echo "Re-enabling USB root filesystem..."
		mv -f /boot/cmdline.usb.txt /boot/cmdline.txt
	else
		echo "Nothing to do"
	fi
	exit 0
}

case $1 in
	fallback) 
		fallback;;
	restore) 
		restore;;
	*)
		echo "Usage: `basename $0` ( fallback | restore )";;
esac

As you can see this script provides two functions: you can either try to fallback from USB to SD or to restore your boot sequence to use a USB root filesystem.
You can obviously use this from command line, something you will have to if the fallback procedure occurs, so I created a symbolic link to it into /usr/sbin to have it on my superuser execution path.
Because I want this file to be available at boot time I need to have it within the initramfs, that’s why I created this file as /etc/xbian-initramfs/usb-boot.sh.
But this is not enough as the initramfs image is created by a script which doesn’t include the file unless you explicitly tell it to: to do so I edited the update-initramfs.sh script adding the following highlighted lines to include my new creation:

cp /etc/xbian-initramfs/cnvres-code.sh ./
cp /etc/xbian-initramfs/splash_updater.sh ./
# Add root fs USB to SD fallback/restore script
cp /etc/xbian-initramfs/usb-rootfs.sh ./

copy_with_libs /usr/bin/stdbuf
copy_with_libs /usr/lib/coreutils/libstdbuf.so
copy_with_libs /usr/bin/setterm

Now you need to have a copy of the /boot/cmdline.txt file which runs nicely from SD card and name it /boot/cmdline.sd.txt: I performed the copy at this stage as so far everything was working fine for me.

At this stage you might want to move your root filesystem over your USB hard drive and this is going to be the easiest task: you can do it through the xbian-config command by simply choosing option number 6 and specifying the partition on your USB hard disk. With XBian RC2 this does practically everything for you!

Next step is to enable the initramfs at boot as it is disabled by default to save a little on boot time: edit /boot/config.txt uncommenting the initramfs line.

Before creating the new initramfs image let’s tweak the init process a little to automate the fallback procedure: remember, my keyboard is not recognized during the boot sequence so I will not be able to hold down the shift key…

The file to alter is /etc/xbian-initramfs and the following highlighted lines are the contributions which automate the fallback check and reboot if needed:

if [ "$CONFIG_rootfstype" != "nfs" ]; then
    while ! get_root && [ -n "$CONFIG_rootwait"  -a  "$X" -lt "$CONFIG_rootwait" ]; do
	/sbin/modprobe -q usb_storage
	X=$(($X+1))
	echo "$X Waiting for root..."
        sleep 1
    done
    if [ ! -b "${CONFIG_root}" ]; then
	echo "Root partition ${CONFIG_root} missing"
	eval ./usb-rootfs.sh fallback
	if [ "$?" -eq '0' ]; then
	    echo "Fallback root filesystem applied: rebooting now!"
	    sync
	    reboot -f -d2
	fi
	drop_shell
    fi
    ln -s ${CONFIG_root} /dev/root
    up "root block device found"

    export FSCHECK=$(blkid -s TYPE -o value -p ${CONFIG_root})
    resize_part; resize_ext4; convert_btrfs
    up "after resize, convert"
fi

Practically the added section steps into the root partition identification and right after the declaration of a missing root partition tries to perform a fallback procedure: if it succeeds it reboots the system, otherwise the process continues as normal and the user is dropped into the rescue shell.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s