You are here

Live CD With LFS

Uditha Atukorala's picture

AUTHOR: Mike Hernandez

DATE: 2005-09-03

LICENSE: GNU Free Documentation License Version 1.2

SYNOPSIS: Beginners Guide To Creating A Live CD With LFS 6.0

ALTERNATE LOCATION: For most recent edition of this hint you can check
http://www.culmination.org/Mike/2.6-udev-nptl-bootcd.txt

DESCRIPTION:
This hint is a detailed description of how I made a live cd from a system
built with LFS 6.0. The reader should be able to follow the hint to create
a live cd of his or her own. It was adapted from the "Easy" hint to work with
LFS 6.0. It is my intention to make it as easy as possible for a first time
live cd builder.

PREREQUISITES:
1. A working LFS System (and cdrtools if you want to burn the cd, of course)
2. An LFS system built for the purpose of creating a live cd (see below)
3. CD Writer + Media (but you knew that, I bet)
4. Syslinux (http://freshmeat.net/projects/syslinux/)

HINT:

Before we get started here, let me make some things clear.

I call this section:

------------------------------
| What it is and what it ain't |
------------------------------

------------
| What it is |
------------

This is a hint for creating a simple live cd. To be more clear:
Upon booting from the cd, a user will be presented with a linux prompt.

If you build it from an LFS system (no BLFS stuff) then the cd will be
helpful for repairing an LFS system that got messed up (menu.lst typos
/etc/fstab weirdness, things like that).

Creating live cd's can be fun, and knowing how to do so opens up the door
for many possibilities. This hint is a good starting point for that
"ultimate rescue cd" idea you've had or maybe can help you answer the
"I wonder if Linux will run on my _____" question =)

---------------
| What it ain't |
---------------

As I said above, this will help you make a simple livecd. The user will be
presented with a linux prompt and not much else beyond that unless you add
the functionality yourself.

This hint does not describe how to put tons of software on the cd as you
might find on knoppix or the official LFS boot CD.

This hint does not describe how to create an install program to copy the
contents of the cd onto a hard drive.

Also, you will not find any cross-compiling info here, so if you want your
CD to boot on a completely different architecture than your own, you have
to do that research yourself.

--------------------------------------------------
| Why it is what it is, and it ain't what it ain't |
--------------------------------------------------

This hint is designed to help a first time live cd builder. I tried to keep
it as simple as possible, so that it wouldn't require too much advanced
knowledge of LFS to complete (the hint it's based on is called the "Easy"
boot CD hint, after all.) Of course you need to know a bit, but expert
knowledge is not a requirement. Creating an install CD, or using
filesystems such as squashfs, may require more info than a beginner might
have, and attempting to include all of it might make this hint more
confusing than helpful.

---------------
| The Beginning |
---------------

This hint, like the hint it is based on, requires that the reader have two
(yes 2) systems built. One system is your usual working system, which you
will use to burn the cd when you are done. The other is the system created
specifically for the purpose of putting on the live CD. If you just want
the CD to boot on the machine you built it on, then making a copy of your
LFS system to another partition is fine.

You might be wondering why you need two systems to create a live CD. The
reason is actually quite simple. If you are like me, you optimized your LFS
system to suit your pc (or in my case, laptop). I have a Pentium 4 system,
so all of the programs which can handle optimization have been built with:

CFLAGS='-march=pentium4'

So what's the issue? It's that I want my live CD to run on just about
anything that can boot a CD! The programs on my current system won't run on
any machine that isn't a pentium 4. I actually use many more optimizations
when I build, but here I mention the architecture because it brings up an
important point:

----------------------------------------------------------
| Know in advance what hardware you want the CD to run on! |
----------------------------------------------------------

Before you start you should also decide what you want your live CD to do.
You may want to consider optimizing everything in your live CD system for
size, or for a specific type of machine, or not to optimize at all.
Which is best? That's up to you.

Another reason you want to have a separate system is because in order to
create the CD we make some directories and move very important files
around. In the event that something goes wrong, having at least your
initial working system (if not a backup of the live CD system) can be a
life saver.

----------------------------
| Setting up the environment |
----------------------------

To make things easier, you should set the LIVECD variable to point to the
mount point of the system you are going to use for the CD:

export LIVECD=/mnt/livecd

You also might want to set CDDEV as well (actually, you should):

export CDDEV=/dev/your-drive+partition

Set the ISODIR to the location where you would like to keep the image:

export ISODIR=/where/you/have/space

--------------------------------
| Configuring the live CD system |
--------------------------------

Now that the environment is all set up, it's time to do some final
configuration of the live CD system. This includes making sure the kernel
is how you want it, and maybe adding some other programs if you so desire.

If you are absolutely sure that the kernel for your CD system will work for
the system you want the CD to run on, and you don't need to install any
other software for your CD, then you can skip to the section called
"Moving around the furniture".

Before we can configure and install a new kernel for the live CD, we have
to chroot into the system:

1. Mount your live CD system:

mkdir -p $LIVECD
mount $CDDEV $LIVECD

2. As per the directions of the LFS-6.0 book,
mount the virtual file systems prior to entering the chroot:

mount -t proc proc $LIVECD/proc
mount -t sysfs sysfs $LIVECD/sys
mount -f -t ramfs ramfs $LIVECD/dev
mount -f -t tmpfs tmpfs $LIVECD/dev/shm
mount -f -t devpts -o gid=4,mode=620 devpts $LIVECD/dev/pts

3. chroot into the live CD system with the command given at the end of
chapter 6. (NOT THE CHROOT COMMAND AT THE BEGINNING!!!):

chroot $LIVECD /usr/bin/env -i \
HOME=/root TERM=$TERM PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/bin/bash --login

4. mount ramfs and populate /dev

mount -n -t ramfs none /dev
/sbin/udevstart

5. Create essential symlinks and directories not created by udev:

ln -s /proc/self/fd /dev/fd
ln -s /proc/self/fd/0 /dev/stdin
ln -s /proc/self/fd/1 /dev/stdout
ln -s /proc/self/fd/2 /dev/stderr
ln -s /proc/kcore /dev/core
mkdir /dev/pts
mkdir /dev/shm

6. Perform the mounting of the proper virtual (kernel) file systems:

mount -t devpts -o gid=4,mode=620 none /dev/pts
mount -t tmpfs none /dev/shm

Now you are in the chroot, so you can configure and build the kernel for
the CD. If you are absolutely sure that the kernel for your CD system
will work for the system you want the CD to run on, then you can skip this
part and just install the software you need.

Building the kernel for your live CD is not something to be taken lightly
by even a veteran! There are options which need to be built in and others
which can be built as modules. I assume that if you feel you are ready to
create a live CD out of your system, that you know what you are doing. I do
suggest not using modules, because it can create issues if you aren't
familiar with all the work that goes into using modules with the 2.6 kernel
and udev. Be Careful! =)

When you are done installing your kernel you might want to test it to be
sure it works. Once you are all set, then you should exit the chroot and
run the rest of the commands from your working system, as root.

-----------------------------
| Moving around the furniture |
-----------------------------

A.K.A. Moving /dev /etc /home /root /tmp /var to /fake/needwrite

When I followed the "Easy" hint, I came to this point and wondered:
What is /fake/needwrite? (Actually it was more like "what the hell is this
/fake/needwrite stuff?") Here is an answer for those of you wondering the
same:

The /fake/needwrite directory is used to hold files that must be writable
while the live CD is running. Obviously, these files can not remain on the
CD-ROM (due to the RO part of ROM), and so they are moved to a location from
which they will be copied into a ramdisk during the CD boot process. Having
the files in a ram disk allows us to modify them. Also, we can create files in
the directories which reside on the ram disk, such as in /tmp, or /home.

First we have to create the directory and a mount point for the ramdisk:

* NOTE: If you haven't already mounted your CD system, do so now:
* mount $CDDEV $LIVECD
* thanks Bernard, for pointing this out ;)

mkdir -p $LIVECD/fake/{needwrite,ramdisk}

Then we can move the directories which we want to have write access there:

cd $LIVECD/
mv dev/ etc/ home/ root/ tmp/ var/ fake/needwrite/

Now we have to create symlinks so that everything seems to be as before.

cd $LIVECD/
ln -s fake/needwrite/dev dev
ln -s fake/needwrite/var var
ln -s fake/needwrite/tmp tmp
ln -s fake/needwrite/root root
ln -s fake/needwrite/home home
ln -s fake/needwrite/etc etc

At this point, execute ls -l
The output should say:

dev -> fake/needwrite/dev
etc -> fake/needwrite/etc
home -> fake/needwrite/home
root -> fake/needwrite/root
tmp -> fake/needwrite/tmp
var -> fake/needwrite/var

---------------------------------------------
| Tailoring the CD boot process for our needs |
---------------------------------------------

Ok, we have /etc /dev /var /tmp /root /home linked to /fake/needwrite which
is read-only (because it's on the CD). To be able to login (and to run
services which need write access to /dev /var /tmp /root /home or /etc) we
must call a script from our /etc/rc.d/init.d/ directory which mounts a ram
disk on /fake/needwrite with write access.

The following script creates 2 ram disks, a temporary one, and one that
will house the directories which need write permission. It copies the files
from the CD to the temporary ram disk, and then from there to the final ram
disk.

The original hint used 1 ram disk, but this caused a serious problem for me.
First of all, the initrd which is loaded at boot time uses the first ramdisk
(/dev/ram0). Therefore trying to mount /dev/ram0 somewhere else leads to
"device already mounted" errors. Secondly, unmounting a ram disk causes
all of the files to be lost. The original hint unmounted the ram disk and
remounted it, assuming the files would still be there. That did not work for
me, which is why I made sure that /dev/ram{0,1,2} are all present, and
suggest that you do the same. If they aren't present you should check your
udev setup. You might try using mknod to create the files, but for now
I will say if you don't have /dev/ram devices, you are going to have to
do some research on your own to figure out why.

* Bernard suggested a for loop for doing this, which you might try:
* for i in 0 1 2 3 4 5 6 7; do
* mknod $LIVECD/dev/ram$i b 1 $i;
* done

Copy and paste the script, and tailor it to your needs as necessary:

cat > $LIVECD/etc/rc.d/init.d/create_ramdisk << "EOF"
#!/bin/sh

# SET UP SOME VARIABLES FOR DEVICES AND DIRECTORIES

dev_ram=/dev/ram1
dev_ram2=/dev/ram2
dir_ramdisk=/fake/ramdisk
dir_needwrite=/fake/needwrite

# SOURCE THE FUNCTIONS FILE

source /etc/rc.d/init.d/functions

case "$1" in
start)

# CREATE THE RAM DISK

echo "Creating ext2fs on $dev_ram..."
/sbin/mke2fs -m 0 -i 1024 -q $dev_ram > /dev/null 2>&1
evaluate_retval
sleep 1

# MOUNT THE RAM DISK

echo "Mounting ramdisk on $dir_ramdisk..."
mount -n $dev_ram $dir_ramdisk -t ext2
evaluate_retval
sleep 1

# COPY FILES TO THE RAM DISK

echo "Copying files to ramdisk..."
cp -a $dir_needwrite/* $dir_ramdisk > /dev/null 2>&1
evaluate_retval
sleep 1

# CREATE SECOND RAMDISK

echo "Creating second ramdisk"
/sbin/mke2fs -m 0 -i 1024 -q $dev_ram2 > /dev/null 2>&1
evaluate_retval
sleep 1

# MOUNT SECOND RAMDISK

echo "Mounting second ram disk"
mount -n $dev_ram2 $dir_needwrite -t ext2
evaluate_retval
sleep 1

# COPY FILES TO THE SECOND RAMDISK

echo "Copying files to the second ram disk"
cp -a $dir_ramdisk/* $dir_needwrite
evaluate_retval
sleep 1

# UNMOUNT THE FIRST RAMDISK

echo "Unmounting and clearing first ram disk"
umount -n $dir_ramdisk > /dev/null 2>&1
blockdev --flushbufs /dev/ram1
evaluate_retval
sleep 1
;;
*)
echo "Usage: $0 {start}"
exit 1
;;
esac

EOF

Make the script executable with the following command:

chmod 0755 $LIVECD/etc/rc.d/init.d/create_ramdisk

Gabe Munoz pointed out that this symlink can be S11, where it used to be at
S00. Of course feel free to number the symlink as you see fit. (This is LFS
after all!) Just make sure that you dont start any scripts that will try to
write to one of the directories that needs write permission before the
files are copied over.

cd $LIVECD/etc/rc.d/rcsysinit.d
ln -s ../init.d/create_ramdisk S00create_ramdisk

Next we can install the bootloader, isolinux. It is available with the
syslinux package. You can find syslinux on freshmeat:

http://freshmeat.net/projects/syslinux/

The directions below assume the tarball syslinux-2.11.tar.bz2 is already
placed in $LIVECD/usr/src. (use the current version, 2.11 might be old by
the time you read this)

cd $LIVECD/usr/src
tar xzf syslinux-2.11.tar.gz
mkdir $LIVECD/isolinux
cp syslinux-2.11/isolinux.bin $LIVECD/isolinux

mv $LIVECD/boot/* $LIVECD/isolinux
cd $LIVECD/
rmdir boot
ln -s isolinux boot

The bootloader needs a configuration file. The cat command below creates
this file.

* Note: Be careful with your kernel name!
* See http://syslinux.zytor.com/errors.php
* Keep the name short and sweet.

cat > $LIVECD/isolinux/isolinux.cfg << "EOF"
default livecd

label livecd
kernel lfskernel
append initrd=initrd.gz root=/dev/ram0 init=/linuxrc ramdisk_size=16384
EOF

At this point it's a good idea to change /etc/fstab of the live CD system.
Delete all of the entries that you don't need. (e.g. all /dev/hd* entries)
You only need proc and devpts.

vi $LIVECD/etc/fstab

Don't worry about mounting root filesystem "/".
This will be mounted by the linuxrc script from the initial ram disk.

You may find it helpful to remove the following links:

rm $LIVECD/etc/rc.d/rc3.d/S20network
rm $LIVECD/etc/rc.d/rc0.d/K80network
rm $LIVECD/etc/rc.d/rc6.d/K80network
rm $LIVECD/etc/rc.d/rcsysinit.d/S40mountfs
rm $LIVECD/etc/rc.d/rcsysinit.d/S30checkfs

Ok! So far so good right?! In order for the boot process to work the way
we want, we create an initial ramdisk. More information about initial
ram disks (initrd for short) can be found in your kernel documentation.

The directions below create the initial ram disk (initrd):

dd if=/dev/zero of=$LIVECD/boot/initrd bs=1024 count=6144
mke2fs -m 0 -i 1024 -F $LIVECD/boot/initrd

mount -o loop $LIVECD/boot/initrd $LIVECD/mnt
cd $LIVECD/mnt
mkdir bin sbin lib dev proc mnt sys etc

cp -a $LIVECD/bin/{bash,mount,grep,umount,echo,ln,mkdir} bin/
cp -a $LIVECD/sbin/udev* sbin/
cp -a $(find $LIVECD -name "test" -type f) bin/
cp -a $(find $LIVECD -name "chroot" -type f) bin/
cp -a $(find $LIVECD -name "pivot_root" -type f) bin/
cp -H $LIVECD/lib/{libncurses.so.5,libdl.so.2,libc.so.6,ld-linux.so.2} lib/
cp -H $LIVECD/lib/{libreadline.so.5.0,libhistory.so.5.0} lib/
cp -a $LIVECD/dev/{console,null,ram{0,1,2}} dev/
cp -a $LIVECD/etc/{udev,dev.d,hotplug.d} etc/

ln -s bash bin/sh
ln -s test bin/[

The first program executed by the kernel is /linuxrc. As it does not
exist we create it. Our script will find the CD in the correct CD-ROM drive
and then mount it as the root file system / and run /sbin/init 3.

Copy and paste the script and tailor it to your needs if necessary:

cat > $LIVECD/mnt/linuxrc << "EOF"
#!/bin/sh

# ID is a file in root of the LFS boot CD, used to identify the CD.

ID="livecd"

TMP_MOUNT="/mnt"

PATH="/bin:/sbin:/usr/bin:/usr/sbin"

CHECK_TYPE="try_mount"

# MOUNT KERNEL FILESYSTEMS

# Create the proc directory if it does not exist

if [ ! -d "/proc/" ]; then
mkdir /proc
fi

# Mount the proc filesystem

mount -n proc /proc -t proc

# If sysfs is listed as a valid filesystem type in /proc
# then mount it (if it doesnt then udev wont work
# and you wont have the devices you need)

if grep -q '[[:space:]]sysfs' /proc/filesystems; then
if [ ! -d /sys/block ]; then
mount -n sysfs /sys -t sysfs
fi
fi

# Create some things that sysfs does not, and should not export for us. Feel
# free to add devices to this list.

make_extra_nodes() {
ln -s /proc/self/fd /dev/fd
ln -s /proc/self/fd/0 /dev/stdin
ln -s /proc/self/fd/1 /dev/stdout
ln -s /proc/self/fd/2 /dev/stderr
ln -s /proc/kcore /dev/core
mkdir /dev/pts
mkdir /dev/shm
}

if [ ! -x /sbin/hotplug ]; then
echo /sbin/udev > /proc/sys/kernel/hotplug
fi

# Mount a temporary file system over /dev, so that any devices
# made or removed during this boot don't affect the next one.
# The reason we don't write to mtab is because we don't ever
# want /dev to be unavailable (such as by `umount -a').

mount -n ramfs /dev -t ramfs

/sbin/udevstart

make_extra_nodes

# Detecting the live CD is pretty complicated,
# but is a very logical process

# Search for cdrom devices and add them to CDROM_LIST

CDROM_LIST=""

# Search in proc tree for ide cdrom devices
# There used to be a section for devfs, but this was
# edited for udev. Actually we should probably not
# use /proc anymore, but use sysfs instead...
# Perhaps in the future;)

# Check for ide channels.

for ide_channel in /proc/ide/ide[0-9]
do

# If there are no ide channels found, then skip this

if [ ! -d "$ide_channel" ]; then
break
fi

# Try each ide device to see if we can find the cd-rom drive

for ide_device in hda hdb hdc hdd hde hdf hdg hdh hdi hdj hdk hdl hdm hdn
do
device_media_file="$ide_channel/$ide_device/media"
if [ -e "$device_media_file" ]; then
grep -i "cdrom" $device_media_file > /dev/null 2>&1
if [ $? -eq 0 ]; then
CDROM_LIST="$CDROM_LIST /dev/$ide_device"
fi
fi
done
done

# Check for scsi cds

for scsi_cdrom in /dev/scd[0-99]
do
if [ -e "$scsi_cdrom" ]; then
CDROM_LIST="$CDROM_LIST $scsi_cdrom"
fi
done

# Now we try to find the LFS boot CD (we use ID as identification)

LFS_CDROM_DEVICE=""

for cdrom_device in $CDROM_LIST
do
if [ "$CHECK_TYPE" = "try_mount" ]; then
mount -n -t iso9660 ${cdrom_device} $TMP_MOUNT
# > /dev/null 2>&1
media_found=$?
fi

if [ $media_found -eq 0 ]; then
echo -n "media found"
if [ "$CHECK_TYPE" = "try_mount" ]; then
[ -e "$TMP_MOUNT/$ID" ]
media_lfs=$?
fi

if [ "$CHECK_TYPE" = "try_mount" ]; then
umount -n $cdrom_device > /dev/null 2>&1
fi

if [ $media_lfs -eq 0 ]; then
echo ", LFS boot CD found. Ready!"
LFS_CDROM_DEVICE="$cdrom_device"
break;
else
echo ", not LFS boot CD."
fi

else
echo "no media "
fi
done

# Mount LFS CD as / (root fs)
if [ "$LFS_CDROM_DEVICE" = "" ]; then
echo "No LFS boot CD found!!!"
exit 1
else
echo "Booting from $LFS_CDROM_DEVICE..."

# This is the magical part that makes a live CD live!
# The cd is mounted and pivot_root+chroot commands
# are used to start the system.
# If you really want to know what is going on here,
# You should read the chroot and pivot_root man pages

mount -n -o ro -t iso9660 $LFS_CDROM_DEVICE $TMP_MOUNT
cd $TMP_MOUNT
pivot_root . mnt
umount -n /mnt/proc >/dev/null 2>&1
exec chroot . sh -c 'umount -n /mnt >/dev/null 2>&1;
exec -a init.new /sbin/init 3' dev/console 2>&1

fi

EOF

To make this script executable run:

chmod 0755 $LIVECD/mnt/linuxrc

Ok, that's it. Unmount the image and compress it.

cd $LIVECD/
umount $LIVECD/mnt
gzip $LIVECD/boot/initrd

---------------------
| Burning the live CD |
---------------------

If you have a CD-RW you should use it for testing. When you know for sure
that it works well from the CD-RW you can burn it on a CD-R.(I give you
this advice, because I got the clue after burning about 10 CD-Rs that
didn't work ;-) [that goes for myself, and the author of the "Easy" hint ;)]

Before you start burning, check the size of your LFS tree:

du -sh $LIVECD/

Delete all the stuff you don't need on a live CD. (e.g. /usr/src/*)

Because linuxrc must be able to identify the CD you have to create a file
called "livecd".

touch $LIVECD/livecd

Now burn the LFS system on CD

Note!!

* dev=/dev/hdc is the device number of your CD-Writer
* Check your devices with "cdrecord -scanbus"
* (as of this writing scsi-emulation is no longer required)
* speed=4 should be changed to (max) speed of your CD-Writer.
* If you are not using a CD-RW remove blank=fast from the cdrecord-command!

cd $LIVECD/
mkisofs -R -l -L -D -b isolinux/isolinux.bin -o $ISODIR/livecd_image.iso \
-c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -V \
"livecd" $LIVECD && cdrecord -v -eject dev=/dev/hdc blank=fast \
$ISODIR/livecd_image.iso

ACKNOWLEDGEMENTS:

Thanks to:

* Thomas Foecking and Christian Hesse
For writing the "Easy Boot CD of your LFS" hint which confused me so much
when I tried it with udev that I decided to write this one =o)

* Gabriel Aneceto Munoz
For bring syntax errors and other updates to my attention

* Bernard Robbins
For giving some good suggestions

Feel free to email me comments, point out typos, etc.

CHANGELOG:
[2004-05-17]
* Initial hint completed.
[2004-05-19]
* Added environment variables for more flexibility
[2004-07-24]
* Finally found the time to proofread and submit the hint;)
[2004-08-04]
* Fixed syntax errors and made other updates
[2004-09-30]
* Tons of text changes and typo fixes, and various other stuff
[2005-09-03]
* Edited to include Bernard's suggestions