ISO/configs/releng/build.sh

302 lines
13 KiB
Bash
Raw Normal View History

2020-07-11 10:42:57 +02:00
#!/usr/bin/env bash
set -e -u
iso_name=archlinux
iso_label="ARCH_$(date +%Y%m)"
iso_publisher="Arch Linux <http://www.archlinux.org>"
iso_application="Arch Linux Live/Rescue CD"
iso_version=$(date +%Y.%m.%d)
install_dir=arch
work_dir=work
out_dir=out
gpg_key=""
verbose=""
script_path=$(readlink -f "${0%/*}")
umask 0022
_usage ()
{
echo "usage ${0} [options]"
echo
echo " General options:"
echo " -N <iso_name> Set an iso filename (prefix)"
echo " Default: ${iso_name}"
echo " -V <iso_version> Set an iso version (in filename)"
echo " Default: ${iso_version}"
echo " -L <iso_label> Set an iso label (disk label)"
echo " Default: ${iso_label}"
echo " -P <publisher> Set a publisher for the disk"
echo " Default: '${iso_publisher}'"
echo " -A <application> Set an application name for the disk"
echo " Default: '${iso_application}'"
echo " -D <install_dir> Set an install_dir (directory inside iso)"
echo " Default: ${install_dir}"
echo " -w <work_dir> Set the working directory"
echo " Default: ${work_dir}"
echo " -o <out_dir> 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}" ]]; then
"$1"
touch "${work_dir}/build.${1}"
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" \
"${script_path}/pacman.conf" > "${work_dir}/pacman.conf"
}
# Base installation, plus needed packages (airootfs)
make_basefs() {
if [ -n "${verbose}" ]; then
mkarchiso -v -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" init
mkarchiso -v -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-p "haveged intel-ucode amd-ucode memtest86+ mkinitcpio-nfs-utils nbd zsh" install
else
mkarchiso -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" init
mkarchiso -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-p "haveged intel-ucode amd-ucode memtest86+ mkinitcpio-nfs-utils nbd zsh" install
fi
}
# Additional packages (airootfs)
make_packages() {
if [ -n "${verbose}" ]; then
mkarchiso -v -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-p "$(grep -h -v '^#' "${script_path}/packages.x86_64"| sed ':a;N;$!ba;s/\n/ /g')" install
else
mkarchiso -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-p "$(grep -h -v '^#' "${script_path}/packages.x86_64"| sed ':a;N;$!ba;s/\n/ /g')" install
fi
}
# Copy mkinitcpio archiso hooks and build initramfs (airootfs)
make_setup_mkinitcpio() {
local _hook
mkdir -p "${work_dir}/x86_64/airootfs/etc/initcpio/hooks"
mkdir -p "${work_dir}/x86_64/airootfs/etc/initcpio/install"
for _hook in archiso archiso_shutdown archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_loop_mnt; do
cp "/usr/lib/initcpio/hooks/${_hook}" "${work_dir}/x86_64/airootfs/etc/initcpio/hooks"
cp "/usr/lib/initcpio/install/${_hook}" "${work_dir}/x86_64/airootfs/etc/initcpio/install"
done
sed -i "s|/usr/lib/initcpio/|/etc/initcpio/|g" "${work_dir}/x86_64/airootfs/etc/initcpio/install/archiso_shutdown"
cp /usr/lib/initcpio/install/archiso_kms "${work_dir}/x86_64/airootfs/etc/initcpio/install"
cp /usr/lib/initcpio/archiso_shutdown "${work_dir}/x86_64/airootfs/etc/initcpio"
cp "${script_path}/mkinitcpio.conf" "${work_dir}/x86_64/airootfs/etc/mkinitcpio-archiso.conf"
if [[ "${gpg_key}" ]]; then
gpg --export "${gpg_key}" > "${work_dir}/gpgkey"
exec 17<>"${work_dir}/gpgkey"
fi
if [ -n "${verbose}" ]; then
ARCHISO_GNUPG_FD="${gpg_key:+17}" mkarchiso -v -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" \
-D "${install_dir}" \
-r 'mkinitcpio -c /etc/mkinitcpio-archiso.conf -k /boot/vmlinuz-linux -g /boot/archiso.img' run
else
ARCHISO_GNUPG_FD="${gpg_key:+17}" mkarchiso -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" \
-D "${install_dir}" \
-r 'mkinitcpio -c /etc/mkinitcpio-archiso.conf -k /boot/vmlinuz-linux -g /boot/archiso.img' run
fi
if [[ "${gpg_key}" ]]; then
exec 17<&-
fi
}
# Customize installation (airootfs)
make_customize_airootfs() {
cp -af --no-preserve=ownership "${script_path}/airootfs" "${work_dir}/x86_64"
cp "${script_path}/pacman.conf" "${work_dir}/x86_64/airootfs/etc"
if [ -n "${verbose}" ]; then
mkarchiso -v -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-r '/root/customize_airootfs.sh' run
else
mkarchiso -w "${work_dir}/x86_64" -C "${work_dir}/pacman.conf" -D "${install_dir}" \
-r '/root/customize_airootfs.sh' run
fi
rm "${work_dir}/x86_64/airootfs/root/customize_airootfs.sh"
chmod -f 750 "${work_dir}/x86_64/airootfs/root"
}
# Prepare kernel/initramfs ${install_dir}/boot/
make_boot() {
mkdir -p "${work_dir}/iso/${install_dir}/boot/x86_64"
cp "${work_dir}/x86_64/airootfs/boot/archiso.img" "${work_dir}/iso/${install_dir}/boot/x86_64/archiso.img"
cp "${work_dir}/x86_64/airootfs/boot/vmlinuz-linux" "${work_dir}/iso/${install_dir}/boot/x86_64/vmlinuz"
}
# Add other aditional/extra files to ${install_dir}/boot/
make_boot_extra() {
cp "${work_dir}/x86_64/airootfs/boot/memtest86+/memtest.bin" "${work_dir}/iso/${install_dir}/boot/memtest"
cp "${work_dir}/x86_64/airootfs/usr/share/licenses/common/GPL2/license.txt" \
"${work_dir}/iso/${install_dir}/boot/memtest.COPYING"
cp "${work_dir}/x86_64/airootfs/boot/intel-ucode.img" "${work_dir}/iso/${install_dir}/boot/intel_ucode.img"
cp "${work_dir}/x86_64/airootfs/usr/share/licenses/intel-ucode/LICENSE" \
"${work_dir}/iso/${install_dir}/boot/intel_ucode.LICENSE"
cp "${work_dir}/x86_64/airootfs/boot/amd-ucode.img" "${work_dir}/iso/${install_dir}/boot/amd_ucode.img"
cp "${work_dir}/x86_64/airootfs/usr/share/licenses/amd-ucode/LICENSE" \
"${work_dir}/iso/${install_dir}/boot/amd_ucode.LICENSE"
[configs/releng] Add UEFI boot support via Linux >= 3.3 EFI boot stub on x86_64 Makes an efiboot.img (FAT16) for "El Torito" (additional). Under an EFI-system, implies that this .ISO works only if is used as "CD-ROM/DVD-ROM" not in ISO-HYBRID-MBR mode. If you want, an EFI-ready USB-key, just unpack this "<ISO>/EFI/efiboot.img" (FAT16) to "<USB-key-FAT-formatted>/EFI" then copy "<ISO>/arch" and setup the filesystem label. An aditional EFI shell is provided with an startup script for automatic booting until EFI_STUB supports "linux.conf" to pass boot parms to kernel. Anyway I think that is a good idea to keep this shell, so can customize boot parms, or for doing other tasks on systems without an EFI-shell. RFCv1: Initial efiboot.img build with vmlinuz.efi (Linux with EFI_STUB enabled) and archiso.img (initramfs). RFCv2: Use an startup.nsh with EFI-Shell 2.0 (generated from build.sh) for automatic boot. RFCv3: Use and older EFI-Shell 1.0 instead of 2.0, since not all UEFI-systems are compatible with 2.3+ specs. RFCv4: The script "startup.nsh" improved by Keshav P R, using a for-loop (see notes below from original commit), now that has more than 1-line, I moved it to an independent file and is parsed by build.sh. ---- About startup.nsh: Author: Keshav P R <the.ridikulus.rat@gmail.com> Date: Thu Apr 5 10:33:20 2012 +0530 [configs/releng] Search in all existing UEFI FS mountpoints for archiso efistub kernel file There is no guarantee that the efistub kernel will always be in fs0: (similar to the case inside linux OS where the sda, sdb confusion exists, hence the need for UUIDs), especially when USB (instead os CD/ISO) is used for booting. Hence loop through all possible fs mountpoints (in UEFI) in startup.nsh and try to launch the first mountpoint that contains the archiso files. Cd's into the fs%m:\EFI\archiso directory also may remove future issues with efistub's linux.conf where the efistub might have problems identifying the directory from which the kernel was launched. Also add an helpful echo message showing the user the UEFI PATH to the archiso kernel file being launched by startup.nsh . Hopefully this should work in both CD and USB. Tested in Tianocore UDK/EDK2 DuetPkg X64 UEFI 2.3.1 firmware with EdkShellBinPkg's Shell. ---- Signed-off-by: Gerardo Exequiel Pozzi <vmlinuz386@yahoo.com.ar>
2012-04-11 02:01:12 +02:00
}
# Prepare /${install_dir}/boot/syslinux
make_syslinux() {
_uname_r=$(file -b "${work_dir}/x86_64/airootfs/boot/vmlinuz-linux"| awk 'f{print;f=0} /version/{f=1}' RS=' ')
mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux"
for _cfg in "${script_path}/syslinux/"*.cfg; do
sed "s|%ARCHISO_LABEL%|${iso_label}|g;
s|%INSTALL_DIR%|${install_dir}|g" "${_cfg}" > "${work_dir}/iso/${install_dir}/boot/syslinux/${_cfg##*/}"
done
cp "${script_path}/syslinux/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
cp "${work_dir}/x86_64/airootfs/usr/lib/syslinux/bios/"*.c32 "${work_dir}/iso/${install_dir}/boot/syslinux"
cp "${work_dir}/x86_64/airootfs/usr/lib/syslinux/bios/lpxelinux.0" "${work_dir}/iso/${install_dir}/boot/syslinux"
cp "${work_dir}/x86_64/airootfs/usr/lib/syslinux/bios/memdisk" "${work_dir}/iso/${install_dir}/boot/syslinux"
mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux/hdt"
gzip -c -9 "${work_dir}/x86_64/airootfs/usr/share/hwdata/pci.ids" > \
"${work_dir}/iso/${install_dir}/boot/syslinux/hdt/pciids.gz"
gzip -c -9 "${work_dir}/x86_64/airootfs/usr/lib/modules/${_uname_r}/modules.alias" > \
"${work_dir}/iso/${install_dir}/boot/syslinux/hdt/modalias.gz"
}
# Prepare /isolinux
make_isolinux() {
mkdir -p "${work_dir}/iso/isolinux"
sed "s|%INSTALL_DIR%|${install_dir}|g" \
"${script_path}/isolinux/isolinux.cfg" > "${work_dir}/iso/isolinux/isolinux.cfg"
cp "${work_dir}/x86_64/airootfs/usr/lib/syslinux/bios/isolinux.bin" "${work_dir}/iso/isolinux/"
cp "${work_dir}/x86_64/airootfs/usr/lib/syslinux/bios/isohdpfx.bin" "${work_dir}/iso/isolinux/"
cp "${work_dir}/x86_64/airootfs/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/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
"${work_dir}/iso/EFI/boot/bootx64.efi"
mkdir -p "${work_dir}/iso/loader/entries"
cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/iso/loader/"
sed "s|%ARCHISO_LABEL%|${iso_label}|g;
s|%INSTALL_DIR%|${install_dir}|g" \
"${script_path}/efiboot/loader/entries/archiso-x86_64-usb.conf" > \
"${work_dir}/iso/loader/entries/archiso-x86_64.conf"
# edk2-shell based UEFI shell
# shellx64.efi is picked up automatically when on /
cp /usr/share/edk2-shell/x64/Shell_Full.efi "${work_dir}/iso/shellx64.efi"
}
# Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
make_efiboot() {
mkdir -p "${work_dir}/iso/EFI/archiso"
truncate -s 64M "${work_dir}/iso/EFI/archiso/efiboot.img"
mkfs.fat -n ARCHISO_EFI "${work_dir}/iso/EFI/archiso/efiboot.img"
mkdir -p "${work_dir}/efiboot"
mount "${work_dir}/iso/EFI/archiso/efiboot.img" "${work_dir}/efiboot"
mkdir -p "${work_dir}/efiboot/EFI/archiso"
cp "${work_dir}/iso/${install_dir}/boot/x86_64/vmlinuz" "${work_dir}/efiboot/EFI/archiso/vmlinuz.efi"
cp "${work_dir}/iso/${install_dir}/boot/x86_64/archiso.img" "${work_dir}/efiboot/EFI/archiso/archiso.img"
cp "${work_dir}/iso/${install_dir}/boot/intel_ucode.img" "${work_dir}/efiboot/EFI/archiso/intel_ucode.img"
cp "${work_dir}/iso/${install_dir}/boot/amd_ucode.img" "${work_dir}/efiboot/EFI/archiso/amd_ucode.img"
mkdir -p "${work_dir}/efiboot/EFI/boot"
cp "${work_dir}/x86_64/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
"${work_dir}/efiboot/EFI/boot/bootx64.efi"
mkdir -p "${work_dir}/efiboot/loader/entries"
cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/efiboot/loader/"
sed "s|%ARCHISO_LABEL%|${iso_label}|g;
s|%INSTALL_DIR%|${install_dir}|g" \
"${script_path}/efiboot/loader/entries/archiso-x86_64-cd.conf" > \
"${work_dir}/efiboot/loader/entries/archiso-x86_64.conf"
# shellx64.efi is picked up automatically when on /
cp "${work_dir}/iso/shellx64.efi" "${work_dir}/efiboot/"
umount -d "${work_dir}/efiboot"
}
# Build airootfs filesystem image
make_prepare() {
cp -a -l -f "${work_dir}/x86_64/airootfs" "${work_dir}"
if [ -n "${verbose}" ]; then
mkarchiso -v -w "${work_dir}" -D "${install_dir}" pkglist
mkarchiso -v -w "${work_dir}" -D "${install_dir}" ${gpg_key:+-g ${gpg_key}} prepare
else
mkarchiso -w "${work_dir}" -D "${install_dir}" pkglist
mkarchiso -w "${work_dir}" -D "${install_dir}" ${gpg_key:+-g ${gpg_key}} prepare
fi
rm -rf "${work_dir}/airootfs"
# rm -rf "${work_dir}/x86_64/airootfs" (if low space, this helps)
}
# Build ISO
make_iso() {
if [ -n "${verbose}" ]; then
mkarchiso -v -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -P "${iso_publisher}" \
-A "${iso_application}" -o "${out_dir}" iso "${iso_name}-${iso_version}-x86_64.iso"
else
mkarchiso -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -P "${iso_publisher}" \
-A "${iso_application}" -o "${out_dir}" iso "${iso_name}-${iso_version}-x86_64.iso"
fi
}
if [[ ${EUID} -ne 0 ]]; then
echo "This script must be run as root."
_usage 1
fi
while getopts 'N:V:L:P:A:D:w:o:g:vh' arg; do
case "${arg}" in
N) iso_name="${OPTARG}" ;;
V) iso_version="${OPTARG}" ;;
L) iso_label="${OPTARG}" ;;
P) iso_publisher="${OPTARG}" ;;
A) iso_application="${OPTARG}" ;;
D) install_dir="${OPTARG}" ;;
w) work_dir="${OPTARG}" ;;
o) out_dir="${OPTARG}" ;;
g) gpg_key="${OPTARG}" ;;
v) verbose="-v" ;;
h) _usage 0 ;;
*)
echo "Invalid argument '${arg}'"
_usage 1
;;
esac
done
mkdir -p "${work_dir}"
run_once make_pacman_conf
run_once make_basefs
run_once make_packages
run_once make_setup_mkinitcpio
run_once make_customize_airootfs
run_once make_boot
run_once make_boot_extra
run_once make_syslinux
run_once make_isolinux
run_once make_efi
run_once make_efiboot
run_once make_prepare
run_once make_iso