BuildISO

From LFScript
Revision as of 13:19, 3 February 2012 by Marcel (talk | contribs) (Protected "BuildISO": Counter-productive edit warring: This is page represents a core feature of LFScript, and therefore I'd like to maintain it myself. ([edit=sysop] (indefinite) [move=sysop] (indefinite)))
mkdir -p live/boot/{isolinux,$(uname -m)}
cp -v /usr/share/syslinux/isolinux.bin live/boot/isolinux
cp -v /boot/vmlinuz-*                  live/boot/$(uname -m)/vmlinuz
cp -v /boot/config-*                   live/boot/$(uname -m)/config
mkdir mnt
mount -o loop,ro /sources/rootfs-$(uname -m).img mnt
FAIL="0"

if [ ! -r mnt/usr/bin/$(uname -m)-*linux-gnu-gcc ]; then
    echo -n "ERROR: Unable to verify image architecture; Your system image does"
    echo " not contain the file '/usr/bin/$(uname -m)-*linux-gnu-gcc'"
    FAIL="1"
fi

if [ ! -d mnt/etc ]; then
    echo "ERROR: Your system image does not contain the directory '/etc'"
    FAIL="1"
fi

if [ ! -x mnt/sbin/init ]; then
    echo "ERROR: Your system image does not contain the executable '/sbin/init'"
    FAIL="1"
fi

if [ ! -e mnt/dev/console ]; then
    echo "ERROR: Your system image does not contain the device '/dev/console'"
    FAIL="1"
fi

if [ "${FAIL}" == "1" ]; then
    return 1
fi
cat > isolinux.cfg << EOF
DEFAULT menu.c32
PROMPT 0
MENU TITLE Select an option...
TIMEOUT 300

LABEL live
    MENU LABEL ^Boot the live system ($(uname -m))
    MENU DEFAULT
    KERNEL /boot/$(uname -m)/vmlinuz
    APPEND initrd=/boot/$(uname -m)/initramfs.cpgz quiet

LABEL harddisk
    MENU LABEL Boot from first ^Hard disk
    LOCALBOOT 0x80

EOF
if [ -e "mnt/usr/share/live/medium" ]; then
    cp -vR mnt/usr/share/live/medium/* live
fi
if [ ! -e "live/boot/isolinux/isolinux.cfg" ]; then
    cp -v /usr/share/syslinux/menu.c32 live/boot/isolinux
    cp -v isolinux.cfg                 live/boot/isolinux
fi
dd if=/dev/random of=live/boot/$(uname -m)/id_label bs=1 count=64
cat > init.sh << "EndOfFile"
#!/bin/busybox sh

# Initramfs boot script 1.3 (2012-01-19)
# Copyright (c) 2010-2012   Marcel van den Boer
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

# FS layout at the start of this script:
# - /boot/id_label
# - /bin/busybox
# - /dev/console (created by kernel)
# - /init (this file)

set -e

ARCH="<ARCH>"

###########################################
copyBindMount() { # COPY/BIND LIVECD MODE #
###########################################

# This function bind-mounts directories which are designed to be capable of
# read-only access and copies the remaining directories to a tmpfs.
#
# The downside of this method is that the resulting root filesystem is not
# fully writable. So, for example, installation of new programs will not be
# possible.
#
# However, this function can be used without any modification to the kernel and
# is therefore perfect for use as a fallback if other options are not available.

# Mount a tmpfs where the new rootfs will be.
mount -t tmpfs tmpfs ${ROOT} # Allows remounting root in the bootscripts

# Bind mount read-only filesystems, copy the rest
cd /mnt/system
for dir in $(ls -1); do
    case ${dir} in
        lost+found)
            ;;
        bin | boot | lib | opt | sbin | usr)
            mkdir ${ROOT}/${dir}
            mount --bind ${dir} ${ROOT}/${dir}
            ;;
        *)
            cp -R ${dir} ${ROOT}
            ;;
    esac
done
cd /

#########################################
}; unionMount() { # UNIONFS LIVECD MODE #
#########################################

# A union mount takes one or more directories and combines them transparantly
# in a third. This function creates a writable directory in memory (tmpfs) and
# uses it to overlay the read-only system image, resulting in a fully writable
# root file system.
#
# The only downside to this method is that it requires a union type filesystem
# in the kernel, which can only be accomplished by patching the kernel as there
# is no such feature in a vanilla kernel.

mkdir -p /mnt/writable
mount -t tmpfs -o rw tmpfs /mnt/writable

UNIONFSOPT="/mnt/writable=rw:/mnt/system=ro"
mount -t unionfs -o dirs=${UNIONFSOPT} unionfs ${ROOT} 2> /dev/null || {

    # If UnionFS fails, fall back to copy/bind mounting
    copyBindMount
}

######################
} # END OF FUNCTIONS #
######################

# Make required applets easier to access
for applet in clear cat chmod cp ls mkdir mknod mount umount switch_root; do
  /bin/busybox ln /bin/busybox /bin/${applet}
done

# Clear the screen
#clear # Don't! This will clear the Linux boot logo when using a framebuffer.
       # If you want to clear the screen on boot add the "clear" command to
       # '/usr/share/live/sec_init.sh' in the system image.

# Create device nodes required to run this script
# Note: /dev/console will already be available in the ramfs
mknod /dev/null c  1  3
mknod /dev/scd0 b 11  0  # +----
mknod /dev/scd1 b 11  1  # |
mknod /dev/scd2 b 11  2  # | <----
mknod /dev/scd3 b 11  3  # |   Devices which could contain the
mknod /dev/hda  b  3  0  # |   boot medium...
mknod /dev/hdb  b  3 64  # |
mknod /dev/hdc  b 22  0  # |
mknod /dev/hdd  b 22 64  # +----

# Create mount points for filesystems
mkdir -p /mnt/medium
mkdir -p /mnt/system
mkdir -p /mnt/rootfs

# Search for, and mount the boot medium
LABEL="$(cat /boot/id_label)"
for device in scd0 scd1 scd2 scd3 hda hdb hdc hdd; do
    mount -t iso9660 -o ro /dev/${device} /mnt/medium 2> /dev/null &&
    if [ "$(cat /mnt/medium/boot/${ARCH}/id_label)" != "${LABEL}" ]; then
        umount /mnt/medium
    else
        DEVICE="${device}"
        break
    fi
done

if [ "${DEVICE}" == "" ]; then
    echo "FATAL: Boot medium not found."
    exit 1
fi

# Mount the system image
mount -t squashfs -o ro,loop /mnt/medium/boot/${ARCH}/root.sqfs /mnt/system || {
    echo "FATAL: Boot medium found, but system image is missing."
    exit 1
}

# Define where the new root filesystem will be
ROOT="/mnt/rootfs" # Also needed for /usr/share/live/sec_init.sh

# Select LiveCD mode
unionMount # Might fall back to copyBindMount

# Move current mounts to directories accessible in the new root
cd /mnt
for dir in $(ls -1); do
    if [ "${dir}" != "rootfs" ]; then
        mkdir -p ${ROOT}/mnt/.boot/${dir}
        mount --move /mnt/${dir} ${ROOT}/mnt/.boot/${dir}
    fi
done
cd /

# Eject the medium before a shutdown
cat > ${ROOT}/etc/rc.d/rc0.d/S98eject << EOF
#!/bin/sh

if [ -x /usr/bin/cdrecord ]; then
    /usr/bin/cdrecord -eject dev=/dev/${DEVICE} &> /dev/null

    echo -e "\033[31m"
    echo -en "Remove the boot medium, close the tray (if any), "
    echo -en "then press ENTER to power off."
    echo -e "\033[0m"

    read
fi
EOF
chmod +x ${ROOT}/etc/rc.d/rc0.d/S98eject

# Overwrite /etc/fstab
# FIXME: This file is specific to LFS-SVN-20120116+, could it be made portable?
cat > ${ROOT}/etc/fstab << "EOF"
# Begin /etc/fstab

# file system  mount-point  type     options             dump  fsck
#                                                              order

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

# End /etc/fstab
EOF

# Run secondary initialization (if the system provides it)
if [ -x ${ROOT}/usr/share/live/sec_init.sh ]; then
    . ${ROOT}/usr/share/live/sec_init.sh
fi

# Switch to the new root and launch INIT!
exec switch_root -c /dev/console ${ROOT} /sbin/init

EndOfFile
mkdir -pv mnt_init/{bin,boot}
cp -v live/boot/$(uname -m)/id_label mnt_init/boot
cp -v /bin/busybox mnt_init/bin
cat init.sh > mnt_init/init
sed -i "s/<ARCH>/$(uname -m)/g" mnt_init/init
chmod +x mnt_init/init
cd mnt_init
find . | /bin/busybox cpio -o -H newc -F ../initramfs.cpio
cd ../
gzip -9 initramfs.cpio
mv -v initramfs.cpio.gz live/boot/$(uname -m)/initramfs.cpgz
rm -rf mnt_init
mksquashfs mnt live/boot/$(uname -m)/root.sqfs -comp xz
umount ./mnt
rm -rf mnt
mkisofs -o /sources/buildmgr/packages/system-$(uname -m).iso \
        -b boot/isolinux/isolinux.bin \
        -c boot.cat                   \
        -no-emul-boot                 \
        -boot-load-size 4             \
        -boot-info-table              \
        -joliet -l -R                 \
        live
rm -rf live
rm -rf ${FAKEROOT}/*