#!/bin/bash set -e -u # edition-specific strings iso_edition="SystemD/CLI" iso_title="Parabola GNU/Linux-libre Live - ${iso_edition} Edition" # $iso_version appended # CLI option defaults iso_version=$(date +%Y.%m.%d) iso_label="PARA_$(date +%Y%m)" iso_dirname='parabola' work_dir=./work out_dir=./out arch=$(uname -m) target='' verbose='' efi_img_kbytes=40000 pacman_conf=${work_dir}/pacman.conf chroot_customization_script=/root/customize_root_image.sh # environment data_dir=/usr/share/parabolaiso/data releng_dir=$(readlink -f ${0%/*}) initcpio_dir=${releng_dir}/../../parabolaiso/initcpio [ "`which mkparabolaiso 2> /dev/null`" ] || export PATH=$PATH:"${releng_dir}/../../parabolaiso" _usage () { echo "usage ${0} [options]" echo echo " General options:" echo " -V Set the iso version in the filename" echo " Default: ${iso_version}" echo " -L Set the iso volume label" echo " Default: ${iso_label}" echo " -D Set the name of the directory inside the ISO" echo " Default: ${iso_dirname}" echo " -w Set the working directory" echo " Default: ${work_dir}" echo " -o Set the output directory" echo " Default: ${out_dir}" echo " -v Enable verbose output" echo " -h This help message" exit ${1} } # Helper function to run make_*() only one time per architecture. run_once() { if [[ ! -e ${work_dir}/build.${1}_${arch} ]]; then $1 touch ${work_dir}/build.${1}_${arch} fi } # Setup custom pacman.conf with current cache directories. make_pacman_conf() { local _cache_dirs _cache_dirs=($(pacman -v 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g')) sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n ${_cache_dirs[@]})|g" ${releng_dir}/pacman.conf > ${pacman_conf} } # Base installation, plus needed packages (root-image) make_basefs() { setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir}/${arch} -C ${pacman_conf} -D ${iso_dirname} init setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir}/${arch} -C ${pacman_conf} -D ${iso_dirname} -p "memtest86+ mkinitcpio-nfs-utils nbd" install } # Additional packages (root-image) make_packages() { setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir}/${arch} -C ${pacman_conf} -D ${iso_dirname} -p "$(grep -h -v ^# ${releng_dir}/packages.{both,${arch}})" install } # Copy mkinitcpio parabolaiso hooks and build initramfs (root-image) make_setup_mkinitcpio() { local _hook for _hook in parabolaiso parabolaiso_shutdown parabolaiso_pxe_common parabolaiso_pxe_nbd parabolaiso_pxe_http parabolaiso_pxe_nfs parabolaiso_loop_mnt; do cp ${initcpio_dir}/hooks/${_hook} ${work_dir}/${arch}/root-image/usr/lib/initcpio/hooks cp ${initcpio_dir}/install/${_hook} ${work_dir}/${arch}/root-image/usr/lib/initcpio/install done cp ${initcpio_dir}/install/parabolaiso_kms ${work_dir}/${arch}/root-image/usr/lib/initcpio/install cp ${initcpio_dir}/hooks/parabolaiso_shutdown ${work_dir}/${arch}/root-image/usr/lib/initcpio cp ${releng_dir}/mkinitcpio.conf ${work_dir}/${arch}/root-image/etc/mkinitcpio-parabolaiso.conf setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir}/${arch} -C ${pacman_conf} -D ${iso_dirname} -r 'mkinitcpio -c /etc/mkinitcpio-parabolaiso.conf -k /boot/vmlinuz-linux-libre -g /boot/parabolaiso.img' run } # Customize installation (root-image) make_customize_root_image() { cp -af ${releng_dir}/root-image ${work_dir}/${arch} echo "Customizing root image" iso_title="${iso_title}" \ setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir}/${arch} \ -C ${pacman_conf} \ -D ${iso_dirname} \ -r ${chroot_customization_script} run rm ${work_dir}/${arch}/root-image${chroot_customization_script} } # Prepare kernel/initramfs ${iso_dirname}/boot/ make_boot() { mkdir -p ${work_dir}/iso/${iso_dirname}/boot/${arch} cp ${work_dir}/${arch}/root-image/boot/parabolaiso.img ${work_dir}/iso/${iso_dirname}/boot/${arch}/parabolaiso.img cp ${work_dir}/${arch}/root-image/boot/vmlinuz-linux-libre ${work_dir}/iso/${iso_dirname}/boot/${arch}/vmlinuz } # Add other aditional/extra files to ${iso_dirname}/boot/ make_boot_extra() { cp ${work_dir}/${arch}/root-image/boot/memtest86+/memtest.bin ${work_dir}/iso/${iso_dirname}/boot/memtest cp ${work_dir}/${arch}/root-image/usr/share/licenses/common/GPL2/license.txt ${work_dir}/iso/${iso_dirname}/boot/memtest.COPYING } # Prepare /${iso_dirname}/boot/syslinux make_syslinux() { mkdir -p ${work_dir}/iso/${iso_dirname}/boot/syslinux for _cfg in ${releng_dir}/syslinux/*.cfg; do sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; s|%INSTALL_DIR%|${iso_dirname}|g" ${_cfg} > ${work_dir}/iso/${iso_dirname}/boot/syslinux/${_cfg##*/} done cp ${releng_dir}/syslinux/splash.png ${work_dir}/iso/${iso_dirname}/boot/syslinux cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/*.c32 ${work_dir}/iso/${iso_dirname}/boot/syslinux cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/lpxelinux.0 ${work_dir}/iso/${iso_dirname}/boot/syslinux cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/memdisk ${work_dir}/iso/${iso_dirname}/boot/syslinux mkdir -p ${work_dir}/iso/${iso_dirname}/boot/syslinux/hdt gzip -c -9 ${work_dir}/${arch}/root-image/usr/share/hwdata/pci.ids > ${work_dir}/iso/${iso_dirname}/boot/syslinux/hdt/pciids.gz gzip -c -9 ${work_dir}/${arch}/root-image/usr/lib/modules/*-gnu-*/modules.alias > ${work_dir}/iso/${iso_dirname}/boot/syslinux/hdt/modalias.gz # inject edition title sed -i "s|_EDITION_TITLE_|${iso_title}|" ${work_dir}/iso/${iso_dirname}/boot/syslinux/parabolaiso_head.cfg } # Prepare /isolinux make_isolinux() { mkdir -p ${work_dir}/iso/isolinux sed "s|%INSTALL_DIR%|${iso_dirname}|g" ${releng_dir}/isolinux/isolinux.cfg > ${work_dir}/iso/isolinux/isolinux.cfg cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/isolinux.bin ${work_dir}/iso/isolinux/ cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/isohdpfx.bin ${work_dir}/iso/isolinux/ cp ${work_dir}/${arch}/root-image/usr/lib/syslinux/bios/ldlinux.c32 ${work_dir}/iso/isolinux/ } # Prepare /EFI make_efi() { mkdir -p ${work_dir}/iso/EFI/boot cp ${work_dir}/x86_64/root-image/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${work_dir}/iso/EFI/boot/bootx64.efi mkdir -p ${work_dir}/iso/loader/entries cp ${releng_dir}/efiboot/loader/loader.conf ${work_dir}/iso/loader/ cp ${releng_dir}/efiboot/loader/entries/uefi-shell-v2-x86_64.conf ${work_dir}/iso/loader/entries/ cp ${releng_dir}/efiboot/loader/entries/uefi-shell-v1-x86_64.conf ${work_dir}/iso/loader/entries/ sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; s|%INSTALL_DIR%|${iso_dirname}|g" \ ${releng_dir}/efiboot/loader/entries/parabolaiso-x86_64-usb.conf > ${work_dir}/iso/loader/entries/parabolaiso-x86_64.conf # EFI Shell 2.0 for UEFI 2.3+ ( http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UEFI_Shell ) cp ${data_dir}/Shell.efi ${work_dir}/iso/EFI/shellx64_v2.efi # EFI Shell 1.0 for non UEFI 2.3+ ( http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=Efi-shell ) cp ${data_dir}/Shell_Full.efi ${work_dir}/iso/EFI/shellx64_v1.efi } # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode make_efiboot() { # cleanup from previous runs while mount | grep ${work_dir}/efiboot; do umount ${work_dir}/efiboot; sleep 1; done; rm ${work_dir}/iso/EFI/parabolaiso/efiboot.img 2> /dev/null || true # create EFI image mkdir -p ${work_dir}/iso/EFI/parabolaiso truncate -s ${efi_img_kbytes}K ${work_dir}/iso/EFI/parabolaiso/efiboot.img mkfs.vfat -n PARABOLAISO_EFI ${work_dir}/iso/EFI/parabolaiso/efiboot.img mkdir -p ${work_dir}/efiboot mkdir -p ${work_dir}/efiboot-staging mount ${work_dir}/iso/EFI/parabolaiso/efiboot.img ${work_dir}/efiboot mkdir -p ${work_dir}/efiboot-staging/EFI/parabolaiso cp ${work_dir}/iso/${iso_dirname}/boot/x86_64/vmlinuz ${work_dir}/efiboot-staging/EFI/parabolaiso/vmlinuz.efi cp ${work_dir}/iso/${iso_dirname}/boot/x86_64/parabolaiso.img ${work_dir}/efiboot-staging/EFI/parabolaiso/parabolaiso.img mkdir -p ${work_dir}/efiboot-staging/EFI/boot cp ${work_dir}/x86_64/root-image/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${work_dir}/efiboot-staging/EFI/boot/bootx64.efi mkdir -p ${work_dir}/efiboot-staging/loader/entries cp ${releng_dir}/efiboot/loader/loader.conf ${work_dir}/efiboot-staging/loader/ cp ${releng_dir}/efiboot/loader/entries/uefi-shell-v2-x86_64.conf ${work_dir}/efiboot-staging/loader/entries/ cp ${releng_dir}/efiboot/loader/entries/uefi-shell-v1-x86_64.conf ${work_dir}/efiboot-staging/loader/entries/ sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; s|%INSTALL_DIR%|${iso_dirname}|g" \ ${releng_dir}/efiboot/loader/entries/parabolaiso-x86_64-cd.conf > ${work_dir}/efiboot-staging/loader/entries/parabolaiso-x86_64.conf cp ${work_dir}/iso/EFI/shellx64_v2.efi ${work_dir}/efiboot-staging/EFI/ cp ${work_dir}/iso/EFI/shellx64_v1.efi ${work_dir}/efiboot-staging/EFI/ efi_kbytes=$(($(du -ks ${work_dir}/efiboot-staging | cut -f 1) + 32)) if [[ ${efi_kbytes} -lt $((${efi_img_kbytes})) ]]; then echo "Populating EFI image (${efi_kbytes}KB)" cp -rT ${work_dir}/efiboot-staging ${work_dir}/efiboot rm -rf ${work_dir}/efiboot-staging umount ${work_dir}/efiboot else echo "Error: Not enough space on EFI image (${efi_img_kbytes}KB - need ${efi_kbytes}KB)" umount ${work_dir}/efiboot exit 1 fi } # Copy aitab make_aitab() { mkdir -p ${work_dir}/iso/${iso_dirname} cp ${releng_dir}/aitab ${work_dir}/iso/${iso_dirname}/aitab } # Build all filesystem images specified in aitab (.fs.sfs .sfs) make_prepare() { cp -a -l -f ${work_dir}/${arch}/root-image ${work_dir} setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir} -D ${iso_dirname} pkglist setarch ${arch} mkparabolaiso ${verbose} -w ${work_dir} -D ${iso_dirname} prepare rm -rf ${work_dir}/root-image # rm -rf ${work_dir}/${arch}/root-image (if low space, this helps) } # Build ISO make_iso() { iso_filename=$(echo $iso_filename | tr '[:upper:]/' '[:lower:]-' | sed 's/\s//g') mkparabolaiso ${verbose} -w ${work_dir} -D ${iso_dirname} checksum mkparabolaiso ${verbose} -w ${work_dir} -D ${iso_dirname} -L ${iso_label} -o ${out_dir} iso ${iso_filename} } ## prepare state ## # set CLI options while getopts 'V:L:D:w:o:vh' arg; do case "${arg}" in V) iso_version="${OPTARG}" ;; L) iso_label="${OPTARG}" ;; D) iso_dirname="${OPTARG}" ;; w) work_dir="${OPTARG}" ;; o) out_dir="${OPTARG}" ;; v) verbose="-v" ;; h) _usage 0 ;; *) echo "Invalid argument '${arg}'" _usage 1 ;; esac done ## sanity checks ## # validate build environment if [[ "$(uname -m)" != 'x86_64' ]] || ! grep 'ID_LIKE=.*archlinux' /usr/lib/os-release > /dev/null; then echo "This script needs to be run on an x86_64 ArchLinux derrivative." exit 1 elif [[ ${EUID} -ne 0 ]]; then echo "This script needs to be run with root privileges." exit 1 elif ! pacman --version | grep libalpm > /dev/null; then echo "This script needs the 'pacman' package manager to be installed." exit 1 elif ! pacman -Qi parabolaiso-data > /dev/null; then echo "This script needs the 'parabolaiso-data' package to be installed." exit 1 fi # sanitize paths iso_label=${iso_label// /} iso_dirname=${iso_dirname// /} work_dir=${work_dir// /} out_dir=${out_dir// /} pacman_conf=${pacman_conf// /} iso_title="${iso_title} ${iso_version}" iso_filename="parabola-${iso_edition}-${iso_type}-${iso_version}.iso" ## build ISO ## chown -R 0:0 "${releng_dir}/root-image/" mkdir -p ${work_dir} run_once make_pacman_conf # Do all stuff for each root-image for arch in i686 x86_64; do run_once make_basefs run_once make_packages run_once make_setup_mkinitcpio run_once make_customize_root_image done for arch in i686 x86_64; do run_once make_boot done # Do all stuff for "iso" run_once make_boot_extra run_once make_syslinux run_once make_isolinux run_once make_efi run_once make_efiboot run_once make_aitab for arch in i686 x86_64; do run_once make_prepare done run_once make_iso