Fork me on GitHub

Kernel Hopping

I keep some old PC hardware around as a filesystem and test machine running Archlinux. I only occasionally bring it up (since the cloud does everything now, right?) but yesterday it failed to boot. Last time I had it on I updated Arch over the filesystem change but having done as instructed, I turned it off and thought nothing of it. On bringing the system up again I got dropped to the linux rootfs# shell. Better still my keyboard did nothing (in retrospect it looks like a ps2 keyboard might have functioned). Rebooting and selecting the fallback kernel didn’t change things and I couldn’t find anything online of much help. I reasoned something was wrong with the kernel as the bootloader - grub2 - was running fine from the disk and I hadn’t made any hardware changes.

So replace the kernel: Trouble is this is old hardware. Old enough that it’s usb boot support is very flaky (and who uses optical disks anymore??). So I could boot from the harddrive but not load linux; I had linux on a usb flash drive but I couldn’t boot from it. I have all the pieces, here’s how to put it together:

# Use GRUB command line to boot kernel from usb
set root=(fd0,msdos1)
linux /casper/vmlinuz root=/dev/fd0
initrd /casper/initrd.lz

# Mount filesystem on harddisk
mkdir -p /mnt/arch
mount /dev/sda2 /mnt/arch

# Set up temporary filesystems and chroot
cd /mnt/arch
mount -t proc proc proc/
mount -t sysfs sys sys/
mount -o bind /dev dev/
mount -t devpts pts dev/pts/
chroot /mnt/arch /usr/bin/bash

# Rebuild kernel on disk
mkinitcpio -p linux

# Exit chroot and reboot

Grub has a command line accessible by pressing c before it loads a kernel. From there you have a small set of commands to use. You can ls to find all the drives grub can see; my hard drive and was listed as hd0 and fd0 is a legacy name for floppy drives thats been repurposed for usb drives. The first set of commands above set grub to use the usb drive, load linux from the kernel image (UNetBootIn puts kernel images in a directory named casper), and load the inital ramdisk to go with it. On booting I got a basic shell with just busybox for commands.

The second block above mounts the filesystem on the sda2 partition (trial and error deduced sda1 was a swap partition). We can fake the environment of the operating system on disk by starting up all the temporary filesytems then changing the filesystem root. We drop into the on-disk bash shell with the new root. Now we can fix up the kernel, mkinitcpio takes care of generating the kernel image and initrd. With that working, we can exit bash back to the shell from usb and reboot to close down the filesystem properly.

Success; my machine is alive again without reinstalling anything. A quick package update and reboot verified everything was running fine. Hopefully this isn’t a common situation, but if it happens to you; you can rebuild linux.

Comments !