Skip to content

bencord0/genboot

Repository files navigation

#!/bin/bash
###########
# Genboot #
###########

# A framework for building boot environments
############################################
#
# Example usage in a qemu/kvm environment
#
# $ qemu-system-x86_64 \
# $     -m 10G \
# $     -enable-kvm \
# $     -smp 6 \
# $     -kernel vmlinuz \
# $     -net nic,model=virtio \
# $     -net user \
# $     -nographic \
# $     -append console=ttyS0 \
# $     -fsdev local,id=portage,path=/usr/portage,security_model=none \
# $     -fsdev local,id=packages,path=/var/lib/portage/packages,security_model=none \
# $     -device virtio-9p-pci,fsdev=portage,mount_tag=portage \
# $     -device virtio-9p-pci,fsdev=packages,mount_tag=packages
#
# Mount the shared portage and package trees using the plan9 filesystem
# # mount -t 9p portage /usr/portage
# # mount -t 9p packages /var/lib/portage/packages
#
# Example usage in a Xen environment
#
# $ cat << EOF > genboot.cfg
# > kernel="/path/to/vmlinuz"
# > vcpus=4
# > memory=10240
# > name="genboot"
# > device_model_override="/usr/bin/qemu-system-x86_64"
# > vif=['script=/path/to/vif-br0']
# > EOF
#
# $ cat << EOF > vif-br0
# > #!/bin/bash
# > test "$1" = "offline" && exit
# > ip link set dev "$vif" master br0
# > ip link set dev "$vif" up
# > EOF
# $ chmod +x vif-br0
#
# This involves lots of RAM, and assumes that you already
# have a bridged network device, br0, configured on the host.
#

# When inside the VM, login as root and run this README file.

# You can use the supplied the kernel image available from
# the github releases page.

# In the meantime, any disposable Gentoo-like environment will do.
# But not the minimal install cd, since that doesn't have 'emerge'.

# If you do have a copy of the all-in-one kernel then you should be aware of
# the changes I have made.
# It does some things atypical to a standard distro initramfs.
#   - Only a kernel is supplied to qemu, there is no stateful disk needed.
#   - The root= kernel cmdline is set inside the initramfs and does not need
#     to be supplied to qemu's "-append".
#   - The VM uses a lot of RAM. All writes are on a RAM backed AUFS rootfs.
#   - QEMU User networking provides a crippled network environment,
#     enough for TCP to download the portage tree and distfiles.
#   - Alternatively use bridged networking, or Xen.
#   - Pointing to a local portage/distfiles mirror is recommended.
#     This involves setting SYNC, GENTOO_MIRRORS and optionally,
#     PORTAGE_BINHOST in /etc/portage/make.conf
#   - No other special networking needs to be made. Qemu can be run as a
#     non-privilaged user.
#   - However, bridged networking is more performant that user networking,
#     and may require administratice access on the host. Not covered here.
#   - While the kernel is fairly standard (sys-kernel/gentoo-sources), however
#     network drivers and other config is tailored for my environment,
#     i.e. qemu/kvm virtio.
#     PXE booting may work, but your hardware might be different.
#   - Kernel modules inside the initramfs are coupled to the kernel version.
#     In theory, the kernel could be compiled without CONFIG_MODULES.
#   - The single kernel image couples the version of kernel modules
#     in the initramfs to the kernel, so the above point is not an issue.
#   - The final image is at least as big as any generated stage tarball and
#     the initramfs will perform a stage3 install during the boot process.
#     This presents a chicken/egg problem to visitors of this git repo that
#     requires the stage3 to build the boot environment, and the boot
#     environment to (cleanly) build the stage tarball.
#   - My custom dracut module is not documented or described here.
#     See prepare_dracut.sh for details.
#   - Once booted, root login is permitted (no password) on the console.
#     This can have security consequences, but this scheme does not allow
#     remote logins, or any password based authentication (e.g. pam/sudo/su)
#     to gain root access.
#     See 'grep root /etc/shadow' for details.
#   - Set a password or download an ssh key on first login.
#     e.g. https://github.com/{username}.keys -> ~/.ssh/authorized_keys

# Set SYNC and GENTOO_MIRRORS variables in /etc/portage/make.conf to
# use a local (and preferably internal) mirror to reduce load on upstream
# Gentoo infrastructure.
set -xe

# If binutils is not installed in $ROOT/usr/portage/profiles
# programs like ar and ld can't be found.
# make the symlinks with binutils-config when a portage tree is available.
ar -V || {
    source /etc/env.d/binutils/$(gcc -dumpmachine)-*
    binutils-config "$TARGET-$VER" && env-update
    source /etc/profile
}

# We'll need git to download these scripts.
# To save on compilation time, skip some of the bigger dependencies.
git --version || {

    # Do we need automake?
    eix -I sys-devel/automake$ || \
    emerge --deep --newuse --verbose --update --jobs \
        --usepkg --buildpkg --getbinpkg \
        sys-devel/automake

    emerge --deep --newuse --verbose --update --jobs \
        --usepkg --buildpkg --getbinpkg \
        dev-vcs/git
}

# These are the steps to run, in order
STAGES=(
  stage_template
  build_stage3
  configure_stage3
  build_modules
  prepare_dracut
  build_initramfs
  build_vmlinuz
  build_fsimg
  build_iso
  build_qcow2
  pack_portdir
)

# Create chroot and .complete files here
cd /root/genboot

# Index the STAGES array, and track the current and next STAGE
for SEQ in $(seq 0 $((${#STAGES} - 1))); do
  STAGE="${STAGES[${SEQ}]}"
  NEXT_STAGE="${STAGES[$((${SEQ} + 1))]}"

  # If the current stage has already run successfully, skip it
  # If the current stage needs to be rebuilt, also rebuild the next stage
  if [[ ! -e ".${STAGE}.complete" ]]; then
    # It is okay if the last +1 stage never exists.
    rm -f ".${NEXT_STAGE}.complete"
    bash "${STAGE}.sh" && touch ".${STAGE}.complete"
  else
    echo "Skipping stage: ${STAGE}"
  fi
done

# Turn off tracing
set +x

# Build artifacts are stored in /root
cd /root

# These files can be used to install Gentoo from stage3
ls -l stage3-systemd.tar.xz # Stage 3 tarball of the rootfs
ls -l systemd.squashfs      # Stage 3 squashfs of the rootfs
ls -l portage.tar.xz        # portage snapshot, with distfiles and binpkgs

ls -l initramfs.cpio        # Uncompressed initramfs with embedded squashfs
                            # Useful for anyone repacking the kernel.

# These are the normal linux image archives, without an embedded squashfs
ls -l linux-image.tar.xz    # vmlinuz + modules tarball (no squash)
ls -l vmlinuz.nosquash      # Normal kernel image, no initramfs
ls -l initramfs.nosquash    # Normal initramfs (with modules), no rootfs

# This is the ultimate build artifact, a self contained kernel image
# with the bundled initramfs and squashfs/overlayfs live environment.
ls -l vmlinuz               # Single kernel image, with initramfs and rootfs
ls -l gentoo-systemd.qcow2  # Cloud-init compatible VM image
ls -l rootfs.img.xz         # Ext4 filesystem based rootfs, good for AMIs
ls -l gentoo-systemd.iso    # ISO-9660 bootable image

# To install a new system, PXE boot into the bundled kernel image, partition and
# create a filesystem and then extract the stage3 tarball, linux-image tarball
# and portage tree (to /usr).
# Grub2 is also included, so the new system can be self hosting.