#!/bin/bash # # Copyright (c) 2018-2020 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # # Utility for adding patches to an unpatched ISO # source "$(dirname $0)/image-utils.sh" if [ -z "${MY_REPO}" ]; then echo "Required environment variable MY_REPO is not set" exit 1 fi if [ -z "${MY_WORKSPACE}" ]; then echo "Required environment variable MY_WORKSPACE is not set" exit 1 fi STX_DIR=${MY_REPO}/stx SETUP_PATCH_REPO=${STX_DIR}/update/extras/scripts/setup_patch_repo.sh if [ ! -x ${SETUP_PATCH_REPO} ]; then echo "Cannot find or execute ${SETUP_PATCH_REPO}" exit 1 fi # Create temp dir if necessary export TMPDIR="$MY_WORKSPACE/tmp" mkdir -p $TMPDIR REPO_UPGRADES_DIR=${STX_DIR}/metal/bsp-files/upgrades RELEASE_INFO="$(get_release_info)" if [ $? -ne 0 ]; then echo "ERROR: failed to find a release info file." exit 1 fi PLATFORM_RELEASE=$(source $RELEASE_INFO && echo $PLATFORM_RELEASE) function usage() { echo "" echo "Usage: " echo " $(basename $0) -i -o [ -u ] ..." echo " -i : Specify input ISO file" echo " -o : Specify output ISO file" echo " -u : Update with upgrades files from ${REPO_UPGRADES_DIR}" echo "" } function extract_pkg_from_patch_repo() { local repodir=${BUILDDIR}/patches local pkgname=$1 local pkgfile=$(repoquery --disablerepo=* --repofrompath local,${repodir} --enablerepo=local --location -q ${pkgname}) if [ -z "${pkgfile}" ]; then return 1 fi rpm2cpio ${pkgfile/file://} | cpio -idmv if [ $? -ne 0 ]; then echo "Failed to extract $pkgname files from ${pkgfile/file://}" exit 1 fi } declare INPUT_ISO= declare OUTPUT_ISO= declare ORIG_PWD=$PWD declare DO_UPGRADES=1 while getopts "i:o:u" opt; do case $opt in i) INPUT_ISO=$OPTARG ;; o) OUTPUT_ISO=$OPTARG ;; u) DO_UPGRADES=0 ;; *) usage exit 1 ;; esac done if [ -z "$INPUT_ISO" -o -z "$OUTPUT_ISO" ]; then usage exit 1 fi if [ ! -f ${INPUT_ISO} ]; then echo "Input file does not exist: ${INPUT_ISO}" exit 1 fi if [ -f ${OUTPUT_ISO} ]; then echo "Output file already exists: ${OUTPUT_ISO}" exit 1 fi shift $((OPTIND-1)) if [ $# -le 0 ]; then usage exit fi for pf in $@; do if [ ! -f $pf ]; then echo "Patch file $pf does not exist" exit 1 fi if [[ ! $pf =~ \.patch$ ]]; then echo "Specified file $pf does not have .patch extension" exit 1 fi done declare MNTDIR= declare BUILDDIR= declare WORKDIR= function check_requirements { local -a required_utils=( rsync mkisofs isohybrid implantisomd5 ) if [ $UID -ne 0 ]; then # If running as non-root user, additional utils are required required_utils+=( guestmount guestunmount ) fi local -i missing=0 for req in ${required_utils[@]}; do which ${req} >&/dev/null if [ $? -ne 0 ]; then echo "Unable to find required utility: ${req}" >&2 let missing++ fi done if [ ${missing} -gt 0 ]; then echo "One or more required utilities are missing. Aborting..." >&2 exit 1 fi } function mount_iso { if [ $UID -eq 0 ]; then # Mount the ISO mount -o loop ${INPUT_ISO} ${MNTDIR} if [ $? -ne 0 ]; then echo "Failed to mount ${INPUT_ISO}" >&2 exit 1 fi else # As non-root user, mount the ISO using guestmount guestmount -a ${INPUT_ISO} -m /dev/sda1 --ro ${MNTDIR} rc=$? if [ $rc -ne 0 ]; then # Add a retry echo "Call to guestmount failed with rc=$rc. Retrying once..." guestmount -a ${INPUT_ISO} -m /dev/sda1 --ro ${MNTDIR} rc=$? if [ $rc -ne 0 ]; then echo "Call to guestmount failed with rc=$rc. Aborting..." exit $rc fi fi fi } function unmount_iso { if [ $UID -eq 0 ]; then umount ${MNTDIR} else guestunmount ${MNTDIR} fi rmdir ${MNTDIR} } function cleanup() { if [ -n "$MNTDIR" -a -d "$MNTDIR" ]; then unmount_iso fi if [ -n "$BUILDDIR" -a -d "$BUILDDIR" ]; then \rm -rf $BUILDDIR fi if [ -n "$WORKDIR" -a -d "$WORKDIR" ]; then \rm -rf $WORKDIR fi } trap cleanup EXIT MNTDIR=$(mktemp -d -p $PWD patchiso_mnt_XXXXXX) if [ -z "${MNTDIR}" -o ! -d ${MNTDIR} ]; then echo "Failed to create mntdir. Aborting..." exit $rc fi BUILDDIR=$(mktemp -d -p $PWD patchiso_build_XXXXXX) if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then echo "Failed to create builddir. Aborting..." exit $rc fi # Mount the ISO mount_iso rsync -a ${MNTDIR}/ ${BUILDDIR}/ rc=$? if [ $rc -ne 0 ]; then echo "Call to rsync ISO content. Aborting..." exit $rc fi unmount_iso # Setup the patch repo ${SETUP_PATCH_REPO} -o ${BUILDDIR}/patches $@ rc=$? if [ $rc -ne 0 ]; then echo "Call to $(basename ${SETUP_PATCH_REPO}) failed with rc=$rc. Aborting..." exit $rc fi # Look for components that need modification #extract_pkg_from_patch_repo WORKDIR=$(mktemp -d -p $PWD patchiso_work_XXXXXX) if [ -z "${WORKDIR}" -o ! -d ${WORKDIR} ]; then echo "Failed to create workdir. Aborting..." exit $rc fi \cd ${WORKDIR} \mkdir extract \cd extract # Changes to copied files here must also be reflected in build-iso extract_pkg_from_patch_repo platform-kickstarts if [ $? -eq 0 ]; then # Replace files \rm -f ${BUILDDIR}/*ks.cfg && \cp --preserve=all var/www/pages/feed/rel-*/*.cfg ${BUILDDIR}/ && \cp --preserve=all ${BUILDDIR}/controller_ks.cfg ${BUILDDIR}/ks.cfg if [ $? -ne 0 ]; then echo "Failed to copy extracted kickstarts" exit 1 fi fi \cd ${WORKDIR} \rm -rf extract \mkdir extract \cd extract extract_pkg_from_patch_repo platform-kickstarts-pxeboot if [ $? -eq 0 ]; then # Replace files \rm -f ${BUILDDIR}/var/pxeboot/pxeboot_controller.cfg \ ${BUILDDIR}/var/pxeboot/pxeboot_smallsystem.cfg \ ${BUILDDIR}/var/pxeboot/pxeboot_smallsystem_lowlatency.cfg && \cp --preserve=all pxeboot/* ${BUILDDIR}/var/pxeboot/ if [ $? -ne 0 ]; then echo "Failed to copy extracted pxeboot kickstarts" exit 1 fi fi \cd ${WORKDIR} \rm -rf extract \mkdir extract \cd extract extract_pkg_from_patch_repo pxe-network-installer if [ $? -eq 0 ]; then # Replace files \rm -f ${BUILDDIR}/pxeboot/pxelinux.0 \ ${BUILDDIR}/pxeboot/menu.c32 \ ${BUILDDIR}/pxeboot/chain.c32 && \cp --preserve=all var/pxeboot/pxelinux.0 var/pxeboot/menu.c32 var/pxeboot/chain.c32 ${BUILDDIR}/pxeboot/ if [ $? -ne 0 ]; then echo "Error: Could not copy all files from installer" exit 1 fi \rm -f ${BUILDDIR}/LiveOS/squashfs.img && \cp --preserve=all var/www/pages/feed/rel-*/LiveOS/squashfs.img ${BUILDDIR}/LiveOS/ if [ $? -ne 0 ]; then echo "Error: Could not copy squashfs from LiveOS" exit 1 fi # Replace vmlinuz and initrd.img with our own pre-built ones \rm -f \ ${BUILDDIR}/vmlinuz \ ${BUILDDIR}/images/pxeboot/vmlinuz \ ${BUILDDIR}/initrd.img \ ${BUILDDIR}/images/pxeboot/initrd.img && \cp --preserve=all var/pxeboot/rel-*/installer-bzImage_1.0 \ ${BUILDDIR}/vmlinuz && \cp --preserve=all var/pxeboot/rel-*/installer-bzImage_1.0 \ ${BUILDDIR}/images/pxeboot/vmlinuz && \cp --preserve=all var/pxeboot/rel-*/installer-intel-x86-64-initrd_1.0 \ ${BUILDDIR}/initrd.img && \cp --preserve=all var/pxeboot/rel-*/installer-intel-x86-64-initrd_1.0 \ ${BUILDDIR}/images/pxeboot/initrd.img if [ $? -ne 0 ]; then echo "Error: Failed to copy installer images" exit 1 fi fi \cd ${WORKDIR} \rm -rf extract \mkdir extract \cd extract extract_pkg_from_patch_repo grub2-efi-x64-pxeboot if [ $? -eq 0 ]; then # Replace files \rm -f ${BUILDDIR}/var/pxeboot/EFI/grubx64.efi && \cp --preserve=all pxeboot/EFI/grubx64.efi ${BUILDDIR}/var/pxeboot/EFI/ if [ $? -ne 0 ]; then echo "Error: Failed to copy grub2-efi-x64-pxeboot files" exit 1 fi fi \cd ${WORKDIR} \rm -rf extract \mkdir extract \cd extract extract_pkg_from_patch_repo grub2-common if [ $? -eq 0 ]; then # Replace files for f in usr/lib/grub/x86_64-efi/*; do f_base=$(basename $f) \rm -f ${BUILDDIR}/var/pxeboot/EFI/$f_base && \cp --preserve=all ${f} ${BUILDDIR}/var/pxeboot/EFI/ if [ $? -ne 0 ]; then echo "Error: Failed to copy grub2-common files" exit 1 fi done fi \cd ${WORKDIR} \rm -rf extract \mkdir extract \cd extract extract_pkg_from_patch_repo grub2-efi-x64-modules if [ $? -eq 0 ]; then # Replace files for f in usr/lib/grub/x86_64-efi/*; do f_base=$(basename $f) \rm -f ${BUILDDIR}/var/pxeboot/EFI/$f_base && \cp --preserve=all ${f} ${BUILDDIR}/var/pxeboot/EFI/ if [ $? -ne 0 ]; then echo "Error: Failed to copy grub2-efi-x64-modules files" exit 1 fi done fi \cd ${WORKDIR} \rm -rf extract \cd ${ORIG_PWD} if [ ${DO_UPGRADES} -eq 0 ]; then # Changes to copied files here must also be reflected in build-iso echo "Updating upgrade support files" ISO_UPGRADES_DIR="${BUILDDIR}/upgrades" \rm -rf ${ISO_UPGRADES_DIR} \mkdir ${ISO_UPGRADES_DIR} \cp ${REPO_UPGRADES_DIR}/* ${ISO_UPGRADES_DIR} sed -i "s/xxxSW_VERSIONxxx/${PLATFORM_RELEASE}/g" ${ISO_UPGRADES_DIR}/metadata.xml chmod +x ${ISO_UPGRADES_DIR}/*.sh # Write the version out (used in upgrade scripts - this is the same as SW_VERSION) echo "VERSION=$PLATFORM_RELEASE" > ${ISO_UPGRADES_DIR}/version fi # Rebuild the ISO mkisofs -o ${OUTPUT_ISO} \ -R -D -A 'oe_iso_boot' -V 'oe_iso_boot' \ -quiet \ -b isolinux.bin -c boot.cat -no-emul-boot \ -boot-load-size 4 -boot-info-table \ -eltorito-alt-boot \ -e images/efiboot.img \ -no-emul-boot \ ${BUILDDIR} isohybrid --uefi ${OUTPUT_ISO} implantisomd5 ${OUTPUT_ISO} # Sign the .iso with the developer private key # Signing with the formal key is only to be done for customer release # and is a manual step afterwards, as with the GA ISO openssl dgst -sha256 \ -sign ${MY_REPO}/build-tools/signing/dev-private-key.pem \ -binary \ -out ${OUTPUT_ISO/%.iso/.sig} \ ${OUTPUT_ISO} rc=$? if [ $rc -ne 0 ]; then echo "Call to $(basename ${SETUP_PATCH_REPO}) failed with rc=$rc. Aborting..." exit $rc fi echo "Patched ISO: ${OUTPUT_ISO}"