Contents

ramusb.igz: a script to build a initramfs suitable to boot Linux from removable media

Usually, to boot Linux we must define a kernel image and a mount point for root "/". At boot time, if kernel not syncing root partition, often we can have a "kernel panic". With ramusb.igz we can avoid this error, because this system performs several tries to mount root partition and, if boot will fail, open a text console. Ramusb.igz can also boot USB stick or other removable media.

How it works

init in ramusb.igz works with principle of "Signature File", in other words search a file inside all disks. File name is user defined; these are the operations:

Build script

The script to build ramusb.igz run in Slackware and creates files using /usr/share/mkinitrd/initrd-tree.tar.gz as base system (Note: it build a 64bit system if you work in Slackware64). Copy source below in a file named "makeramusb-slack.sh" and exec the script as root:

# chmod 755 makeramusb-slack.sh
# ./makeramusb-slack.sh

It create a work tree. The RAMDISK "ramusb.igz" will be located inside "work" directory. Now, copy ramusb.igz in your boot partition, ex: "/boot".

Latest version is 0.7.1 Changelog:

0.6

makeramusb-slack.sh rev. 0.7.1

#!/bin/sh
# *** Makeramusb-slack *** copyleft (!C) FZ
# *** rev 0.7 04/09/2011
 
echo "Removing previous structure and files ..."
#--------------------------------------------------------
rm -Rf work
rm -Rf initrd-tree
 
echo "Getting mkinitrd busybox ..."
#--------------------------------------------------------
if [ ! -f ./initrd-tree.tar.gz ] ; then
 cp -f /usr/share/mkinitrd/initrd-tree.tar.gz .
fi
 
if [ -f ./initrd-tree.tar.gz ] ; then
 mkdir -p initrd-tree
 tar -C initrd-tree -xzplf initrd-tree.tar.gz
else
 echo  "
./initrd-tree.tar.gz not found
/usr/share/mkinitrd/initrd-tree.tar.gz not found
 
get and install mkinitrd package ... exit
"
 exit
fi
 
echo "Creating the folder structure ..."
#--------------------------------------------------------
mkdir -p work/initramfs/{dev,bin,sbin,lib,etc,proc,sys,newroot,usr,usr/bin,usr/sbin}
 
#Create device nodes
mknod work/initramfs/dev/null c 1 3
mknod work/initramfs/dev/tty c 5 0
mknod work/initramfs/dev/console c 5 1
 
cp -f ./initrd-tree/bin/busybox ./work/initramfs/bin/
 
#Check if busybox is a static binary
LIBLIST=`ldd  ./work/initramfs/bin/busybox  | grep /lib | cut -d'/' -f3 | cut -d'(' -f1 | cut -d' ' -f1`
 
if [ "a$LIBLIST" != "a" ] ; then
 IFS=
 echo $LIBLIST |
 while read LIBNAME
 do
  #Copy libs if busybox not static
  cp -f /lib/$LIBNAME ./work/initramfs/lib/
 done
fi
 
cd work
touch initramfs/etc/mdev.conf
 
chmod +x initramfs/bin/busybox
ln -s busybox initramfs/bin/sh
 
echo "Creating a init script"
#--------------------------------------------------------
echo '#!/bin/sh
 
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
 
#Mount things needed by this script
busybox mount -t proc proc /proc
busybox mount -t sysfs sysfs /sys
 
#Create all the symlinks to /bin/busybox
/bin/busybox --install -s
 
touch /etc/mtab
 
#Disable kernel messages from popping onto the screen
echo 0 > /proc/sys/kernel/printk
 
#Clear the screen
clear
 
echo
echo
echo "------------------------------------"
echo "   **** RamUSB Boot v 0.7.1 ****    "
echo "------------------------------------"
echo
 
echo /bin/mdev > /proc/sys/kernel/hotplug
 
#Scan for devices
mdev -s
 
#Defaults
init="/sbin/init"
root="/dev/sda1"
 
HD_FOUND=
 
#Get USB-disk SIGNATURE
USB_LABEL=
COMMAND_LINE=`cat /proc/cmdline`
 
#adjust command line, remove white spaces, etc.
COMMAND_LINE=`echo $COMMAND_LINE | sed s/\s+//`
COMMAND_LINE=`echo $COMMAND_LINE | sed "s/ =/=/g"`
COMMAND_LINE=`echo $COMMAND_LINE | sed "s/= /=/g"`
 
R_RW_OPT="-r"
FS_TYPE=""
ROOTDEV=""
 
#Parse 12 option parameters
#------------------------------------------------
 
for i in 1 2 3 4 5 6 7 8 9 10 11 12
do
 
 OPTION=`echo "$COMMAND_LINE" | cut -d" " -f$i`
 PARAM=`echo "$OPTION" | cut -d"=" -f1`
 VALUE=`echo "$OPTION" | cut -d"=" -f2`
 
 #Test ro|rw mount option
 case "$OPTION" in
  "ro" | "read-only")  R_RW_OPT="-r";;
  "rw" | "read-write") R_RW_OPT="-w";;
 esac
 
 #Test fs type
 if [ "a$PARAM" = "arootfstype" ] ; then
   FS_TYPE="-t $VALUE"
 fi
 
 #Test root device
 if [ "a$PARAM" = "aroot" ] ; then
   ROOTDEV="$VALUE"
 fi
 
 if [ "a$PARAM" = "aUSB_DISK_SIGNATURE" ] ; then
   USB_LABEL=$VALUE
 fi
 
done
 
export R_RW_OPT=$R_RW_OPT
export FS_TYPE=$FS_TYPE
export ROOTDEV=$ROOTDEV
 
export IFS=`echo -ne " \t\n"`
 
#Search for disk signature in HDs
#------------------------------------------------
 
if [ "a$USB_LABEL" != "a" ] ; then
 
 #Try to mount USB-disk
 echo -n "Searching disk signature: $USB_LABEL "
 
 #Rescan for new devices
 mdev -s
 
 #Try to mount all HD devices
 #---------------------------------------------
 
 ls -1 /dev/hd* 2> /dev/null |
 while
  read TRY_DISK
  do
   mount $R_RW_OPT $FS_TYPE $TRY_DISK /newroot 1> /dev/null 2> /dev/null
   if [ -e /newroot/$USB_LABEL ] ; then
    echo "$USB_LABEL --> HARD DISK $TRY_DISK found"
    HD_FOUND="yes"
    break
   fi
   umount $TRY_DISK 2> /dev/null
 done
 
fi
 
#Search for disk signature in SDs
#------------------------------------------------
 
if [ "a$USB_LABEL" != "a" ] && [ "a$HD_FOUND" = "a" ] ; then
 
 #Try to mount USB-disk
 
 n=0
 
 #Repeat test 10 times
 while [ $n -le 9 ]
 do
  #Rescan for new devices
  mdev -s
 
  #Try to mount all sd devices
  #---------------------------------------------
 
  ls -1 /dev/sd* 2> /dev/null |
  while
   read TRY_DISK
   do
    mount $R_RW_OPT $FS_TYPE $TRY_DISK /newroot 1> /dev/null 2> /dev/null
    if [ -e /newroot/$USB_LABEL ] ; then
     echo
     echo "$USB_LABEL found in --> $TRY_DISK"
     echo
     break
    fi
    umount $TRY_DISK 2> /dev/null
  done
  #---------------------------------------------
 
  if [ -e /newroot/$USB_LABEL ] ; then
   break
  fi
 
  sleep 1
  let n=$n+1
  echo -n "."
 done
 
 echo " done."
 
fi
 
IS_ROOT_MOUNTED=`mount | grep /newroot`
 
#Check if root is INIRAMFS system
#--------------------------------
 
IS_INITRAMFS=`echo $ROOTDEV | grep .igz`
 
if [ "a$IS_INITRAMFS" != "a" ] ; then
 cp /newroot/$USB_LABEL/$ROOTDEV /
 DEV_MOUNTED=`mount | grep /newroot | cut -d" " -f1`
 umount /newroot
 eject $DEV_MOUNTED 2>/dev/null
 
 mount -t tmpfs none /newroot
 cd /newroot
 gzip -dc ../$ROOTDEV | cpio -idm 2> /dev/null
 cd /
 rm -f $ROOTDEV
 
else
 
 #Check if device with LABEL is mounted
 #-------------------------------------
 if [ "a$USB_LABEL" != "a" ] ; then
 
  if [ "a$IS_ROOT_MOUNTED" != "a" ] ; then
 
   #try also to mount USB_SIGNATURE_FILE as loop device
   #---------------------------------------------------
   if [ -f /newroot/$USB_LABEL ] ; then
    mount /newroot/$USB_LABEL /newroot -o loop  1> /dev/null 2> /dev/null
   fi
 
  else
   echo "Error: disk signature <<$USB_LABEL>> not found !!!"
 
  fi
 fi
fi
 
#If nothing mounted try root= parameter
#------------------------------------------------
if [ "a$IS_ROOT_MOUNTED" = "a" ] && [ "a$ROOTDEV" != "a" ] ; then
 echo "Try to mount append device root=$ROOTDEV ..."
 mount $R_RW_OPT $FS_TYPE $ROOTDEV /newroot 1> /dev/null 2> /dev/null
fi
 
IS_ROOT_MOUNTED=`mount | grep /newroot`
 
#If nothing mounted ... ask
#------------------------------------------------
 
if [ "a$IS_ROOT_MOUNTED" = "a" ] ; then
 echo "Error: root device not mounted ..."
 echo -n "give me another device to try (ex: /dev/sda1) : "
 read ALT_DEVICE
 
 echo "mount $R_RW_OPT $FS_TYPE $ALT_DEVICE /newroot"
 mount $R_RW_OPT $FS_TYPE $ALT_DEVICE /newroot 1> /dev/null 2> /dev/null
fi
 
#Check if $init exists and is executable
#------------------------------------------------
 
#check if perform chroot to /pathname, before
if [ -d /newroot/$USB_LABEL ] && [ -x "/newroot/$USB_LABEL/${init}" ] ; then
 #Unmount all other mounts so that the ram used by
 #the initramfs can be cleared after switch_root
 umount /sys /proc
 
 #Switch to the new root and execute init
 mount -o bind /newroot/$USB_LABEL /newroot
 exec switch_root /newroot "${init}"
fi
 
if [[ -x "/newroot/${init}" ]] ; then
 #Unmount all other mounts so that the ram used by
 #the initramfs can be cleared after switch_root
 umount /sys /proc
 
 #Switch to the new root and execute init
 exec switch_root /newroot "${init}"
fi
 
#This will only be run if the exec above failed
echo "Failed to switch_root, dropping to a shell"
exec sh' > initramfs/init
 
chmod +x initramfs/init
 
echo "Creating the .cpio and .igz ..."
#--------------------------------------------------------
cd initramfs
find . | cpio -H newc -o > ../ramusb.cpio
cd ..
cat ramusb.cpio | gzip > ramusb.igz
 
echo "Done."

Configure LILO

To boot properly you must set a signature file (i.e "touch /etc/mySlack13.1") and pass this file name as kernel command line in lilo.conf. Example of lilo.conf:

image = /boot/vmlinuz-huge-smp-2.6.xx.x-smp
label = myUSBSlack
initrd=/boot/ramusb.igz
read-only
append = "USB_DISK_SIGNATURE=etc/mySlack13.1"

/etc/fstab

In latest Slackware, kernel works fine with /dev/root device, so fstab may contain only a line:

/dev/root / auto defaults 1 1

Retrieved from "http://www.zoros.org/wiki/index.php?title=Ramusb.igz,_another_way_to_boot_Linux_from_USB_stick_and_other_media"