The hobby of bootable media

Andrew Elian e_lion_1 at hotmail.com
Mon Apr 23 16:23:35 PDT 2012


Hello one and all,

I've been puttering away with LFS 7.1 and turning it into a bootable
DVD.  The end result does boot and work in qemu.  Perhaps there is an
adventurous soul would like to try it out.  I wouldn't mind some
feedback on it.

Thanks!
ae
-- 
My Blog: http://elian001.wordpress.com
-------------- next part --------------
AUTHOR:        Andrew Elian <e_lion_1 at hotmail dot com>
INITIAL DATE:  2010-05-16
UPDATED:       2012-04-23
LICENSE:       GNU Free Documentation License Version 1.2
SYNOPSIS:      Bootable DVD creation 
DESCRIPTION:
  A brief guide on creating a complete LFS resuce DVD, using initramfs.  I have
  named my take of LFS: dLFS.  Be sure to change it to what you like!

PREREQUISITES:
    Time:            Even more time
    "Fresh" LFS:     7.1
    busybox:         1.19.4

    A host linux system with the following:
    syslinux:        4.04
    nasm:            2.07   (Needed only to compile syslinux)
    dvd+rw-tools:    7.1
    (GNU) cpio:      2.9
    cdrtools:        2.01   (Optional)
    qemu:            0.12.3 (Optional)

  Instructions for cdrtools, dvd+rw-tools, cpio and nasm can be found in the BLFS book. 

HINT:

This hint assumes that the instructions are done as root.
  Prepare the environment:
    export ROOTFS=<ROOTFS>
    export RESCUE=<RESCUE>
  Variable $LFS needs to be set too!

  Create the needed directories:
    mkdir -pv $ROOTFS
    mkdir -pv $RESCUE

  Install the needed programs on the host system.

  Unpack and build busybox:
    cd busybox-1.19.4
    make menuconfig
      Busybox Settings  --->
        Installation Options  --->
          ( <ROOTFS> ) BusyBox installation prefix
    make
    make install
  I found the default configuration to work well. Be sure to set the
  installation prefix as this will install the programs into $ROOTFS.

  Unpack and install syslinux on the host system if needed:
    cd syslinux-4.04
    make
    make install
  You may want to check and edit MCONFIG before running make.

  Create the ROOTFS init script:

cat > $ROOTFS/init << "EOF"
#!/bin/sh
# Begin /init

NORMAL="\\033[0m"
BRED="\\033[1;31m"
BBLUE="\\033[1;34m"
BCYAN="\\033[1;36m"
GREEN="\\033[0;32m"
BGREEN="\\033[1;32m"
YELLOW="\\033[0;33m"
BYELLOW="\\033[1;33m"

# Find current screen size
# Borrowed from LFS functions script

  if [ -z "${COLUMNS}" ]; then
    COLUMNS=$(stty size)
    COLUMNS=${COLUMNS##* }
  fi

ECOL=$((${COLUMNS} - 2))
END_COL="\\033[${ECOL}G"

fancy()
{
  width=""
  width=$(( ($COLUMNS / 2) + (${#2}/2) - 3))
  echo -n -e " >>"
  printf "${1}%${width}s\c" "${2}"
  echo -n -e "${NORMAL}${END_COL}<<"
  echo
}

fancy ${BRED} ">> Mounting Kernel File Systems <<"
mount -n /proc
mount -n /sys

fancy ${BRED} ">> Running mdev <<"
echo > /proc/sys/kernel/hotplug
mdev -s

# Mount the DVD AutoMagically

fancy ${YELLOW} ">> Finding DVD <<"
for DEV in /sys/block/[hs]*                                                                                              
do                                                                                                                       
  C=$(cat $DEV/removable)
    case $C in
      1)  DNAME=`basename $DEV`
          if mount -o ro -t iso9660 /dev/$DNAME /media/dvd >/dev/null 2>&1; then
            fancy ${BYELLOW} ">> Found /dev/$DNAME <<"
            fancy ${BYELLOW} ">> Checking for dLFS-live <<"
            if [ -e /media/dvd/dLFS-live ]; then
                DVD_FOUND="/dev/$DNAME"
              else
                umount /media/dvd
            fi
          fi
      ;;
      0)
      ;;
    esac
done

mount -o ro -t iso9660 $DVD_FOUND /media/dvd >/dev/null 2>&1
umount -l /sys
umount -l /proc

fancy ${BGREEN} ">> Switching Root <<"
exec switch_root /media/dvd /sbin/init

# End /init
EOF
  Make the scipt executable
    chmod +x $ROOTFS/init

  Create some needed subdirectories
    mkdir -pv $ROOTFS/{dev,etc,lib,media/dvd,proc,sys}

  Add a few needed devices:
    mknod $ROOTFS/dev/console c 5 1
    mknod $ROOTFS/dev/null c 1 3
    mknod $ROOTFS/dev/tty c 5 1

  Copy needed shared libraries to $ROOTFS/lib.
    cp -v /lib/ld-linux-x86-64.so.2 $ROOTFS/lib
    cp -v /lib/libcrypt.so.1 $ROOTFS/lib
    cp -v /lib/libc.so.6 $ROOTFS/lib
    cp -v /lib/libm.so.6 $ROOTFS/lib

  ld-linux-x86-64.so.2 may be different depending on your host, so adjust accordingly.

  Create a link to lib, if needed:
    ln -sv ./lib $ROOTFS/lib64

  Create a minimal fstab for $ROOTFS:
cat > $ROOTFS/etc/fstab << "EOF"
proc     /proc    proc     defaults          0  0
sysfs    /sys     sysfs    defaults          0  0
devpts   /dev/pts devpts   gid=4,mode=620    0  0
EOF

  Create the raminitfs:
    cd $ROOTFS
    find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
    cd ../

  Prepare the rescue system:
  From BLFS, I usually add gpm (1.20.6), links (2.2), and dhcpcd (5.5.6) to the
  fresh LFS system. I found the easiest way to setup the rescue system was to copy 
  newly completed LFS system.
    cp -a $LFS/* $RESCUE 
  
  Some modifications are needed for the system work off a read only filesystem.
  Create needed links
    cd $RESCUE/etc
      rm localtime resolv.conf
      ln -sv /var/localtime localtime
      ln -sv /var/resolv.conf resolv.conf
      rm $RESCUE/etc/mtab
      ln -sv /proc/mounts mtab
    cd $RESCUE
      ln -sv /var/tmp tmp

  Modify the filesystem
    mkdir -pv $RESCUE/static
    mv -v $RESCUE/root $RESCUE/static/
    mkdir -v $RESCUE/static/lfs

  Create an empty file:

    touch $RESCUE/dLFS-live
  The startup script from $ROOTFS looks for the existence of this file.

  The rescue image needs a minimal fstab.  Replace the current fstab with the
  following:
    rm $RESCUE/etc/fstab
cat > $RESCUE/etc/fstab << "EOF"
# Begin /etc/fstab

proc           /proc        proc     nosuid,noexec,nodev 0     0
sysfs          /sys         sysfs    nosuid,noexec,nodev 0     0
devpts         /dev/pts     devpts   gid=4,mode=620      0     0
tmpfs          /run         tmpfs    defaults            0     0
devtmpfs       /dev         devtmpfs mode=0755,nosuid    0     0

# End /etc/fstab
EOF

  This live DVD uses custom BSD style boot scripts instead of the LFS standard SYS V.
  Mostly I found it a little easier to work with and modify.
  
  Remove the $RESCUE/etc/init.d link and create a directory:
    rm $RESCUE/etc/init.d
    mkdir $RESCUE/etc/init.d

cat > $RESCUE/etc/init.d/rc.common << "EOF"
#!/bin/bash
# Begin /etc/init.d/rc.common
# Common reused code

NORMAL="\\033[0m"
RED="\\033[0;31m"
BRED="\\033[1;31m"
GREEN="\\033[0;32m"
BGREEN="\\033[1;32m"
YELLOW="\\033[0;33m"
BYELLOW="\\033[1;33m"
BLUE="\\033[0;34m"
BBLUE="\\033[1;34m"
MAGENTA="\\033[0;35m"
BMAGENTA="\\033[1;35m"
CYAN="\\033[0;36m"
BCYAN="\\033[1;36m"
WHITE="\\033[0;37m"
BWHITE="\\033[01;37m"

# Find current screen size
if [ -z "${COLUMNS}" ]; then
  COLUMNS=$(stty size)
  COLUMNS=${COLUMNS##* }
fi

ECOL=$((${COLUMNS} - 2))
END_COL="\\033[${ECOL}G"

fancy()
  {
    width=""
    width=$(( ($COLUMNS / 2) + (${#2}/2) - 3))
    echo -n -e " >>"
    printf "${1}%${width}s" "${2}"
    echo -n -e "${NORMAL}${END_COL}<<"
    echo
  }

# End /etc/init.d/rc.common
EOF

cat > $RESCUE/etc/init.d/rc.S << "EOF"
#!/bin/bash
# Begin system init script
# With parts borrowed from LFS bootscripts

source /etc/init.d/rc.common

# Mount kernel filesystems
fancy ${RED} ">> Mounting kernel-based file systems <<"
mkdir -p /run
mount -n /run 
mkdir -p /run/{var,lock,shm}
chmod 1777 /run/shm

mount -n -o nosuid,noexec,nodev /proc
mount -n -o nosuid,noexec,nodev /sys
mount -n -o mode=0755,nosuid /dev
ln -s /run/shm /dev/shm

# Set the default loglevel
LOGLEVEL=7
fancy ${RED} ">> Console log level to ${LOGLEVEL} <<"
dmesg -n $LOGLEVEL

# Start udev
fancy ${YELLOW} ">> Creating device nodes <<"
mount -n -t tmpfs tmpfs /dev -o mode=755
echo > /proc/sys/kernel/hotplug
cp -a /lib/udev/devices/null /dev
/sbin/udevd --daemon
/sbin/udevadm trigger --action=add
/sbin/udevadm settle

# Create RAM disk
fancy ${YELLOW} ">> Preparing RAM disk <<"
mount -t tmpfs -o size=5M tmpfs /var
mkdir -p /var/{lock,log,mail,run,spool,tmp}
mkdir -p /var/{opt,cache,lib/{dhcpcd,misc,locate},local}
touch /var/run/utmp /var/log/{btmp,lastlog,wtmp}
cp /usr/share/zoneinfo/Canada/Saskatchewan /var/localtime
cp -a /static/{root,lfs} /var
chmod 755 /var/lfs
chmod 750 /var/root
chmod 1777 /var/tmp
chown lfs.lfs /var/lfs

fancy ${GREEN} ">> Mounting file systems <<"
mount -a -O no_netdev >/dev/null

fancy ${GREEN} ">> Bringing up the loopback interface <<"
ip addr add 127.0.0.1/8 label lo dev lo
ip link set lo up

source /etc/sysconfig/network
fancy ${GREEN} ">> Setting hostname to ${HOSTNAME} <<"
hostname ${HOSTNAME}

source /etc/sysconfig/console
ECHO="/bin/echo"
fancy ${GREEN} ">> Loading keymap and font <<"
     [ -z "${KEYMAP}" ] ||
         loadkeys ${KEYMAP} >/dev/null 2>&1
     [ -z "${FONT}" ] ||
          setfont ${FONT}

# End /etc/init.d/rcS
EOF

cat > $RESCUE/etc/init.d/rc.M << "EOF"
#!/bin/bash
# Going Multi-user

source /etc/init.d/rc.common

fancy ${BGREEN} ">> Starting system log daemon <<"
syslogd -m 0

fancy ${BGREEN} ">> Starting kernel log daemon <<"
klogd

if [ -f /etc/sysconfig/mouse ]
   then
   . /etc/sysconfig/mouse
fi

fancy ${BGREEN} ">> Starting gpm <<"
/usr/sbin/gpm -m $MDEVICE -t $PROTOCOL $GPM

if [ -e /sys/class/net/eth0 ];
then
  for DEV in /sys/class/net/eth[01]
  do
    NAME=$(basename $DEV)
    dhcpcd -q $NAME
      if [ $? = 0 ]; then
        fancy ${BGREEN} ">> Started dhcpcd on $NAME <<"
      else
        fancy ${RED} ">> Problems starting dhcpcd on $NAME <<"
      fi
  done
fi

fancy ${BCYAN} ">> Welcome! Login as lfs for normal user <<"

# End /etc/init.d/rc.M
EOF

cat > $RESCUE/etc/init.d/rc.K << "EOF"
#!/bin/bash
# Reboot/Halt Script

source /etc/init.d/rc.common

fancy()
{
  width=""
  width=$(( ($COLUMNS / 2) + (${#2}/2) - 3))
  echo -n -e " >>"
  printf "${1}%${width}s" "${2}"
  echo -n -e "${NORMAL}${END_COL}<<"
  echo
}

if [ -e /sys/class/net/eth0 ];
then
  for DEV in /sys/class/net/eth[01]
  do
    NAME=$(basename $DEV)
    dhcpcd -q -k $NAME
    if [ $? = 0 ]; then
      fancy ${BBLUE} ">> Stopped dhcpcd on $NAME <<"
    fi
  done
fi
fancy ${BBLUE} ">> TERM signal sent <<"
/sbin/killall5 -15
sleep 1

fancy ${BBLUE} ">> KILL signal sent <<"
/sbin/killall5 -9
sleep 1

case "$0" in
  *6)
    /sbin/reboot -w
  ;;
  *0)
    /sbin/halt -w
  ;;
esac


fancy ${BBLUE} ">> Unmounting local filesystems <<"
/bin/umount -a > /dev/null 2>&1
sleep 1
/bin/umount -a > /dev/null 2>&1

case "$0" in
  *6)
    fancy ${BYELLOW} ">> Rebooting <<"
    /sbin/reboot -d -f -i
  ;;
  *0)
    fancy ${BCYAN} ">> Bye <<"
    /sbin/halt -d -f -p
  ;;
esac

# End /etc/init.d/rc.K
EOF

cat > $RESCUE/etc/init.d/rc.1 << "EOF"
#!/bin/bash
# Single User

# Stop Networking, if any
if [ -e /sys/class/net/eth[01] ];
then
  for DEV in /sys/class/net/eth[01]
  do
    NAME=$(basename $DEV)
    dhcpcd -q -k $NAME
      if [ $? = 0 ]; then
        fancy ${BRED} ">> Stopped dhcpcd on $NAME <<"
      fi
  done
fi

# Kill all processes.
fancy ${BRED} ">> Sending all processes the SIGHUP signal <<"
killall5 -1
fancy ${BRED} ">> Sending all processes the SIGTERM signal <<"
killall5 -15
fancy ${BRED} ">> Sending all processes the SIGKILL signal <<"
killall5 -9

# End /etc/init.d/rc.1
EOF

  Create a couple of links to the kill script
    cd $RESCUE/etc/init.d
    ln -s rc.K rc.6
    ln -s rc.K rc.0

  Make sure that the scripts are executable:
    chmod -v +x rc.1 rc.K rc.M rc.S

  Replace the default /etc/inittab with this one:

    rm -v $RESCUE/etc/inittab
cat > $RESCUE/etc/inittab << "EOF"
# Begin /etc/inittab

id:2:initdefault:

si::sysinit:/etc/init.d/rc.S sysinit

l0:0:wait:/etc/init.d/rc.0
l1:S1:wait:/etc/init.d/rc.1
l2:2:wait:/etc/init.d/rc.M
l6:6:wait:/etc/init.d/rc.6

ca:12:ctrlaltdel:/sbin/shutdown -t1 -a -r now

su:S1:respawn:/sbin/sulogin

1:2:respawn:/sbin/agetty tty1 9600
2:2:respawn:/sbin/agetty tty2 9600
3:2:respawn:/sbin/agetty tty3 9600

# End /etc/inittab
EOF
  
  This will tell init to use the custom bootscripts.

  Add the lfs user by adding a line to the passwd and group files and creating a home
  directory:
    echo "lfs::1000:1500::/var/lfs:/bin/bash" >> $RESCUE/etc/passwd
    echo "lfs:x:2000:" >> $RESCUE/etc/group
  
  Modify $RESCUE/etc/passwd so root's $HOME is changed.
    sed 's/\/root/\/var\/root/g' $RESCUE/etc/passwd > $RESCUE/etc/passwd.new
    rm $RESCUE/etc/passwd
    mv -v $RESCUE/etc/passwd.new $RESCUE/etc/passwd

  Finish the modifications:
    mkdir -pv $RESCUE/static
    mv -v $RESCUE/root $RESCUE/static
    mkdir -pv $RESCUE/static/lfs
    cp -va $RESCUE/etc/skel/.bash* $RESCUE/static/lfs

  This moves or creates the home directories for root and lfs which are then copied into the 
  ramdisk during startup.

  According to your preference, add a password for root and lfs. Or not.
  Since the default LFS bootscripts are not used, they can be removed safely.

  Install isolinux by:
    mkdir -pv $RESCUE/boot/isolinux
    cd $RESCUE/boot/isolinux

cat > $RESCUE/boot/boot.msg << "EOF"
dLFS LiveDVD
EOF

cat > $RESCUE/boot/isolinux.cfg << "EOF"
display boot.msg

DEFAULT LiveDVD
    LABEL LiveDVD
    KERNEL /boot/vmlinux
    APPEND root=/dev/ram0 initrd=/boot/rootfs.cpio.gz quiet
EOF

    Of course, be sure to put the name of your kernel in the right place.  I had
    mistyped vmlinux vmlinuz and wondered why it wasn't working!

    cp /usr/share/syslinux/isolinux.bin $RESCUE/boot/isolinux
    cd $RESCUE/../
    mv -v rootfs.cpio.gz $RESCUE/boot/rootfs.cpio.gz

  Now create the dvd image:
    mkisofs -r -J -l -no-emul-boot -boot-load-size 4 -boot-info-table \
    -graft-points -iso-level 4 -pad -allow-leading-dots -b \
    boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -o RESCUE.iso ./RESCUE

  Test the image with the right qemu, which for me is qemu-system-x86_64.
    qemu-system-x86_64 -net nic,vlan=1 -net user,vlan=1 -cdrom RESCUE.iso -boot d -m 512

  Burn to DVD:
    growisofs -Z /dev/hdc=RESCUE.iso

  Or burn to CD if the image is small enough:
    cdrecord -v dev=/dev/hdc RESCUE.iso

  If the ISO image is too large, recompressing all of the sources with xz works very well.
    
BUGS:
  BLFS now uses xorriso instead of cdrtools, but I'm not familiar with it.
  Suggestions and improvements welcome. 
 
ACKNOWLEDGEMENTS:
  LFS. The reason I can do UNIX like things on my computer!
  LFS liveCD. Provided lots of inspiration.
  boot-cd_easy hint. Now a bit outdated but I found it very useful.
  Slackware. It's been around this long for a reason.

CHANGELOG:
[2010-05-16]
  Initial hint creation.
[2010-11-11]
  Edited for clarity.
[2011-08-05]
  Changed to BSD style bootscripts.
  Updated to Syslinux 4.04.
[2012-04-23]
  Updated to busybox 1.19.4  
  Changed the instructions so as not to use a chroot.
  Modified the startup scripts to be in sync with LFS bootscripts.
  Removed screen.


More information about the lfs-chat mailing list