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