[Fedora-livecd-list] Net Boot

Mohammed_Khan at Dell.com Mohammed_Khan at Dell.com
Thu Jun 7 21:52:43 UTC 2007


Ok, I am pasting them here...

These were hacked from the Fedora Release 7 Gold version of
livecd-tools, I would love to work off of the versions in git but I
can't get http:// to work to get to the git repo... Is http enabled for
the fedora git repos? (git:// will not work from my network b/c the port
is blocked going out). 

To build livecd iso w/ net capability:
--------------------------------------
1. Backup and replace livecd-creator and mayflower on Fedora 7 with
versions pasted below...
2. Run: livecd-creator --enable-netroot --config=somefile.ks ... 

The --enable-netroot option:
1. enables a netroot option for the kernel commandline that is consumed
by initramfs
2. adds some nic drivers and nfs modules to initramfs
2. adds busybox and some symlinks from it to initramfs (needed for net
operations)
4. adds a supporting file and some supporting dirs for busybox udhcp

NOTE: in your ks config file, you must specify following package, else
intramfs will not be able to perform network operations:
a. busybox

And the following packages are nice to have for use in real root: 
a. nfs-utils
b. dhclient
c. net-tools

To netboot:
-----------
1. add netroot on the kernel commandline
2. you must also set following kernel commandline options:
		   rootfstype=nfs
		   rootflags=nolock
		   root=mynfsserverip:/location/of/squashfs.img

NOTE: this will enable initramfs to mount squashfs over nfs, so an nfs
server must be exporting squashfs.img at root specified location.
NOTE: the squashfs.img file on the nfs server must be exported (and
chmodded) as rw unless you also use the live_ram option.

If you use pxelinux for your pxe needs, below is an exmaple of a
pxelinux config file assuming you placed livecd contents in
/tftpboot/livecd (and nfs exported /tftpboot/livecd): 
	label boot
	kernel livecd/isolinux/vmlinuz
	initrd livecd/isolinux/initrd.img
	append netroot rootfstype=nfs rootflags=nolock
root=192.168.0.1:/tftpboot/livecd

NOTE: You can also pass live_ram if you want to copy the squashfs.img
into ram so that you do not have to remain mounted over nfs. 

That's it...

Limitations:
------------
1. Only supports dhcp for getting an ip in initramfs, no code to handle
static ip allocation is present, so you must have a dhcp server on your
network (this is a requirement for pxe-booting anyways... So not sure if
static ip capability is needed?)

Questions/Thoughts:
----------
1. Is there any interest in actually patching this capability in? or is
livecd intended purely for cd /usb... 
2. I thought the kernel can be compiled with nfsroot capability? I tried
this w/ the stock initramfs and one hacked w/ network moduels but I
think standard kernels on fedora yum repos do no have this enabled b/c I
get a /dev/nfs is unknown error, using a kernel w/ nfsroot enabled may
be another avenue to explore for netbooting...

Thanks,

MFK 

-------------------------

livecd-creator:

===========================================

#!/usr/bin/python -tt
#
# livecd-creator : Creates Live CD based for Fedora.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.

import getopt
import os
import os.path
import sys
import errno
import string
import tempfile
import time
import traceback
import subprocess
import shutil
import yum
import pykickstart.parser
import pykickstart.version

class MountError(Exception):
    def __init__(self, msg):
        Exception.__init__(self, msg)

class InstallationError(Exception):
    def __init__(self, msg):
        Exception.__init__(self, msg)

class BindChrootMount:
    """Represents a bind mount of a directory into a chroot."""
    def __init__(self, src, chroot, dest = None):
        self.src = src
        self.root = chroot

        if not dest:
            dest = src
        self.dest = self.root + "/" + dest

        self.mounted = False

    def mount(self):
        if not self.mounted:
            if not os.path.exists(self.dest):
                os.makedirs(self.dest)
            rc = subprocess.call(["/bin/mount", "--bind", self.src,
self.dest])
            if rc != 0:
                raise MountError("Bind-mounting '%s' to '%s' failed" %
(self.src, self.dest))
            self.mounted = True

    def umount(self):
        if self.mounted:
            rc = subprocess.call(["/bin/umount", self.dest])
            self.mounted = False
        

class LoopbackMount:
    def __init__(self, lofile, mountdir, fstype = None):
        self.lofile = lofile
        self.mountdir = mountdir
        self.fstype = fstype

        self.mounted = False
        self.losetup = False
        self.rmdir   = False
        self.loopdev = None

    def cleanup(self):
        self.umount()
        self.lounsetup()

    def umount(self):
        if self.mounted:
            rc = subprocess.call(["/bin/umount", self.mountdir])
            self.mounted = False

        if self.rmdir:
            try:
                os.rmdir(self.mountdir)
            except OSError, e:
                pass
            self.rmdir = False

    def lounsetup(self):
        if self.losetup:
            rc = subprocess.call(["/sbin/losetup", "-d", self.loopdev])
            self.losetup = False
            self.loopdev = None

    def loopsetup(self):
        if self.losetup:
            return

        rc = subprocess.call(["/sbin/losetup", "-f", self.lofile])
        if rc != 0:
            raise MountError("Failed to allocate loop device for '%s'" %
self.lofile)

        # succeeded; figure out which loopdevice we're using
        buf = subprocess.Popen(["/sbin/losetup", "-a"],
                               stdout=subprocess.PIPE).communicate()[0]
        for line in buf.split("\n"):
            # loopdev: fdinfo (filename)
            fields = line.split()
            if len(fields) != 3:
                continue
            if fields[2] == "(%s)" %(self.lofile,):
                self.loopdev = fields[0][:-1]
                break

        if not self.loopdev:
            raise MountError("Failed to find loop device associated with
'%s' from '/sbin/losetup -a'" % self.lofile)

        self.losetup = True

    def mount(self):
        if self.mounted:
            return

        self.loopsetup()

        if not os.path.isdir(self.mountdir):
            os.makedirs(self.mountdir)
            self.rmdir = True

        args = [ "/bin/mount", self.loopdev, self.mountdir ]
        if self.fstype:
            args.extend(["-t", self.fstype])

        rc = subprocess.call(args)
        if rc != 0:
            raise MountError("Failed to mount '%s' to '%s'" %
(self.loopdev, self.mountdir))

        self.mounted = True

class SparseExt3LoopbackMount(LoopbackMount):
    def __init__(self, lofile, mountdir, size, fslabel):
        LoopbackMount.__init__(self, lofile, mountdir, fstype = "ext3")
        self.size = size
        self.fslabel = fslabel

    def _createSparseFile(self):
        dir = os.path.dirname(self.lofile)
        if not os.path.isdir(dir):
            os.makedirs(dir)

        # create the sparse file
        fd = os.open(self.lofile, os.O_WRONLY | os.O_CREAT)
        off = long(self.size * 1024L * 1024L)
        os.lseek(fd, off, 0)
        os.write(fd, '\x00')
        os.close(fd)

    def _formatFilesystem(self):
        rc = subprocess.call(["/sbin/mkfs.ext3", "-F", "-L",
self.fslabel,
                              "-m", "1", self.lofile])
        if rc != 0:
            raise MountError("Error creating ext3 filesystem")
        rc = subprocess.call(["/sbin/tune2fs", "-c0", "-i0",
"-Odir_index",
                              "-ouser_xattr,acl", self.lofile])

    def mount(self):
        self._createSparseFile()
        self._formatFilesystem()
        return LoopbackMount.mount(self)

class LiveCDYum(yum.YumBase):
    def __init__(self):
        yum.YumBase.__init__(self)

    def doFileLogSetup(self, uid, logfile):
        # don't do the file log for the livecd as it can lead to open
fds
        # being left and an inability to clean up after ourself
        pass

    def _writeConf(self, datadir, installroot):
        conf  = "[main]\n"
        conf += "installroot=%s\n" % installroot
        conf += "cachedir=/var/cache/yum\n"
        conf += "plugins=0\n"
        conf += "reposdir=\n"

        path = datadir + "/yum.conf"

        f = file(path, "w+")
        f.write(conf)
        f.close()

        os.chmod(path, 0644)

        return path

    def setup(self, datadir, installroot):
        self.doConfigSetup(fn = self._writeConf(datadir, installroot),
                           root = installroot)
        self.conf.cache = 0
        self.doTsSetup()
        self.doRpmDBSetup()
        self.doRepoSetup()
        self.doSackSetup()

    def selectPackage(self, pkg):
        """Select a given package.  Can be specified with name.arch or
name*"""
        try:
            self.install(pattern = pkg)
        except yum.Errors.InstallError, e:
            raise InstallationError("Failed to find package '%s' : %s" %
(pkg, e))
        
    def deselectPackage(self, pkg):
        """Deselect package.  Can be specified as name.arch or name*"""
        sp = pkg.rsplit(".", 2)
        txmbrs = []
        if len(sp) == 2:
            txmbrs = self.tsInfo.matchNaevr(name=sp[0], arch=sp[1])

        if len(txmbrs) == 0:
            exact, match, unmatch =
yum.packages.parsePackages(self.pkgSack.returnPackages(), [pkg],
casematch=1)
            for p in exact + match:
                txmbrs.append(p)

        if len(txmbrs) > 0:
            map(lambda x: self.tsInfo.remove(x.pkgtup), txmbrs)
        else:
            print >> sys.stderr, "No such package %s to remove" %(pkg,)

    def selectGroup(self, grp, include =
pykickstart.parser.GROUP_DEFAULT):
        try:
            yum.YumBase.selectGroup(self, grp)
        except (yum.Errors.InstallError, yum.Errors.GroupsError), e:
            raise InstallationError("Failed to find group '%s' : %s" %
(grp, e))
        if include == pykickstart.parser.GROUP_REQUIRED:
            map(lambda p: self.deselectPackage(p),
grp.default_packages.keys())
        elif include == pykickstart.parser.GROUP_ALL:
            map(lambda p: self.selectPackage(p),
grp.optional_packages.keys())
        
    def addRepository(self, name, url = None, mirrorlist = None):
        repo = yum.yumRepo.YumRepository(name)
        if url:
            repo.baseurl.append(url)
        if mirrorlist:
            repo.mirrorlist = mirrorlist
        conf = yum.config.RepoConf()
        for k, v in conf.iteritems():
            if v or not hasattr(repo, k):
                repo.setAttribute(k, v)
        repo.basecachedir = self.conf.cachedir
        repo.metadata_expire = 0
        # disable gpg check???
        repo.gpgcheck = 0
        repo.enable()
        repo.setup(0)
        self.repos.add(repo)
            
    def runInstall(self):
        (res, resmsg) = self.buildTransaction()
        if res != 2:
            raise InstallationError("Failed to build transaction : %s" %
str.join("\n", resmsg))
        
        dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state
in ("i", "u"), self.tsInfo.getMembers()))
        self.downloadPkgs(dlpkgs)
        # FIXME: sigcheck?
        
        self.initActionTs()
        self.populateTs(keepold=0)
        self.ts.check()
        self.ts.order()
        # FIXME: callback should be refactored a little in yum 
        sys.path.append('/usr/share/yum-cli')
        import callback
        cb = callback.RPMInstallCallback()
        cb.tsInfo = self.tsInfo
        cb.filelog = False
        return self.runTransaction(cb)

class InstallationTarget:
    def __init__(self, repos, packages, epackages, groups, fs_label,
skip_compression, skip_prelink):
        self.ayum = None
        self.repos = repos
        self.packages = packages
        self.epackages = epackages
        self.groups = groups
        self.fs_label = fs_label
        self.skip_compression = skip_compression
        self.skip_prelink = skip_prelink

        self.build_dir = None
        self.instloop = None
        self.bindmounts = []
        self.ksparser = None
        
    def parse(self, kscfg):
        ksversion = pykickstart.version.makeVersion()
        self.ksparser = pykickstart.parser.KickstartParser(ksversion)
        if kscfg:
            try:
                self.ksparser.readKickstart(kscfg)
            except IOError, (err, msg):
                raise InstallationError("Failed to read kickstart file
'%s' : %s" % (kscfg, msg))
            except pykickstart.errors.KickstartError, e:
                raise InstallationError("Failed to parse kickstart file
'%s' : %s" % (kscfg, e))

            for repo in self.ksparser.handler.repo.repoList:
                already_given = False
                for cmd_name, cmd_url in self.repos:
                    if cmd_name == repo.name:
                        already_given = True
                        break

                if not already_given:
                    self.repos.append( (repo.name, repo.baseurl) )

 
self.packages.extend(self.ksparser.handler.packages.packageList)
            self.groups.extend(map(lambda g: (g.name, g.include),
 
self.ksparser.handler.packages.groupList))
 
self.epackages.extend(self.ksparser.handler.packages.excludedList)

        if not self.packages and not self.groups:
            raise InstallationError("No packages or groups specified")

        if not self.repos:
            raise InstallationError("No repositories specified")

    def base_on_iso(self, base_on):
        """helper function to extract ext3 file system from a live CD
ISO"""

        isoloop = LoopbackMount(base_on, "%s/base_on_iso"
%(self.build_dir,))

        squashloop = LoopbackMount("%s/squashfs.img"
%(isoloop.mountdir,),
                                   "%s/base_on_squashfs"
%(self.build_dir,),
                                   "squashfs")

        try:
            try:
                isoloop.mount()
            except MountError, e:
                raise InstallationError("Failed to loopback mount '%s' :
%s" % (base_on, e))

            if not os.path.exists(squashloop.lofile):
                raise InstallationError("'%s' is not a valid live CD ISO
: squashfs.img doesn't exist" % base_on)

            try:
                squashloop.mount()
            except MountError, e:
                raise InstallationError("Failed to loopback mount
squashfs.img from '%s' : %s" % (base_on, e))

            os_image = self.build_dir + "/base_on_squashfs/os.img"

            if not os.path.exists(os_image):
                raise InstallationError("'%s' is not a valid live CD ISO
: os.img doesn't exist" % base_on)

            shutil.copyfile(os_image, self.build_dir + "/data/os.img")
        finally:
            # unmount and tear down the mount points and loop devices
used
            squashloop.cleanup()
            isoloop.cleanup()

    def write_fstab(self):
        fstab = open(self.build_dir + "/install_root/etc/fstab", "w")
        fstab.write("/dev/mapper/livecd-rw   /
ext3    defaults,noatime 0 0\n")
        fstab.write("devpts                  /dev/pts
devpts  gid=5,mode=620  0 0\n")
        fstab.write("tmpfs                   /dev/shm
tmpfs   defaults        0 0\n")
        fstab.write("proc                    /proc
proc    defaults        0 0\n")
        fstab.write("sysfs                   /sys
sysfs   defaults        0 0\n")
        fstab.close()

    def setup(self, image_size, base_on = None):
        """setup target ext3 file system in preparation for an
install"""

        # setup temporary build dirs
        try:
            self.build_dir = tempfile.mkdtemp(dir="/var/tmp",
prefix="livecd-creator-")
        except OSError, (err, msg):
            raise InstallationError("Failed create build directory in
/var/tmp: %s" % msg)

        os.makedirs(self.build_dir + "/out/isolinux")
        os.makedirs(self.build_dir + "/out/sysroot")
        os.makedirs(self.build_dir + "/data/sysroot")
        os.makedirs(self.build_dir + "/install_root")
        os.makedirs(self.build_dir + "/yum-cache")

        if base_on:
            # get backing ext3 image if we're based this build on an
existing live CD ISO
            self.base_on_iso(base_on)

            self.instloop = LoopbackMount("%s/data/os.img"
%(self.build_dir,),
                                          "%s/install_root"
%(self.build_dir,))
        else:
            self.instloop = SparseExt3LoopbackMount("%s/data/os.img"
                                                    %(self.build_dir,),
                                                    "%s/install_root"
                                                    %(self.build_dir,),
                                                    image_size,
                                                    self.fs_label)
            

        try:
            self.instloop.mount()
        except MountError, e:
            raise InstallationError("Failed to loopback mount '%s' : %s"
% (self.instloop.lofile, e))

        if not base_on:
            # create a few directories needed if it's a new image
            os.makedirs(self.build_dir + "/install_root/etc")
            os.makedirs(self.build_dir + "/install_root/boot")
            os.makedirs(self.build_dir + "/install_root/var/log")
            os.makedirs(self.build_dir + "/install_root/var/cache/yum")

        # bind mount system directories into install_root/
        for (f, dest) in [("/sys", None), ("/proc", None), ("/dev",
None),
                          ("/dev/pts", None), ("/selinux", None),
                          (self.build_dir + "/yum-cache",
"/var/cache/yum")]:
            self.bindmounts.append(BindChrootMount(f, self.build_dir +
"/install_root", dest))

        for b in self.bindmounts:
            b.mount()

        # make sure /etc/mtab is current inside install_root
        os.symlink("../proc/mounts", self.build_dir +
"/install_root/etc/mtab")

        self.write_fstab()

        self.ayum = LiveCDYum()
        self.ayum.setup(self.build_dir + "/data",
                        self.build_dir + "/install_root")

    def unmount(self):
        """detaches system bind mounts and install_root for the file
system and tears down loop devices used"""
        self.ayum = None

        # FIXME: Make one last ditch effort to close fds still open
        # in the install root; this is only needed because
        # there's no way to ask yum to close its sqlite dbs,
        # though. See https://bugzilla.redhat.com/236409
        for i in range(3, os.sysconf("SC_OPEN_MAX")):
            try:
                os.close(i)
            except:
                pass

        try:
            os.unlink(self.build_dir + "/install_root/etc/mtab")
        except OSError:
            pass

        self.bindmounts.reverse()
        for b in self.bindmounts:
            b.umount()

        if self.instloop:
            self.instloop.cleanup()
            self.instloop = None

    def teardown(self):
        if self.build_dir:
            self.unmount()
            shutil.rmtree(self.build_dir, ignore_errors = True)

    def addRepository(self, name, url):
        """adds a yum repository to temporary yum.conf file used"""
        self.ayum.addRepository(name, url)

    def run_in_root(self):
        os.chroot("%s/install_root" %(self.build_dir,))
        os.chdir("/")

    def installPackages(self, packageList, excludePackageList, groupList
= []):
        """install packages into target file system"""
        try:
            map(lambda pkg: self.ayum.selectPackage(pkg), packageList)
            map(lambda grp: self.ayum.selectGroup(grp[0], grp[1]),
groupList)
            map(lambda pkg: self.ayum.deselectPackage(pkg),
excludePackageList)

            self.ayum.runInstall()
        finally:
            self.ayum.closeRpmDB()

    def writeNetworkIfCfg(self, instroot, network):
        path = instroot + "/etc/sysconfig/network-scripts/ifcfg-" +
network.device

        f = file(path, "w+")
        os.chmod(path, 0644)

        f.write("DEVICE=%s\n" % network.device)
        f.write("BOOTPROTO=%s\n" % network.bootProto)

        if network.bootProto.lower() == "static":
            if network.ip:
                f.write("IPADDR=%s\n" % network.ip)
            if network.netmask:
                f.write("NETMASK=%s\n" % network.netmask)

        if network.onboot:
            f.write("ONBOOT=on\n")
        else:
            f.write("ONBOOT=off\n")

        if network.essid:
            f.write("ESSID=%s\n" % network.essid)

        if network.ethtool:
            if network.ethtool.find("autoneg") == -1:
                network.ethtool = "autoneg off " + network.ethtool
            f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)

        if network.bootProto.lower() == "dhcp":
            if network.hostname:
                f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
            if network.dhcpclass:
                f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)

        if network.mtu:
            f.write("MTU=%s\n" % network.mtu)

        f.close()

    def writeNetworkKey(self, instroot, network):
        if not network.wepkey:
            return

        path = instroot + "/etc/sysconfig/network-scripts/keys-" +
network.device
        f = file(path, "w+")
        os.chmod(path, 0600)
        f.write("KEY=%s\n" % network.wepkey)
        f.close()

    def writeNetworkConfig(self, instroot, useipv6, hostname, gateway):
        path = instroot + "/etc/sysconfig/network"
        f = file(path, "w+")
        os.chmod(path, 0644)

        f.write("NETWORKING=yes\n")

        if useipv6:
            f.write("NETWORKING_IPV6=yes\n")
        else:
            f.write("NETWORKING_IPV6=no\n")

        if hostname:
            f.write("HOSTNAME=%s\n" % hostname)
        else:
            f.write("HOSTNAME=localhost.localdomain\n")

        if gateway:
            f.write("GATEWAY=%s\n" % gateway)

        f.close()

    def writeNetworkHosts(self, instroot, hostname):
        localline = ""
        if hostname and hostname != "localhost.localdomain":
            localline += hostname + " "
            l = string.split(hostname, ".")
            if len(l) > 1:
                localline += l[0] + " "
        localline += "localhost.localdomain localhost"

        path = instroot + "/etc/hosts"
        f = file(path, "w+")
        os.chmod(path, 0644)
        f.write("127.0.0.1\t\t%s\n" % localline)
        f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
        f.close()

    def writeNetworkResolv(self, instroot, nodns, primaryns,
secondaryns):
        if nodns or not primaryns:
            return

        path = instroot + "/etc/resolv.conf"
        f = file(path, "w+")
        os.chmod(path, 0644)

        for ns in (primaryns, secondaryns):
            if ns:
                f.write("nameserver %s\n" % ns)

        f.close()

    def configureNetwork(self):
        instroot = self.build_dir + "/install_root"

        try:
            os.makedirs(instroot + "/etc/sysconfig/network-scripts")
        except OSError, (err, msg):
            if err != errno.EEXIST:
                raise

        useipv6 = False
        nodns = False
        hostname = None
        gateway = None
        primaryns = None
        secondaryns = None

        for network in self.ksparser.handler.network.network:
            if not network.device:
                raise InstallationError("No --device specified with
network kickstart command")

            if network.onboot and network.bootProto.lower() != "dhcp"
and \
               not (network.ip and network.netmask):
                raise InstallationError("No IP address and/or netmask
specified with static " +
                                        "configuration for '%s'" %
network.device)

            self.writeNetworkIfCfg(instroot, network)
            self.writeNetworkKey(instroot, network)

            if network.ipv6:
                useipv6 = True
            if network.nodns:
                nodns = True

            if network.hostname:
                hostname = network.hostname
            if network.gateway:
                gateway = network.gateway

            if network.nameserver:
                nameservers = string.split(network.nameserver, ",")
                if len(nameservers) >= 1:
                    primaryns = nameservers[0]
                if len(nameservers) >= 2:
                    secondayns = nameservers[0]

        self.writeNetworkConfig(instroot, useipv6, hostname, gateway)
        self.writeNetworkHosts(instroot, hostname)
        self.writeNetworkResolv(instroot, nodns, primaryns, secondaryns)

    def configureSystem(self):
        instroot = "%s/install_root" %(self.build_dir,)
        
        # FIXME: this is a bit ugly, but with the current pykickstart
        # API, we don't really have a lot of choice.  it'd be nice to
        # be able to do something different, but so it goes

        # set up the language
        lang = self.ksparser.handler.lang.lang or "en_US.UTF-8"
        f = open("%s/etc/sysconfig/i18n" %(instroot,), "w+")
        f.write("LANG=\"%s\"\n" %(lang,))
        f.close()

        # next, the keyboard
        # FIXME: should this impact the X keyboard config too???
        # or do we want to make X be able to do this mapping
        import rhpl.keyboard
        k = rhpl.keyboard.Keyboard()
        if self.ksparser.handler.keyboard.keyboard:
            k.set(self.ksparser.handler.keyboard.keyboard)
        k.write(instroot)

        # next up is timezone
        tz = self.ksparser.handler.timezone.timezone or
"America/New_York"
        utc = self.ksparser.handler.timezone.isUtc
        f = open("%s/etc/sysconfig/clock" %(instroot,), "w+")
        f.write("ZONE=\"%s\"\n" %(tz,))
        f.write("UTC=%s\n" %(utc,))
        f.close()

        # do any authconfig bits
        auth = self.ksparser.handler.authconfig.authconfig or
"--useshadow --enablemd5"
        if os.path.exists("%s/usr/sbin/authconfig" %(instroot,)):
            args = ["/usr/sbin/authconfig", "--update", "--nostart"]
            args.extend(auth.split())
            subprocess.call(args, preexec_fn=self.run_in_root)

        # firewall.  FIXME: should handle the rest of the options
        if self.ksparser.handler.firewall.enabled and
os.path.exists("%s/usr/sbin/lokkit" %(instroot,)):
            subprocess.call(["/usr/sbin/lokkit", "-f", "--quiet",
                             "--nostart", "--enabled"],
                            preexec_fn=self.run_in_root)

        # selinux
        if os.path.exists("%s/usr/sbin/lokkit" %(instroot,)):
            args = ["/usr/sbin/lokkit", "-f", "--quiet", "--nostart"]
            if self.ksparser.handler.selinux.selinux:
                args.append("--selinux=enforcing")
            else:
                args.append("--selinux=disabled")
            subprocess.call(args, preexec_fn=self.run_in_root)

        # Set the root password
        if self.ksparser.handler.rootpw.isCrypted:
            subprocess.call(["/usr/sbin/usermod", "-p",
self.ksparser.handler.rootpw.password, "root"],
preexec_fn=self.run_in_root)
        elif self.ksparser.handler.rootpw.password == "":
            # Root password is not set and not crypted, empty it
            subprocess.call(["/usr/bin/passwd", "-d", "root"],
preexec_fn=self.run_in_root)
        else:
            # Root password is set and not crypted
            p1 = subprocess.Popen(["/bin/echo",
self.ksparser.handler.rootpw.password], stdout=subprocess.PIPE,
preexec_fn=self.run_in_root)
            p2 = subprocess.Popen(["/usr/bin/passwd", "--stdin",
"root"], stdin=p1.stdout, stdout=subprocess.PIPE,
preexec_fn=self.run_in_root)
            output = p2.communicate()[0]

        # enable/disable services appropriately
        if os.path.exists("%s/sbin/chkconfig" %(instroot,)):
            for s in self.ksparser.handler.services.enabled:
                subprocess.call(["/sbin/chkconfig", s, "--level", "345",
"on"],
                                preexec_fn=self.run_in_root)
            for s in self.ksparser.handler.services.disabled:
                subprocess.call(["/sbin/chkconfig", s, "--level", "345",
"off"],
                                preexec_fn=self.run_in_root)

        # x by default?
        if self.ksparser.handler.xconfig.startX:
            f = open("%s/etc/inittab" %(instroot,), "rw+")
            buf = f.read()
            buf = buf.replace("id:3:initdefault", "id:5:initdefault")
            f.seek(0)
            f.write(buf)
            f.close()

        # and now, for arbitrary %post scripts
        for s in filter(lambda s: s.type ==
pykickstart.parser.KS_SCRIPT_POST,
                        self.ksparser.handler.scripts):
            # we can only safely run scripts in the chroot
            if not s.inChroot:
                print >> sys.stderr, "Not running script outside of
chroot"
                continue

            (fd, path) = tempfile.mkstemp("", "ks-script-", "%s/tmp"
%(instroot,))
            os.write(fd, s.script)
            os.close(fd)
            os.chmod(path, 0700)

            try:
                subprocess.call([s.interp, "/tmp/%s"
%(os.path.basename(path),)],
                                preexec_fn = self.run_in_root)
            except OSError, (err, msg):
                os.unlink(path)
                raise InstallationError("Failed to execute %%post script
with '%s' : %s" % (s.interp, msg))
            os.unlink(path)

    def get_kernel_version(self):
        #
        # FIXME: this doesn't handle multiple kernels - we should list
        #        them all in the isolinux menu
        #
        kernels = []
        modules_dir = "%s/install_root/lib/modules" % self.build_dir

        if os.path.isdir(modules_dir):
            kernels = os.listdir(modules_dir)

        if not kernels:
            raise InstallationError("No kernels installed: /lib/modules
is empty")

        return kernels[0]

    def createInitramfs(self, enable_netroot):
        # Create initramfs
        if not os.path.isfile("/usr/lib/livecd-creator/mayflower"):
            raise InstallationError("livecd-creator not correctly
installed : "+
                                    "/usr/lib/livecd-creator/mayflower
not found")
        shutil.copy("/usr/lib/livecd-creator/mayflower",
                        "%s/install_root/sbin/mayflower"
%(self.build_dir,))
        # modules needed for booting (this is butt ugly and we need to
retrieve this from elsewhere, e.g. the kernel)
        mayflowerconf = open(self.build_dir +
"/install_root/etc/mayflower.conf", "w")
        mayflowerconf.write('MODULES+="cdrom ide-cd ahci loop
dm_snapshot squashfs ext3 ext2 ehci_hcd uhci_hcd ohci_hcd usb_storage
sd_mod sr_mod usbhid ata_piix vfat msdos "\n')
        if enable_netroot:
                mayflowerconf.write('MODULES+="3c59x 8139cp 8139too 8390
acenic amd8111e b44 de600 de620 dl2k e100 e1000 forcedeth ixgb ne2k-pci
pcnet32 r8169 tg3 sunrpc nfs nfs_acl lockd "\n')
        mayflowerconf.write('MODULES+="sata_mv sata_qstor sata_sis
sata_uli "\n')
        mayflowerconf.write('MODULES+="sata_nv sata_sil24 sata_svw
sata_via "\n')
        mayflowerconf.write('MODULES+="sata_promise sata_sil sata_sx4
sata_vsc "\n')
        mayflowerconf.write('MODULES+="ata_generic pata_ali pata_amd
pata_artop pata_atiixp pata_cmd64x pata_cs5520 pata_cs5530 pata_cs5535
pata_cypress pata_efar pata_hpt366 pata_hpt37x pata_hpt3x2n pata_hpt3x3
pata_isapnp pata_it821x pata_jmicron pata_marvell pata_mpiix
pata_netcell pata_ns87410 pata_oldpiix pata_optidma pata_opti
pata_pcmcia pata_pdc2027x pata_pdc202xx_old pata_qdi pata_serverworks
pata_sil680 pata_sis pata_sl82c105 pata_triflex pata_via pdc_adma "\n')
        mayflowerconf.write('MODULES+="sym53c8xx aic7xxx "\n')        
        mayflowerconf.close()

        if enable_netroot:
                subprocess.call(["/sbin/mayflower", "--enable-netroot",
"-f", 
                            "/boot/livecd-initramfs.img", 
                            self.get_kernel_version()], 
                            preexec_fn=self.run_in_root)
        else:
                subprocess.call(["/sbin/mayflower", "-f", 
                            "/boot/livecd-initramfs.img", 
                            self.get_kernel_version()], 
                            preexec_fn=self.run_in_root)
        for f in ("/sbin/mayflower", "/etc/mayflower.conf"):
            os.unlink("%s/install_root/%s" %(self.build_dir, f))

    def relabelSystem(self):
        # finally relabel all files
        if self.ksparser.handler.selinux.selinux:
            instroot = "%s/install_root" %(self.build_dir,)
            if os.path.exists("%s/sbin/restorecon" %(instroot,)):
                subprocess.call(["/sbin/restorecon", "-v", "-r", "/"],
                                preexec_fn=self.run_in_root)

    def prelinkSystem(self):
        # prelink the system
        instroot = "%s/install_root" %(self.build_dir,)
        if os.path.exists("%s/usr/sbin/prelink" %(instroot,)):
            subprocess.call(["/usr/sbin/prelink", "-mRaN"],
                            preexec_fn=self.run_in_root)
        return True

    def launchShell(self):
        subprocess.call(["/bin/bash"], preexec_fn=self.run_in_root)

    def configureBootloader(self):
        """configure the boot loader"""
        
        # set up boot loader
        #
        # TODO:
        #  - fix for archs not using grub
        #  - fix for non-i386
        #  - error handling
        #
        shutil.copyfile("%s/install_root/boot/vmlinuz-%s"
                        %(self.build_dir, self.get_kernel_version()),
                        "%s/out/isolinux/vmlinuz" %(self.build_dir,))

        shutil.copyfile("%s/install_root/boot/livecd-initramfs.img"
                        %(self.build_dir,),
                        "%s/out/isolinux/initrd.img" %(self.build_dir,))
        os.unlink("%s/install_root/boot/livecd-initramfs.img"
                  %(self.build_dir,))

        for p in ["isolinux.bin", "vesamenu.c32"]:
            path = "%s/install_root/usr/lib/syslinux/%s" %
(self.build_dir, p)

            if not os.path.isfile(path):
                raise InstallationError("syslinux not installed : %s not
found" % path)

            shutil.copy(path, "%s/out/isolinux/%s" % (self.build_dir,
p))

        if
os.path.exists("%s/install_root/usr/lib/anaconda-runtime/syslinux-vesa-s
plash.jpg" %(self.build_dir,)):
 
shutil.copy("%s/install_root/usr/lib/anaconda-runtime/syslinux-vesa-spla
sh.jpg" %(self.build_dir,),
                        "%s/out/isolinux/splash.jpg" %(self.build_dir,))
            have_background = "menu background splash.jpg"
        else:
            have_background = ""

        cfg = """
default vesamenu.c32
timeout 600

%(background)s
menu title Welcome to %(label)s!
menu color border 0 #ffffffff #00000000
menu color sel 7 #ffffffff #ff000000
menu color title 0 #ffffffff #00000000
menu color tabmsg 0 #ffffffff #00000000
menu color unsel 0 #ffffffff #00000000
menu color hotsel 0 #ff000000 #ffffffff
menu color hotkey 7 #ffffffff #ff000000
""" %{"label": self.fs_label, "background" : have_background}

        stanzas = [("linux", "Run from image", ""),
                   ("runfromram", "Run from RAM - requires 1 GB+",
"live_ram")]
        if
os.path.exists("%s/install_root/usr/lib/anaconda-runtime/checkisomd5"
%(self.build_dir,)):
            stanzas.append( ("check", "Verify and run from image",
"check") )

        for (short, long, extra) in stanzas:
            cfg += """label %(short)s
  menu label %(long)s
  kernel vmlinuz
  append initrd=initrd.img  ro quiet root=CDLABEL=%(label)s
rootfstype=iso9660 liveimg %(extra)s
""" %{"label": self.fs_label, "background" : have_background,
      "short": short, "long": long, "extra": extra}

        cfgf = open("%s/out/isolinux/isolinux.cfg" %(self.build_dir,),
"w")
        cfgf.write(cfg)
        cfgf.close()
        
        # TODO: enable external entitity to partipate in adding boot
entries

    def install(self, enable_netroot):
        for (name, url) in self.repos:
            self.ayum.addRepository(name, url)

        self.installPackages(self.packages, self.epackages, self.groups)
        self.configureSystem()
        self.configureNetwork()
        self.relabelSystem()
        if not self.skip_prelink:
            self.prelinkSystem()
        self.createInitramfs(enable_netroot)
        self.configureBootloader()

    def createIso(self):
        """write out the live CD ISO"""
        subprocess.call(["/usr/bin/mkisofs", "-o", "%s.iso"
%(self.fs_label,),
                         "-b", "isolinux/isolinux.bin",
                         "-c", "isolinux/boot.cat",
                         "-no-emul-boot", "-boot-load-size", "4",
                         "-boot-info-table", "-J", "-r",
"-hide-rr-moved",
                         "-V", "%s" %(self.fs_label,), "%s/out"
%(self.build_dir)])

        # implant an isomd5sum
        if os.path.exists("/usr/lib/anaconda-runtime/implantisomd5"):
            subprocess.call(["/usr/lib/anaconda-runtime/implantisomd5",
                             "%s.iso" %(self.fs_label,)])
        else:
            print >> sys.stderr, "anaconda-runtime not installed; not
setting up mediacheck"

    def createSquashFS(self):
        """create compressed squashfs file system"""
        if not self.skip_compression:
            # FIXME: mksquashfs segfaults if PWD isn't set in the
environment
            subprocess.call(["/sbin/mksquashfs", "os.img", "sysroot",
                             "../out/squashfs.img"],
                            cwd="%s/data" %(self.build_dir,),
                            env={"PWD": "%s/data" %(self.build_dir,)})
        else:
            shutil.move("%s/data/os.img" %(self.build_dir,),
                        "%s/out/ext3fs.img" %(self.build_dir,))

    def package(self):
        self.createSquashFS()
        self.createIso()

def usage(out):
    print >> out, """
usage: livecd-creator [--help] 
                      [--config=<path-to-kickstart-file> |
--repo=<name>,<url> --package=<p>]
                      [--repo=<name1>,<url1>] [--repo=<name2>,<url2>
...]
                      [--package=<p1>] [--package=<p2> ...]
                      [--exclude-package=<e1>] [--exclude-package=<e2>
...]
                      [--base-on=<path-to-iso-file>]
                      [--fslabel=<label>]
                      [--skip-compression]
                      [--uncompressed-size=<size-in-MB>]
                      [--shell]
                      [--enable-netroot]

 --help              : Print usage and exit
 --config            : Path to kickstart config file
 --repo              : Add / override yum repository
 --package           : Include this package
 --exclude-package   : Exclude this package
 --base-on           : Add packages to an existing live CD iso9660 image
 --fslabel           : File system label (default: livecd-YYYYMMDD-HHMI)
 --skip-compression  : Don't compress the image
 --prelink           : Prelink the image
 --uncompressed-size : Size of uncompressed fs in MB (default: 4096)
 --shell             : Start a shell in the chroot for
post-configuration
 --enable-netroot    : Enable net root (root can be mounted over net for
eg over nfs)

 Examples:

  Create minimal live cd:
  # livecd-creator
--config=/usr/share/livecd-tools/livecd-fedora-minimal.ks

  Create minimal live cd and use local package repositories:
  # livecd-creator
--config=/usr/share/livecd-tools/livecd-fedora-minimal.ks \\
                   --repo=a-dev,file:///home/user/core/RPMS
\\
                   --repo=a-extras-dev,file:///home/user/extras/RPMS
"""

class Usage(Exception):
    def __init__(self, msg = None, no_error = False):
        Exception.__init__(self, msg, no_error)

class Options:
    def __init__(self):
        self.repos = []
        self.packages = []
        self.groups = []
        self.epackages = []
        self.fs_label = "livecd-" + time.strftime("%Y%m%d-%H%M")
        self.base_on = None
        self.kscfg = None
        self.skip_compression = False
        self.skip_prelink = True
        self.uncompressed_size = 4096
        self.give_shell = False
        self.enable_netroot = False

def parse_options(args):
    try:
        opts, args = getopt.getopt(args, "hr:b:p:e:f:c:su:l",
                                   ["help", "repo=", "base-on=",
"package=",
                                    "exclude-package=", "fslabel=",
"config=",
                                    "skip-compression",
"uncompressed-size=",
                                    "shell", "enable-netroot",
"no-prelink", "prelink"])
    except getopt.GetoptError, msg:
        raise Usage(msg)

    options = Options()

    for o, a in opts:
        if o in ("-h", "--help"):
            raise Usage(no_error = True)
        if o in ("-l", "--shell"):
            options.give_shell = True
            continue
        if o in ("--enable-netroot"):
            options.enable_netroot = True
            continue
        if o in ("-s", "--skip-compression"):
            options.skip_compression = True
            continue
        if o in ("--no-prelink",):
            options.skip_prelink = True
            continue
        if o in ("--prelink",):
            options.skip_prelink = False
            continue
        if o in ("-u", "--uncompressed-size"):
            options.uncompressed_size = int(a)
            continue
        if o in ("-c", "--config"):
            options.kscfg = a
            if not os.path.isfile(options.kscfg):
                raise Usage("Kickstart config '%s' does not exist" %
options.kscfg)
            continue
        if o in ("-r", "--repo"):
            (name, url) = a.split(",")
            for (n, u) in options.repos:
                if n == name:
                    raise Usage("Repo name '%s' is already in use" % n)
            options.repos.append((name, url))
            continue
        if o in ("-p", "--package"):
            if a.startswith("@"):
                options.groups.append((a[1:],
pykickstart.parser.GROUP_DEFAULT))
            else:
                options.packages.append(a)
            continue
        if o in ("-e", "--exclude-package"):
            options.epackages.append(a)
            continue
        if o in ("-f", "--fslabel"):
            options.fs_label = a
            if len(options.fs_label) > 32:
                raise Usage("CD labels are limited to 32 characters")
            continue
        if o in ("-b", "--base-on"):
            options.base_on = a
            if not os.path.isfile(options.base_on):
                raise Usage("Live CD ISO '%s' does not exist" %
options.base_on)
            continue
        raise Usage("Unknown option %s" % o)

    if not options.kscfg and not (options.packages or options.groups):
        raise Usage("No packages or groups specified")

    if not options.kscfg and not options.repos:
        raise Usage("No repositories specified")

    return options

def main():
    try:
        options = parse_options(sys.argv[1:])
    except Usage, (msg, no_error):
        if no_error:
            out = sys.stdout
            ret = 0
        else:
            out = sys.stderr
            ret = 2
        if msg:
            print >> out, msg
        usage(out)
        return ret

    if os.geteuid () != 0:
        print >> sys.stderr, "You must run livecd-creator as root"
        return 1

    target = InstallationTarget(options.repos,
                                options.packages,
                                options.epackages,
                                options.groups,
                                options.fs_label,
                                options.skip_compression,
                                options.skip_prelink)

    try:
        target.parse(options.kscfg)

        target.setup(options.uncompressed_size, options.base_on)

        target.install(options.enable_netroot)

        if options.give_shell:
            print "Launching shell. Exit to continue."
            print "----------------------------------"
            target.launchShell()

        target.unmount()

        target.package()
    except InstallationError, e:
        print >> sys.stderr, "Error creating Live CD : %s" % e
        target.teardown()
        return 1
    target.teardown()

    return 0

if __name__ == "__main__":
    sys.exit(main())



=================================
Mayflower:

=================================

#!/bin/bash

# mayflower - flexible mkinitrd replacement
#
# Copyright 2006 David Zeuthen <davidz at redhat.com>
#
# Licensed under the GPLv2. See the file COPYING for details. 
# Inspired by similar programs from a bunch of other distributions.
#

usage() {
    echo "$0 [--help] [--enable-netroot] <out-initrd-image>
<kernel-version>"
    echo
    echo "example: $0 /boot/myinitramfs.img \`uname -r\`"
}

opt_allow_overwrite=0
opt_verbose=0
opt_enable_netroot=0
INITRAMFS_TARGET=""
KERNEL=""
while [ $# -gt 0 ] ; do
    case $1 in
        --help)
            usage
            exit 0
            ;;
        -f)
            opt_allow_overwrite=1
            ;;
        --allow-missing)
	    echo "Ignore option $1 for /sbin/mkinitrd compatibility"
	    ;;
        -v|--verbose)
            opt_verbose=1
            ;;
	--enable-netroot)
	    echo "Enabling netroot support"
	    opt_enable_netroot=1
	    ;;
        *)
            if [ -z "$INITRAMFS_TARGET" ] ; then
                INITRAMFS_TARGET=$1
            elif [ -z "$KERNEL" ] ; then
                KERNEL=$1
            else
                echo "Unknown option or parameter \"$1\""
                echo
                usage
                exit 1
            fi
            ;;
        *)
            ;;
    esac

    shift
done

if [ -z "$INITRAMFS_TARGET" -o -z "$KERNEL" ] ; then
    usage
    exit 1
fi

if [  "$opt_allow_overwrite" == "0" ] ; then
    if [ -e $INITRAMFS_TARGET ] ; then
	echo "Image $INITRAMFS_TARGET already exists. Use -f to
overwrite"
	exit 1
    fi
fi

echo "Building an initramfs at $INITRAMFS_TARGET for kernel $KERNEL"

TEMPDIR=`mktemp -d` || exit 1
pushd $TEMPDIR > /dev/null
mkdir initramfs_dir
cd initramfs_dir

# Make directory structure 
mkdir bin sbin dev sys proc lib lib/udev sysroot etc etc/udev
etc/udev/rules.d

cp /sbin/losetup sbin
cp /sbin/blockdev sbin
cp /sbin/dmsetup sbin
cp /bin/dd bin

MODULES=

if [ -e /etc/mayflower.conf ] ; then
    source /etc/mayflower.conf
fi

# TODO: right now we only recognize MODULES... add support for more
# options such as 'include all modules neccessary to mount the mount
# point /mnt/temp_os_install' etc.

MODULES+=" "

if [ "$opt_verbose" == "1" ] ; then
    echo "Kernel modules requested: $MODULES"
    echo
fi
rm -f modules

for m in $MODULES ; do
    /sbin/modprobe --set-version $KERNEL --show-depends $m >> modules
2>/dev/null
done

cat modules | awk '{if ($1=="install") print $5; else print $2; }' |
sort -u > modules2
rm -f modules
PRE_MODULES_FILES=`cat modules2`
rm -f modules2
for n in $PRE_MODULES_FILES ; do
    if [ `dirname $n` = "." ]; then 
        echo `find /lib/modules -name "${n}.ko" | grep $KERNEL` >>
modules3
    else 
	echo $n >> modules3
    fi
done
MODULES_FILES=`cat modules3`
rm -rf modules3

mkdir -p lib/modules/$KERNEL/

# Copy kernel modules over
for f in $MODULES_FILES ; do
    if [ "$opt_verbose" == "1" ] ; then
	echo "Copying kernel module $f"
    fi
    cp $f lib/modules/$KERNEL/
done

# Build module deps file so we can use modprobe
if [ "$opt_verbose" == "1" ] ; then
    /sbin/depmod -b `pwd` -v $KERNEL
else
    /sbin/depmod -b `pwd` -v $KERNEL > /dev/null
fi

# Copy /etc/fstab over
cp /etc/fstab etc

# Copy modprobe.conf and friends over
if [ -e /etc/modprobe.conf ] ; then
    cp /etc/modprobe.conf etc
fi
cp -R /etc/modprobe.d etc

# Copy binaries over
cp /bin/echo bin
cp /bin/sleep bin
cp /bin/bash bin
cp /bin/mount bin
cp /bin/umount bin
[ -x /usr/sbin/eject ] && cp /usr/sbin/eject sbin
cp /bin/ls bin
cp /bin/mknod bin
cp /bin/mkdir bin
cp /bin/chmod bin
cp /bin/ln bin
cp /bin/cat bin
cp /usr/bin/kill bin
cp /bin/rm bin

cp /sbin/udevsettle sbin
cp /sbin/udevtrigger sbin
cp /sbin/udevd sbin
cp /sbin/insmod sbin
cp /sbin/modprobe sbin
cp /sbin/pidof sbin
cp /sbin/killall5 sbin
cp /sbin/nash sbin
cp /lib/udev/vol_id lib/udev

# symlink niceties
ln -s bash bin/sh

# Not really required but nice
[ -x /usr/bin/tree ] && cp /usr/bin/tree bin
[ -x /usr/bin/less ] && cp /usr/bin/less bin
cp /bin/env bin
cp /bin/grep bin
cp /bin/dmesg bin
cp /sbin/lsmod sbin

# if we have the iso checker, we want it
[ -x /usr/lib/anaconda-runtime/checkisomd5 ] && cp
/usr/lib/anaconda-runtime/checkisomd5 bin

# Copy all required shared libs
for i in bin/* sbin/* lib/udev/*; do 
    ldd $i | sed 's|.*=>||g' | awk '/\// { print $1 }' | while read lib
; do
        if [ "$opt_verbose" == "1" ] ; then
	    echo "Copying DSO $l"
        fi
        cp --parents $lib .
    done
done

if [  "$opt_enable_netroot" == "1" ] ; then
	cp /sbin/busybox sbin
	ln -sf /sbin/busybox sbin/udhcpc
	ln -sf /sbin/busybox sbin/ifconfig # needed by default.script
	ln -sf /sbin/busybox sbin/route # needed by default.script
	mkdir -p usr/share/udhcpc
cat > usr/share/udhcpc/default.script <<EOF
#!/bin/sh

# udhcpc script edited by Tim Riker <Tim at Rikers.org>

[ -z "\$1" ] && echo "Error: default.script should be called from
udhcpc" && exit 1
RESOLV_CONF="/etc/resolv.conf"
[ -n "\$broadcast" ] && BROADCAST="broadcast \$broadcast"
[ -n "\$subnet" ] && NETMASK="netmask \$subnet"

case "\$1" in
	deconfig)
		/sbin/ifconfig \$interface 0.0.0.0
		;;
	renew|bound)
		/sbin/ifconfig \$interface \$ip \$BROADCAST \$NETMASK
		if [ -n "\$router" ]; then
			echo "deleting routers"
			while route del default gw 0.0.0.0 dev
\$interface; do
				:
			done
			for i in \$router; do
				route add default gw \$i dev \$interface
			done
		fi
	
		echo -n > \$RESOLV_CONF
		[ -n "\$domain" ] && echo search \$domain >>
\$RESOLV_CONF
		for i in \$dns; do
			echo adding dns \$i
			echo nameserver \$i >> \$RESOLV_CONF
		done
		;;
esac
exit 0

EOF
	chmod +x usr/share/udhcpc/default.script
fi

cat > sbin/run-init <<EOF
#!/sbin/nash
setuproot
switchroot
EOF
chmod 755 sbin/run-init

# Write out init
cat > init <<EOF
#!/bin/bash

emergency_shell()
{
    echo "Bug in initramfs /init detected. Dropping to a shell. Good
luck!"
    echo
    bash
}
trap "emergency_shell" 0 2

# exit immediately if a command fails
set -e

export PATH=/sbin:/bin

exec < /dev/console > /dev/console 2>&1

mount -n -t tmpfs -o mode=0755 udev /dev
mknod /dev/console c 5 1
mknod /dev/null c 1 3
mknod /dev/kmsg c 1 11
mkdir /dev/pts
mkdir -m 1777 /dev/shm
ln -s /proc/self/fd /dev/fd
ln -s fd/0 /dev/stdin
ln -s fd/1 /dev/stdout
ln -s fd/2 /dev/stderr

mount -n -t proc proc /proc
mount -n -t sysfs sysfs /sys

echo "" > /proc/sys/kernel/hotplug

# Declare all variables here.. mostly for housekeeping
#
init="/sbin/init"
root_ro=0
root_rw=0
root=""
rootflags=""
rootfstype=""
quiet=0
shell=0
eshell=0
live_ram=0
check_iso=0
live_locale=""
netroot=0


# Parse kernel commandline options
#
for o in \`cat /proc/cmdline\` ; do
    case \$o in 
    init=*)
        init=\${o#init=}
        ;;
    ro)
        root_ro=1
        ;;
    rw)
        root_rw=1
        ;;
    quiet)
        quiet=1
        ;;
    shell)
        shell=1
        ;;
    eshell)
        eshell=1
        ;;
    live_ram)
        live_ram=1
        ;;
    live_locale=*)
        live_locale=\${o#live_locale=}
        ;;
    check)
        check_iso=1
        ;;
    netroot)
        netroot=1
        ;;
    esac
done

if [ "\$quiet" != "1" ] ; then
    echo "kernel commandline: \`cat /proc/cmdline\`"
fi

# First, read rootfs target from embedded /etc/fstab file
#
if [ -f /etc/fstab ] ; then
    root=$(cat /etc/fstab | while read d m f o r; do if [ "$m" == "/" ]
; then echo $d; fi; done)
    rootflags=$(cat /etc/fstab | while read d m f o r; do if [ "$m" ==
"/" ] ; then echo $o; fi; done)
    rootfstype=$(cat /etc/fstab | while read d m f o r; do if [ "$m" ==
"/" ] ; then echo $f; fi; done)
    if [ "\$quiet" != "1" ] ; then
        echo "fstab suggests root=\$root"
        echo "fstab suggests rootflags=\$rootflags"
        echo "fstab suggests rootfstype=\$rootfstype"
        # Handle the case with bogus /etc/fstab pointing to /dev/root
        # which by definition does not exist...
        #
        if [ "\$root" == "/dev/root" ] ; then
            echo "WARNING: Bogus /etc/fstab file - cannot have /dev/root
as the device for /"
            root=""
            rootflags=""
            rootfstype=""
        fi
    fi
fi

# Users can override rootfs target on the kernel commandline
#
for o in \`cat /proc/cmdline\` ; do
    case \$o in 
    root=*)
        root=\${o#root=}
        ;;
    rootflags=*)
        rootflags=\${o#rootflags=}
        ;;
    rootfstype=*)
        rootfstype=\${o#rootfstype=}
        ;;
    esac
done

# Print out what we are going to do
#
if [ "\$quiet" != "1" ] ; then
    echo "init=\$init"
    echo "root=\$root"
    echo "rootflags=\$rootflags"
    echo "rootfstype=\$rootfstype"
    echo "root_ro=\$root_ro"
    echo "root_rw=\$root_rw"
    echo "netroot=\$netroot"
fi

waitforsymlink=0
# generate udev rules to generate /dev/root symlink
if [ -z \$root ] ; then
    root=/dev/something
else
    case \$root in
        /dev/disk/by-label/*)
            LABEL=\${root#/dev/disk/by-label/}
            echo "SUBSYSTEM==\"block\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$LABEL\", SYMLINK+=\"root\"" >
/etc/udev/rules.d/00-label.rules
            if [ "\$quiet" != "1" ] ; then
                echo "Added udev rule 00-label.rules:"
                cat /etc/udev/rules.d/00-label.rules
            fi
            waitforsymlink=1
            thingtomount=/dev/root
            ;;
        CDLABEL=*)
            CDLABEL=\${root#CDLABEL=}
            echo "KERNEL==\"hd[a-z]\", BUS==\"ide\",
SYSFS{removable}==\"1\", ATTRS{media}==\"cdrom\",
PROGRAM=\"/lib/udev/vol_id -l %N\", RESULT==\"\$CDLABEL\",
SYMLINK+=\"root\"" > /etc/udev/rules.d/00-cdlabel.rules
            echo "KERNEL==\"sr[0-9]\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$CDLABEL\", SYMLINK+=\"root\"" >>
/etc/udev/rules.d/00-cdlabel.rules
            echo "KERNEL==\"scd[0-9]\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$CDLABEL\", SYMLINK+=\"root\"" >>
/etc/udev/rules.d/00-cdlabel.rules
            echo "KERNEL==\"pcd[0-9]\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$CDLABEL\", SYMLINK+=\"root\"" >>
/etc/udev/rules.d/00-cdlabel.rules
            if [ "\$quiet" != "1" ] ; then
                echo "Added udev rule 00-cdlabel.rules:"
                cat /etc/udev/rules.d/00-cdlabel.rules
            fi
            waitforsymlink=1
            thingtomount=/dev/root
            ;;
        LABEL=*)
            LABEL=\${root#LABEL=}
            echo "SUBSYSTEM==\"block\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$LABEL\", SYMLINK+=\"root\"" >
/etc/udev/rules.d/00-label.rules
            if [ "\$quiet" != "1" ] ; then
                echo "Added udev rule 00-label.rules:"
                cat /etc/udev/rules.d/00-label.rules
            fi
            waitforsymlink=1
            thingtomount=/dev/root
            ;;
        /dev/disk/by-id/*)
            UUID=\${root#/dev/disk/by-id/}
            echo "SUBSYSTEM==\"block\", PROGRAM=\"/lib/udev/vol_id -u
%N\", RESULT==\"\$UUID\", SYMLINK+=\"root\"" >
/etc/udev/rules.d/01-uuid.rules
            if [ "\$quiet" != "1" ] ; then
                echo "Added udev rule 01-uuid.rules:"
                cat /etc/udev/rules.d/01-uuid.rules
            fi
            waitforsymlink=1
            thingtomount=/dev/root
            ;;
        UUID=*)
            UUID=\${root#UUID=}
            echo "SUBSYSTEM==\"block\", PROGRAM=\"/lib/udev/vol_id -u
%N\", RESULT==\"\$UUID\", SYMLINK+=\"root\"" >
/etc/udev/rules.d/01-uuid.rules
            if [ "\$quiet" != "1" ] ; then
                echo "Added udev rule 01-uuid.rules:"
                cat /etc/udev/rules.d/01-uuid.rules
            fi
            waitforsymlink=1
            thingtomount=/dev/root
            ;;
        /dev/*)
            ln -s \$root /dev/root
            thingtomount=\$root
            ;;
        *)
            thingtomount=\$root      
            ;;
    esac
fi

if [ "\$netroot" == "1" ] ; then
    waitforsymlink=1
fi

echo "udev_log=\"error\"" >> /etc/udev/udev.conf

# rules for loading modules
#
echo -n "ACTION==\"add\", SUBSYSTEM==\"?*\", ENV{MODALIAS}==\"?*\",
RUN+=\"/sbin/modprobe \$" >> /etc/udev/rules.d/10-modprobe.rules
echo "env{MODALIAS}\"" >> /etc/udev/rules.d/10-modprobe.rules
echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\" RUN+=\"/sbin/modprobe
sg\"" >> /etc/udev/rules.d/10-modprobe.rules
echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\",
SYSFS{type}==\"0|7|14\", RUN+=\"/sbin/modprobe sd_mod\"" >>
/etc/udev/rules.d/10-modprobe.rules
echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\",
SYSFS{type}==\"[45]\", RUN+=\"/sbin/modprobe sr_mod\"" >>
/etc/udev/rules.d/10-modprobe.rules

# OLPC specific: olpc_nand_enable, hardcodes this device file.. sigh..
#
echo "KERNEL==\"msr[0-9]*\", NAME=\"cpu/%n/msr\"" >
/etc/udev/rules.d/20-cpu.rules

# FIXME: hack since sr_mod seems to fail to get loaded sometimes
(#239657)
/sbin/modprobe sr_mod

if [ "\$quiet" != "1" ] ; then
    echo "starting udevd"
fi
/sbin/udevd --daemon

if [ "\$quiet" != "1" ] ; then
    echo "creating devices"
fi
/sbin/udevtrigger

if [ "\$quiet" != "1" ] ; then
    echo "waiting for system to settle"
fi
/sbin/udevsettle --timeout=30 || :


if [ "\$shell" == "1" ] ; then
    echo "Shell requested on kernel commandline. Exit to continue
booting."
    echo
    bash
fi

# don't wait for "mtd0" as no device file will appear
if [ "\$root" != "mtd0" ] && [ "\$netroot" == "0" ] ; then

    # If we don't have the /dev/root link.. ask the user to create..
    if [ "\$waitforsymlink" != "1" ] ; then
        if [ ! -L /dev/root ] ; then
            echo
            echo "--------------------------------------"
            echo "WARNING: Cannot find root file system!"
            echo "--------------------------------------"
            echo
            echo "Create symlink /dev/root and then exit this shell to
continue"
            echo "the boot sequence."
            echo
            bash
        fi
    fi

    # udevsettle might return before slow devices such as USB are in
shape
    # Wait up to 60 seconds for them to appear...
    #
    if [ ! -b /dev/root ] ; then
        if [ "\$quiet" != "1" ] ; then
            echo "no root yet, udev rule will write symlink..."
            echo
            echo "waiting up to 60 seconds before dropping to emergency
shell."
        fi
        COUNTDOWN=60
        while [ "x\$COUNTDOWN" != "x0" ] ; do
            if [ "\$quiet" != "1" ] ; then
                echo -n "."
            fi
            COUNTDOWN=\$((\$COUNTDOWN - 1))
            /bin/sleep 1
            if [ -e /dev/root ] ; then
	        COUNTDOWN=0
            fi
        done
    fi
    if [ ! -b /dev/root ] ; then
        echo
        echo "--------------------------------------"
        echo "WARNING: Cannot find root file system!"
        echo "--------------------------------------"
        echo
        echo "Create symlink /dev/root and then exit this shell to
continue"
        echo "the boot sequence."
        echo
        bash
    fi

    if [ "\$quiet" != "1" ] && [ "\$netroot" == "0" ] ; then
        echo "mounting /dev/root"
        ls -l /dev/root
    fi

    if [ -z \$rootfstype ] ; then
        rootfstype=auto
    fi

fi

if [ "x\$check_iso" == "x1" -a -x /bin/checkisomd5 -a "x\$rootfstype" ==
"xiso9660" ]; then
   echo "Verifying ISO image..."
   /bin/checkisomd5 --verbose /dev/root
   if [ \$? -ne 0 ]; then
       echo "Are you SURE you want to continue?"
       echo "Press Enter to continue or ctrl-alt-del to reboot."
       read
   fi
fi 

if [ "x\$root_ro" == "x1" ] ; then
   if [ -z \$rootflags ] ; then
       rootflags="ro"
   else
       rootflags="\$rootflags,ro"
   fi
fi

if [ "x\$root_rw" == "x1" ] ; then
   if [ -z \$rootflags ] ; then
       rootflags="rw"
   else
       rootflags="\$rootflags,rw"
   fi
fi

if [ -z \$rootflags ] ; then
    mountoptions=""
else
    mountoptions=" -o\$rootflags"
fi
if [ "\$netroot" != "1" ]; then
	mount -n -t \$rootfstype \$mountoptions \$thingtomount /sysroot
else
    	busybox udhcpc
	busybox mount -n -t \$rootfstype \$mountoptions \$thingtomount
/sysroot
fi

RES=\$?

if [ "\$RES" != "0" ] ; then
    echo "---------------------------------"
    echo "WARNING: Cannot mount rootfs!"
    echo "---------------------------------"
    echo
    echo "Dropping to a shell. "
    echo "Mount rootfs at /sysroot and exit shell to continue. Good
luck!"
    echo
    bash
fi

# Now get ready to leave the initramfs
#

# only pass kernel command line if we're launching /sbin/init
if [ "\$init" == "/sbin/init" ] ; then
    initargs=\$(cat /proc/cmdline)
else
    initargs=""
fi

# live cd helper function
do_live_from_loop121() {
    # create a sparse file for the overlay
    dd if=/dev/null of=/overlay bs=1024 count=1 seek=$((512*1024)) 2>
/dev/null
    losetup /dev/loop119 /overlay

    # set up the snapshot
    echo 0 \`blockdev --getsize /dev/loop121\` snapshot /dev/loop121
/dev/loop119 p 8 | dmsetup create live-rw

    # set up new /dev/root symlink
    rm -f /dev/root
    ln -s /dev/mapper/live-rw /dev/root

    mount -n -t ext3 /dev/mapper/live-rw /sysroot
    # here you can modify the rw ext3 fs for testing if you don't want
to
    # respin the entire rootfs (which takes ages). Example
    #
    #  echo foo > /sysroot/etc/bar.conf
    #
    # We also use it to dynamically set the system locale from the boot
    # menu on live cd's.
    #
    if [ "\$live_locale" != "" ] ; then
        echo "LANG=\$live_locale" > /sysroot/etc/sysconfig/i18n
    fi

    # create rule so udev creates /dev/live symlink on real rootfs
    if [ -n "\$CDLABEL" ]; then
       echo "KERNEL==\"hd[a-z]\", BUS==\"ide\", SYSFS{removable}==\"1\",
ATTRS{media}==\"cdrom\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$CDLABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules
       echo "KERNEL==\"sr[0-9]\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$CDLABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules
       echo "KERNEL==\"scd[0-9]\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$CDLABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules
       echo "KERNEL==\"pcd[0-9]\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$CDLABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules
    elif [ -n "\$LABEL" ]; then
       echo "KERNEL==\"hd[a-z]\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$LABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"hd[a-z][0-9]*\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$LABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"sd[a-z]\", PROGRAM=\"/lib/udev/vol_id -l %N\",
RESULT==\"\$LABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"sd[a-z][0-9]*\", PROGRAM=\"/lib/udev/vol_id -l
%N\", RESULT==\"\$LABEL\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
    elif [ -n "\$UUID" ]; then
       echo "KERNEL==\"hd[a-z]\", PROGRAM=\"/lib/udev/vol_id -u %N\",
RESULT==\"\$UUID\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"hd[a-z][0-9]*\", PROGRAM=\"/lib/udev/vol_id -u
%N\", RESULT==\"\$UUID\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"sd[a-z]\", PROGRAM=\"/lib/udev/vol_id -u %N\",
RESULT==\"\$UUID\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
       echo "KERNEL==\"sd[a-z][0-9]*\", PROGRAM=\"/lib/udev/vol_id -u
%N\", RESULT==\"\$UUID\", SYMLINK+=\"live\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules        
    fi

    # add rules for /dev/live-squashed and /dev/live-osimg
    echo "KERNEL==\"loop120\" SYMLINK+=\"live-squashed\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules
    echo "KERNEL==\"loop121\" SYMLINK+=\"live-osimg\"" >>
/sysroot/etc/udev/rules.d/50-udev.rules

    if [ "\$netroot" == "0" ] ; then
        mount -n -o ro,remount /sysroot
    fi
}

# we might have an uncompressed embedded ext3  to use as rootfs
(uncompressed live)
#
if [ -e /sysroot/LiveOS/ext3fs.img ]; then
  EXT3FS="/sysroot/LiveOS/ext3fs.img"
elif [ -e /sysroot/ext3fs.img ] ; then
  EXT3FS="/sysroot/ext3fs.img"
fi

if [ -n "\$EXT3FS" ] ; then
    if [ "\$quiet" != "1" ] ; then
        echo "setting up embedded ext3 fs "
    fi

    mknod /dev/loop118 b 7 118
    mknod /dev/loop119 b 7 119
    mknod /dev/loop120 b 7 120
    mknod /dev/loop121 b 7 121
    mkdir -p /dev/mapper
    mknod /dev/mapper/control c 10 63
    modprobe loop max_loop=128
    modprobe dm_snapshot

    losetup /dev/loop121 \$EXT3FS
    umount -l /sysroot

    do_live_from_loop121
fi

# we might have an embedded ext3 on squashfs to use as rootfs
(compressed live)
#
if [ -e /sysroot/LiveOS/squashfs.img ]; then
  SQUASHED="/sysroot/LiveOS/squashfs.img"
elif [ -e /sysroot/squashfs.img ]; then
  SQUASHED="/sysroot/squashfs.img"
fi

if [ -n "\$SQUASHED" ] ; then

    if [ "\$quiet" != "1" ] ; then
        echo "setting up embedded squash -> ext3 fs "
    fi

    mknod /dev/loop118 b 7 118
    mknod /dev/loop119 b 7 119
    mknod /dev/loop120 b 7 120
    mknod /dev/loop121 b 7 121
    mkdir -p /dev/mapper
    mknod /dev/mapper/control c 10 63
    modprobe loop max_loop=128
    modprobe dm_snapshot

    if [ "\$live_ram" == "1" ] ; then
        echo "Copying live image to RAM..."
        echo "(this may take a few minutes)"
        dd if=\$SQUASHED of=/squashed.img bs=512 2> /dev/null
        umount -n /sysroot
        echo "Done copying live image to RAM."
	if [ "\$netroot" == "0" ]; then
            eject -p /dev/root
        fi
        SQUASHED="/squashed.img"
    fi

    losetup /dev/loop120 \$SQUASHED
    mkdir -p /squashfs
    mount -n -t squashfs -o ro /dev/loop120 /squashfs

    losetup /dev/loop121 /squashfs/os.img
    
    umount -l /squashfs
    if [ "\$live_ram" == "0" ] ; then
        umount -l /sysroot
    fi

    do_live_from_loop121
fi

if [ "\$eshell" == "1" ] ; then
    echo "Shell requested on kernel commandline."
    echo "Rootfs is mounted ro on /sysroot. Exit to continue booting."
    echo
    bash
fi

if [ -x /sysroot\$init ] ; then

    # Leave initramfs and transition to rootfs
    kill \`pidof udevd\`
    if [ "\$quiet" != "1" ] ; then
        echo "transfering control to \$init"
    fi

    exec /sbin/run-init
    echo "---------------------------------"
    echo "WARNING: Error switching to real rootfs!"
    echo "---------------------------------"
    echo
    echo "Dropping to a shell. Good luck!"
    echo
    bash
else
    echo "---------------------------------------------------------"
    echo "WARNING: Requested \$init binary does not exist on rootfs."
    echo "---------------------------------------------------------"
    echo
    echo "Dropping to a shell. Good luck!"
    echo
    bash
fi

EOF

chmod a+x init

if [ "$opt_verbose" == "1" ] ; then
    tree -s .
    echo
    cat -n init
    echo
fi


find . | cpio --quiet -o -H newc | gzip -9 > ../initramfs
popd > /dev/null
rm -f $INITRAMFS_TARGET
cp $TEMPDIR/initramfs $INITRAMFS_TARGET
rm -rf $TEMPDIR

echo "Done; initramfs is $(du -h $INITRAMFS_TARGET | awk '{print $1}')."
echo
exit 0


-----Original Message-----
From: fedora-livecd-list-bounces at redhat.com
[mailto:fedora-livecd-list-bounces at redhat.com] On Behalf Of Jane Dogalt
Sent: Wednesday, June 06, 2007 6:29 PM
To: fedora-livecd-list at redhat.com
Subject: RE: [Fedora-livecd-list] Net Boot


--- Mohammed_Khan at Dell.com wrote:

> I hacked mayflower and livecd-creator to add busybox and some network 
> modules and their dependencies... I can now get the livecd to boot 
> kernel / initramfs over pxe and then louad the squashfs.img over nfs.
> If
> you guys are interested I can post the code here.

Yes please.  I suspect it may help out if I ever get around to trying to
scratch that fuse-http-iso-fs itch.  (i.e. mounting squashfs.img from
the web)

-dmc/jdog



       
________________________________________________________________________
____________
Choose the right car based on your needs.  Check out Yahoo! Autos new
Car Finder tool.
http://autos.yahoo.com/carfinder/

--
Fedora-livecd-list mailing list
Fedora-livecd-list at redhat.com
https://www.redhat.com/mailman/listinfo/fedora-livecd-list




More information about the Fedora-livecd-list mailing list