2.6-udev-nptl-bootcd corrections

Mike Hernandez Mike at Culmination.org
Wed Aug 4 06:52:18 PDT 2004


Thanks to Gabe for pointing out some errors and for making some other
great suggestions!

Mike
-------------- next part --------------
AUTHOR: Mike Hernandez <mike at culmination dot org>

DATE: 2004-07-24

LICENSE: GNU Free Documentation License Version 1.2

SYNOPSIS: How to create a live cd with udev, NPTL, and the 2.6 kernel
          

DESCRIPTION:
This hint describes, in detail, the process by which I created a live cd
from a system built with the BE-LFS book (As of 2004-04-27). The reader
should be able to follow the hint to create a live cd of their own.
It was adapted from the "Easy" hint to work with what is currently
the "unstable" book.

PREREQUISITES:
1. A working LFS System (and cdrtools)
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

HINT:

First of all 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 illustrates my first point:

**Remember that the system running your live cd may not be the same as your 
working system.**

It really all depends on what you want your live cd to do. You may want to
consider optimizing everything in your live cd system for size? 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 livecd system) is essential.

Ok with that out of the way, let's get to creating the cd!

If you want to copy and paste commands, you should set the LIVECD
variable set to point to the mount point of the system you are
building:

        export LIVECD=/mnt/livecd 

For the purpose of the next command you might want to set LIVECDDEV as well:

        export LIVECDDEV=/dev/your-drive+partition

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

        export ISODIR=/where/you/have/space

STEP ONE: chrooting into the livecd system 
1.  Mount your live cd system:

        mkdir -p $LIVECD
        mount $LIVECDDEV $LIVECD

2.  As per the directions of the BE-LFS book which is current at
	the time this is written, mount the virtual file systems prior 
	to entering the chroot environment:
		
        mount -t proc proc $LIVECD/proc
        mount -t sysfs sysfs $LIVECD/sys

    and perform the fake mounts:

        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

STEP TWO: Building the kernel for your live cd

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're using what is, at
the moment, either the testing or unstable branch of the book,
that you know how to build and configure the 2.6 kernel, just be careful! =) 
 
STEP THREE: Installing cdrtools (for using isoinfo)
  Note: The original "easy" hint allowed for the use of isoinfo.
        The options for isoinfo have changed, however.
        I do not use isoinfo but have left the section in tact
        so that the directions for using it could be added later.
        (point: you really dont need to install cdrtools)

(Follow blfs instructions)
If you are using cdrtools-2.00.3 then you may have to
insert:
 
        typedef unsigned char u8; 

"ifdef linux" section of scsihack.c in order for it to compile properly.
(see http://linuxfromscratch.org/pipermail/blfs-support/2003-July/043100.html)                                                                                
STEP FOUR: Moving /dev /etc /home /root /tmp /var  to /fake/needwrite

# What is /fake/needwrite?
# The /fake/needwrite directory is used to hold files that must be
# writable while the livecd is running.
# Obviously, these files can not remain on the cd-rom, and so are moved
# To a location from which they will be copied into a ramdisk

	First we have to create this directory and the mountpoint for the ramdisk:

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

	Then we can move it there:

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

 Create symlinks /... -> /fake/needwrite/...

	We have moved dev/ etc/ home/ root/ tmp/ and var/ to /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

    now "ls -l" says:
    dev  -> fake/needwrite/dev
    etc  -> fake/needwrite/etc
    home -> fake/needwrite/home
    root -> fake/needwrite/root
    tmp  -> fake/needwrite/tmp
    var  -> fake/needwrite/var


STEP FIVE: Create boot script which mounts the ramdisk
   --------------------------------------------

	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 on runlevel x
	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 ramdisk 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 it
  trying to mount /dev/ram0 somewhere else leads to "device
  already mounted" errors. Secondly, umounting 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 you do the
  same. 

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 ram disks"
          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 it executable:

        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!):
	/etc/rc.d/rcsysinit.d/S11create_ramdisk -> ../init.d/create_ramdisk

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

**Note: If you have another script set to run first (at S00) you should
  move that script to start after. (Maybe to S05?)



STEP SIX: Install the bootloader isolinux
   -------------------------------

	We also need a bootloader on the CD to boot the kernel and ramdisk.
	lilo and grub are all nice but isolinux is made to boot iso images!
	(it comes with syslinux). I assume the tarball syslinux-2.09.tar.bz2 is
	already placed in $LIVECD/usr/src.

cd $LIVECD/usr/src

tar xzf syslinux-2.09.tar.gz
mkdir $LIVECD/isolinux
cp syslinux-2.09/isolinux.bin $LIVECD/isolinux

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

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

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

STEP SEVEN: Create initial ramdisk
   ----------------------

	!!! But first we have to change /etc/fstab of the live cd system !!!
	Delete all entries you don't need. (e.g. all /dev/hd*)
	You only need proc (and maybe devfs, devpts)

vi $LIVECD/etc/fstab

	Don't worry about mounting root filesystem "/".
	This will be mounted by linuxrc from initrd fs.

	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

	Now we create the initrd image file and filesystem.

    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/

You need the console, null, ram0, ram1 and ram2 devices!
console and null should already be present
but we have to create /dev/ram0, /dev/ram1 and /dev/ram2

    cp -a $LIVECD/dev/{console,null} dev/

You need /etc/udev, /etc/hotplug and /etc/dev.d

    cp -a $LIVECD/etc/{udev,dev.d,hotplug.d} etc/

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

If you wish to use isoinfo instead of mount to detect the live cd you
must also copy isoinfo into the initial ramdisk.

    cp $(find $LIVECD -name "isoinfo" -type f) 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 rootfs / and run /sbin/init 3.


----------- copy & paste -------------

cat > $LIVECD/mnt/linuxrc << "EOF"
#!/bin/sh
                                                                                
#ID is the volume id / label of the LFS boot CD if you use /bin/isoinfo
#or ID is a file in root of the LFS boot CD
ID="livecd"
TMP_MOUNT="/mnt"
                                                                                
PATH="/bin:/sbin:/usr/bin:/usr/sbin"
                                                                                
#isoinfo currently does not work
#if [ -e "/bin/isoinfo" ]; then
#  CHECK_TYPE="isoinfo"
#else
  CHECK_TYPE="try_mount"
#fi
                                                                                
#***********************************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 livecd is pretty complicated, 
# but is a very logical process
                                                                                
#1. 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
                                                                                
#2. 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

	# Again, the isoinfo check here doesnt work
	# I plan on figuring this out when I'm not lazy
	# The livecd will work just fine without isoinfo
	# I'm leaving this here to create less work later =)

  if [ "$CHECK_TYPE" = "isoinfo" ]; then
    isoinfo -d -i $cdrom_device > /dev/null 2>&1
    media_found=$?
    if [ $media_found -ne 0 ]; then
      isoinfo -V $cdrom_device > /dev/null 2>&1
      media_found=$?
    fi
  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" = "isoinfo" ]; then
     isoinfo -d -i $cdrom_device | grep -i "Volume id:" | grep "$ID" \
      > /dev/null 2>&1
      media_lfs=$?
      if [ $media_lfs -ne 0 ]; then
        isoinfo -V $cdrom_device | grep "$ID" > /dev/null 2>&1
        media_lfs=$?
      fi
    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
                                                                                
                                                                                
#3. 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 livecd 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 >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


8. Burn the Boot CD
   ----------------

	If you have a CD-RW you should take this for testing. When
	your system boots quite good from 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 ;-)

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

du -ch $LIVECD/ | grep total

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

	Because linuxrc must be able to identify the CD you have to create a
	file called "livecd". (unless you use isoinfo)

touch $LIVECD/livecd

	Now burn the LFS system on CD

	Note!
	dev=/dev/hdc is the device number of your CD-Writer
	Check your SCSI 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 <thomas at foecking.de> and Christian Hesse <mail at earthworm.de>
   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

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

CHANGELOG:
[2004-08-04]
  * Fixed syntax errors and made other updates
[2004-07-24]
  * Finally found the time to proofread and submit the hint;)
[2004-05-19]
  * Added environment variables for more flexibility
[2004-05-17]
  * Initial hint completed.


More information about the hints mailing list