diff --git a/utilities/platform-util/centos/platform-util.spec b/utilities/platform-util/centos/platform-util.spec index 176dbf4e..806c0870 100644 --- a/utilities/platform-util/centos/platform-util.spec +++ b/utilities/platform-util/centos/platform-util.spec @@ -61,10 +61,10 @@ install %{_buildsubdir}/scripts/tc_setup.sh %{buildroot}%{local_bindir} install %{_buildsubdir}/scripts/remotelogging_tc_setup.sh %{buildroot}%{local_bindir} install %{_buildsubdir}/scripts/connectivity_test %{buildroot}%{local_bindir} install -m 555 %{_buildsubdir}/scripts/is-rootdisk-device.sh %{buildroot}%{local_bindir} -install -m 555 %{_buildsubdir}/scripts/update-iso.sh %{buildroot}%{local_bindir} +install -m 555 %{_buildsubdir}/scripts/update-iso-centos.sh %{buildroot}%{local_bindir}/update-iso.sh install -m 555 %{_buildsubdir}/scripts/gen-bootloader-iso-centos.sh %{buildroot}%{local_bindir} install -m 555 %{_buildsubdir}/scripts/prepare-prestage-packages.sh %{buildroot}%{local_bindir} -install -m 555 %{_buildsubdir}/scripts/stx-iso-utils.sh %{buildroot}%{local_bindir} +install -m 555 %{_buildsubdir}/scripts/stx-iso-utils-centos.sh %{buildroot}%{local_bindir}/stx-iso-utils.sh install -m 555 %{_buildsubdir}/scripts/show-certs.sh %{buildroot}%{local_bindir} install -m 555 %{_buildsubdir}/scripts/update_docker_registry_auth.sh %{buildroot}%{local_bindir} install -m 555 %{_buildsubdir}/scripts/change_system_private_registry.sh %{buildroot}%{local_bindir} diff --git a/utilities/platform-util/scripts/stx-iso-utils-centos.sh b/utilities/platform-util/scripts/stx-iso-utils-centos.sh new file mode 100644 index 00000000..2e1ff42d --- /dev/null +++ b/utilities/platform-util/scripts/stx-iso-utils-centos.sh @@ -0,0 +1,290 @@ +#!/bin/bash +# +# Copyright (c) 2020 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Common bash utility functions for StarlingX ISO tools +# + +declare BUILDDIR= +declare EFIBOOT_IMG_LOOP= +declare EFI_MOUNT= +declare MNTDIR= +declare WORKDIR= + +function common_cleanup { + unmount_efiboot_img + + 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 +} + +function common_check_requirements { + local -a required_utils=( + awk + grep + implantisomd5 + isohybrid + mkisofs + mktemp + rm + rmdir + rsync + sed + ) + if [ $UID -eq 0 ]; then + required_utils+=( + losetup + mount + mountpoint + umount + ) + else + # If running as non-root user, additional utils are required + required_utils+=( + guestmount + guestunmount + udisksctl + ) + fi + + required_utils+=( $@ ) + + local -i missing=0 + + which which >&/dev/null + if [ $? -ne 0 ]; then + log_error "Unable to find 'which' utility. Aborting..." + exit 1 + fi + + for req in ${required_utils[@]}; do + which ${req} >&/dev/null + if [ $? -ne 0 ]; then + log_error "Unable to find required utility: ${req}" + let -i missing++ + fi + done + + if [ ${missing} -gt 0 ]; then + log_error "One or more required utilities are missing. Aborting..." + exit 1 + fi +} + +function check_required_param { + local param="${1}" + local value="${2}" + + if [ -z "${value}" ]; then + log_error "Required parameter ${param} is not set" + exit 1 + fi +} + +function check_files_exist { + for value in "$@"; do + if [ ! -f "${value}" ]; then + log_error "file path '${value}' is invalid" + exit 1 + fi + done +} + +function check_files_size { + local file_size + + # Aprox 4 GB file size limit for iso file systems. + local file_size_limit=4000000000 + + for value in "$@"; do + file_size=$(stat --printf="%s" ${value}) + if [ ${file_size} -gt ${file_size_limit} ]; then + log_error "file size of '${value}' exceeds 4 GB limit" + exit 1 + fi + done +} + +function mount_iso { + local input_iso=$1 + local basedir=${2:-$PWD} + + MNTDIR=$(mktemp -d -p "$basedir" stx-iso-utils_mnt_XXXXXX) + if [ -z "${MNTDIR}" -o ! -d ${MNTDIR} ]; then + log_error "Failed to create mntdir $MNTDIR. Aborting..." + exit 1 + fi + + 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 mount_efiboot_img { + local isodir=$1 + + if [ -e ${isodir}/images/efiboot.img ]; then + local efiboot_img=${isodir}/images/efiboot.img + else + local efiboot_img=${isodir}/efi.img + fi + + local loop_setup_output= + + if [ $UID -eq 0 ]; then + # As root, setup a writeable loop device for the + # efiboot.img file and mount it + loop_setup_output=$(losetup --show -f ${efiboot_img}) + if [ $? -ne 0 ]; then + echo "Failed losetup" >&2 + exit 1 + fi + + EFIBOOT_IMG_LOOP=${loop_setup_output} + + EFI_MOUNT=$(mktemp -d -p /mnt -t EFI-noudev.XXXXXX) + mount ${EFIBOOT_IMG_LOOP} ${EFI_MOUNT} + if [ $? -ne 0 ]; then + echo "Failed to mount loop device ${EFIBOOT_IMG_LOOP}" >&2 + exit 1 + fi + else + # As non-root user, we can use the udisksctl to setup a loop device + # and mount the efiboot.img, with read/write access. + loop_setup_output=$(udisksctl loop-setup -f ${efiboot_img} --no-user-interaction) + if [ $? -ne 0 ]; then + echo "Failed udisksctl loop-setup" >&2 + exit 1 + fi + + EFIBOOT_IMG_LOOP=$(echo ${loop_setup_output} | awk '{print $5;}' | sed -e 's/\.$//g') + if [ -z "${EFIBOOT_IMG_LOOP}" ]; then + echo "Failed to determine loop device from command output:" >&2 + echo "${loop_setup_output}" >&2 + exit 1 + fi + + udisksctl mount -b ${EFIBOOT_IMG_LOOP} + if [ $? -ne 0 ]; then + echo "Failed udisksctl mount" >&2 + exit 1 + fi + + EFI_MOUNT=$(udisksctl info -b ${EFIBOOT_IMG_LOOP} | grep MountPoints | awk '{print $2;}') + if [ -z "${EFI_MOUNT}" ]; then + echo "Failed to determine mount point from udisksctl info command" >&2 + exit 1 + fi + fi +} + +function unmount_efiboot_img { + if [ $UID -eq 0 ]; then + if [ -n "${EFI_MOUNT}" ]; then + mountpoint -q ${EFI_MOUNT} && umount ${EFI_MOUNT} + rmdir ${EFI_MOUNT} + EFI_MOUNT= + fi + + if [ -n "${EFIBOOT_IMG_LOOP}" ]; then + losetup -d ${EFIBOOT_IMG_LOOP} + EFIBOOT_IMG_LOOP= + fi + else + if [ -n "${EFIBOOT_IMG_LOOP}" ]; then + udisksctl unmount -b ${EFIBOOT_IMG_LOOP} + udisksctl loop-delete -b ${EFIBOOT_IMG_LOOP} + EFI_MOUNT= + EFIBOOT_IMG_LOOP= + fi + fi +} + +function update_parameter { + local isodir=$1 + local param=$2 + local value=$3 + + if [ -z "${EFI_MOUNT}" ]; then + mount_efiboot_img ${isodir} + fi + + for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do + grep -q "^[[:space:]]*append\>.*[[:space:]]${param}=" ${f} + if [ $? -eq 0 ]; then + # Parameter already exists. Update the value + sed -i -e "s#^\([[:space:]]*append\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f} + if [ $? -ne 0 ]; then + log_error "Failed to update parameter ($param)" + exit 1 + fi + else + # Parameter doesn't exist. Add it to the cmdline + sed -i -e "s|^\([[:space:]]*append\>.*\)|\1 ${param}=${value}|" ${f} + if [ $? -ne 0 ]; then + log_error "Failed to add parameter ($param)" + exit 1 + fi + fi + done + + for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do + grep -q "^[[:space:]]*linuxefi\>.*[[:space:]]${param}=" ${f} + if [ $? -eq 0 ]; then + # Parameter already exists. Update the value + sed -i -e "s#^\([[:space:]]*linuxefi\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f} + if [ $? -ne 0 ]; then + log_error "Failed to update parameter ($param)" + exit 1 + fi + else + # Parameter doesn't exist. Add it to the cmdline + sed -i -e "s|^\([[:space:]]*linuxefi\>.*\)|\1 ${param}=${value}|" ${f} + if [ $? -ne 0 ]; then + log_error "Failed to add parameter ($param)" + exit 1 + fi + fi + done +} + diff --git a/utilities/platform-util/scripts/stx-iso-utils.sh b/utilities/platform-util/scripts/stx-iso-utils.sh index 2e1ff42d..402d9ccc 100644 --- a/utilities/platform-util/scripts/stx-iso-utils.sh +++ b/utilities/platform-util/scripts/stx-iso-utils.sh @@ -13,19 +13,28 @@ declare EFI_MOUNT= declare MNTDIR= declare WORKDIR= +function ilog { + echo "$(date "+%F %H-%M-%S"): $*" >&2 +} + +function elog { + echo "$(date "+%F %H-%M-%S") Error: $*" >&2 + exit 1 +} + function common_cleanup { unmount_efiboot_img - if [ -n "$MNTDIR" -a -d "$MNTDIR" ]; then + if [ -n "${MNTDIR}" ] && [ -d "${MNTDIR}" ]; then unmount_iso fi - if [ -n "$BUILDDIR" -a -d "$BUILDDIR" ]; then - \rm -rf $BUILDDIR + if [ -n "${BUILDDIR}" ] && [ -d "${BUILDDIR}" ]; then + \rm -rf "${BUILDDIR}" fi - if [ -n "$WORKDIR" -a -d "$WORKDIR" ]; then - \rm -rf $WORKDIR + if [ -n "${WORKDIR}" ] && [ -d "${WORKDIR}" ]; then + \rm -rf "${WORKDIR}" fi } @@ -58,27 +67,26 @@ function common_check_requirements { ) fi - required_utils+=( $@ ) + required_utils+=( "$@" ) local -i missing=0 - which which >&/dev/null - if [ $? -ne 0 ]; then - log_error "Unable to find 'which' utility. Aborting..." - exit 1 + if which which >&/dev/null -ne 0 ; then + elog "Unable to find 'which' utility. Aborting..." fi - for req in ${required_utils[@]}; do - which ${req} >&/dev/null - if [ $? -ne 0 ]; then - log_error "Unable to find required utility: ${req}" - let -i missing++ + for req in "${required_utils[@]}"; do + which "${req}" >&/dev/null + if [ $? -ne 0 ] ; then + ilog "Unable to find required utility: ${req}" + (( missing++ )) fi done - if [ ${missing} -gt 0 ]; then - log_error "One or more required utilities are missing. Aborting..." - exit 1 + if [ "${missing}" -gt 0 ]; then + elog "One or more required utilities are missing. Aborting..." + else + ilog "all required iso utilities present" fi } @@ -87,16 +95,14 @@ function check_required_param { local value="${2}" if [ -z "${value}" ]; then - log_error "Required parameter ${param} is not set" - exit 1 + elog "Required parameter ${param} is not set" fi } function check_files_exist { for value in "$@"; do if [ ! -f "${value}" ]; then - log_error "file path '${value}' is invalid" - exit 1 + elog "file path '${value}' is invalid" fi done } @@ -108,10 +114,9 @@ function check_files_size { local file_size_limit=4000000000 for value in "$@"; do - file_size=$(stat --printf="%s" ${value}) - if [ ${file_size} -gt ${file_size_limit} ]; then - log_error "file size of '${value}' exceeds 4 GB limit" - exit 1 + file_size=$(stat --printf="%s" "${value}") + if [ "${file_size}" -gt "${file_size_limit}" ]; then + elog "file size of '${value}' exceeds 4 GB limit" fi done } @@ -121,52 +126,51 @@ function mount_iso { local basedir=${2:-$PWD} MNTDIR=$(mktemp -d -p "$basedir" stx-iso-utils_mnt_XXXXXX) - if [ -z "${MNTDIR}" -o ! -d ${MNTDIR} ]; then - log_error "Failed to create mntdir $MNTDIR. Aborting..." - exit 1 + if [ -z "${MNTDIR}" ] || [ ! -d "${MNTDIR}" ]; then + elog "Failed to create mntdir $MNTDIR. Aborting..." fi if [ $UID -eq 0 ]; then # Mount the ISO - mount -o loop ${input_iso} ${MNTDIR} + ilog "mounting ${input_iso} to ${MNTDIR}" + mount -o loop "${input_iso}" "${MNTDIR}" >&/dev/null if [ $? -ne 0 ]; then - echo "Failed to mount ${input_iso}" >&2 - exit 1 + elog "Failed to mount ${input_iso}" >&2 fi else # As non-root user, mount the ISO using guestmount - guestmount -a ${input_iso} -m /dev/sda1 --ro ${MNTDIR} + guestmount -a "${input_iso}" -m /dev/sda1 --ro "${MNTDIR}" rc=$? - if [ $rc -ne 0 ]; then + if [ "${rc}" -ne 0 ]; then # Add a retry - echo "Call to guestmount failed with rc=$rc. Retrying once..." + ilog "Call to guestmount failed with rc=$rc. Retrying once..." - guestmount -a ${input_iso} -m /dev/sda1 --ro ${MNTDIR} + guestmount -a "${input_iso}" -m /dev/sda1 --ro "${MNTDIR}" >&/dev/null rc=$? - if [ $rc -ne 0 ]; then - echo "Call to guestmount failed with rc=$rc. Aborting..." - exit $rc + if [ ${rc} -ne 0 ]; then + elog "Call to guestmount failed with rc=$rc. Aborting..." fi fi fi } function unmount_iso { - if [ $UID -eq 0 ]; then - umount ${MNTDIR} + if [ "${UID}" -eq 0 ]; then + ilog "unmounting ${MNTDIR}" + umount "${MNTDIR}" >&/dev/null else - guestunmount ${MNTDIR} + guestunmount "${MNTDIR}" >&/dev/null fi - rmdir ${MNTDIR} + rmdir "${MNTDIR}" } function mount_efiboot_img { local isodir=$1 - if [ -e ${isodir}/images/efiboot.img ]; then - local efiboot_img=${isodir}/images/efiboot.img + if [ -e "${isodir}/images/efiboot.img" ]; then + local efiboot_img="${isodir}/images/efiboot.img" else - local efiboot_img=${isodir}/efi.img + local efiboot_img="${isodir}/efi.img" fi local loop_setup_output= @@ -174,45 +178,42 @@ function mount_efiboot_img { if [ $UID -eq 0 ]; then # As root, setup a writeable loop device for the # efiboot.img file and mount it - loop_setup_output=$(losetup --show -f ${efiboot_img}) + loop_setup_output=$(losetup --show -f "${efiboot_img}") if [ $? -ne 0 ]; then - echo "Failed losetup" >&2 - exit 1 + elog "Failed losetup" >&2 fi EFIBOOT_IMG_LOOP=${loop_setup_output} EFI_MOUNT=$(mktemp -d -p /mnt -t EFI-noudev.XXXXXX) - mount ${EFIBOOT_IMG_LOOP} ${EFI_MOUNT} + mount "${EFIBOOT_IMG_LOOP}" "${EFI_MOUNT}" if [ $? -ne 0 ]; then - echo "Failed to mount loop device ${EFIBOOT_IMG_LOOP}" >&2 - exit 1 + elog "Failed to mount loop device ${EFIBOOT_IMG_LOOP}" >&2 fi else # As non-root user, we can use the udisksctl to setup a loop device # and mount the efiboot.img, with read/write access. - loop_setup_output=$(udisksctl loop-setup -f ${efiboot_img} --no-user-interaction) + loop_setup_output=$(udisksctl loop-setup -f "${efiboot_img}" --no-user-interaction) if [ $? -ne 0 ]; then - echo "Failed udisksctl loop-setup" >&2 - exit 1 + elog "Failed udisksctl loop-setup" >&2 fi - EFIBOOT_IMG_LOOP=$(echo ${loop_setup_output} | awk '{print $5;}' | sed -e 's/\.$//g') + EFIBOOT_IMG_LOOP=$(echo "${loop_setup_output}" | awk '{print $5;}' | sed -e 's/\.$//g') if [ -z "${EFIBOOT_IMG_LOOP}" ]; then - echo "Failed to determine loop device from command output:" >&2 + echo "Error: Failed to determine loop device from command output:" >&2 echo "${loop_setup_output}" >&2 exit 1 fi - udisksctl mount -b ${EFIBOOT_IMG_LOOP} + udisksctl mount -b "${EFIBOOT_IMG_LOOP}" if [ $? -ne 0 ]; then - echo "Failed udisksctl mount" >&2 + echo "Error: Failed udisksctl mount" >&2 exit 1 fi - EFI_MOUNT=$(udisksctl info -b ${EFIBOOT_IMG_LOOP} | grep MountPoints | awk '{print $2;}') + EFI_MOUNT=$(udisksctl info -b "${EFIBOOT_IMG_LOOP}" | grep MountPoints | awk '{print $2;}') if [ -z "${EFI_MOUNT}" ]; then - echo "Failed to determine mount point from udisksctl info command" >&2 + echo "Error: Failed to determine mount point from udisksctl info command" >&2 exit 1 fi fi @@ -221,19 +222,19 @@ function mount_efiboot_img { function unmount_efiboot_img { if [ $UID -eq 0 ]; then if [ -n "${EFI_MOUNT}" ]; then - mountpoint -q ${EFI_MOUNT} && umount ${EFI_MOUNT} - rmdir ${EFI_MOUNT} + mountpoint -q "${EFI_MOUNT}" && umount "${EFI_MOUNT}" + rmdir "${EFI_MOUNT}" EFI_MOUNT= fi if [ -n "${EFIBOOT_IMG_LOOP}" ]; then - losetup -d ${EFIBOOT_IMG_LOOP} + losetup -d "${EFIBOOT_IMG_LOOP}" EFIBOOT_IMG_LOOP= fi else if [ -n "${EFIBOOT_IMG_LOOP}" ]; then - udisksctl unmount -b ${EFIBOOT_IMG_LOOP} - udisksctl loop-delete -b ${EFIBOOT_IMG_LOOP} + udisksctl unmount -b "${EFIBOOT_IMG_LOOP}" + udisksctl loop-delete -b "${EFIBOOT_IMG_LOOP}" EFI_MOUNT= EFIBOOT_IMG_LOOP= fi @@ -245,44 +246,41 @@ function update_parameter { local param=$2 local value=$3 + ilog "updating parameter ${param} to ${param}=${value}" if [ -z "${EFI_MOUNT}" ]; then - mount_efiboot_img ${isodir} + mount_efiboot_img "${isodir}" fi - for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do - grep -q "^[[:space:]]*append\>.*[[:space:]]${param}=" ${f} + for f in "${isodir}"/isolinux/isolinux.cfg ; do + grep -q "^[[:space:]]*append\>.*[[:space:]]${param}=" "${f}" if [ $? -eq 0 ]; then # Parameter already exists. Update the value - sed -i -e "s#^\([[:space:]]*append\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f} + sed -i -e "s#^\([[:space:]]*append\>.*${param}\)=[^[:space:]]*#\1=${value}#" "${f}" if [ $? -ne 0 ]; then - log_error "Failed to update parameter ($param)" - exit 1 + elog "Failed to update parameter ($param)" fi else # Parameter doesn't exist. Add it to the cmdline - sed -i -e "s|^\([[:space:]]*append\>.*\)|\1 ${param}=${value}|" ${f} + sed -i -e "s|^\([[:space:]]*append\>.*\)|\1 ${param}=${value}|" "${f}" if [ $? -ne 0 ]; then - log_error "Failed to add parameter ($param)" - exit 1 + elog "Failed to add parameter ($param)" fi fi done - for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do - grep -q "^[[:space:]]*linuxefi\>.*[[:space:]]${param}=" ${f} + for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg ; do + grep -q "^[[:space:]]*linux\>.*[[:space:]]${param}=" "${f}" if [ $? -eq 0 ]; then # Parameter already exists. Update the value - sed -i -e "s#^\([[:space:]]*linuxefi\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f} + sed -i -e "s#^\([[:space:]]*linux\>.*${param}\)=[^[:space:]]*#\1=${value}#" "${f}" if [ $? -ne 0 ]; then - log_error "Failed to update parameter ($param)" - exit 1 + elog "Failed to update parameter ($param)" fi else # Parameter doesn't exist. Add it to the cmdline - sed -i -e "s|^\([[:space:]]*linuxefi\>.*\)|\1 ${param}=${value}|" ${f} + sed -i -e "s|^\([[:space:]]*linux\>.*\)|\1 ${param}=${value}|" "${f}" if [ $? -ne 0 ]; then - log_error "Failed to add parameter ($param)" - exit 1 + elog "Failed to add parameter ($param)" fi fi done diff --git a/utilities/platform-util/scripts/update-iso-centos.sh b/utilities/platform-util/scripts/update-iso-centos.sh new file mode 100755 index 00000000..76bae631 --- /dev/null +++ b/utilities/platform-util/scripts/update-iso-centos.sh @@ -0,0 +1,310 @@ +#!/bin/bash +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Utility for updating an ISO +# +# This utility supports the following: +# 1. Provide a custom kickstart post addon, allowing the user +# to add some custom configuration, such as custom network +# interface config +# 2. Add or modify installation boot parameters, such as changing +# the default boot_device and rootfs_device disks +# + +# Source shared utility functions +source $(dirname $0)/stx-iso-utils.sh + +function log_error { + echo "$@" >&2 +} + +function usage { + cat < -o + [ -a ] [ -p param=value ] + [ -d ] [ -t ] + -i : Specify input ISO file + -o : Specify output ISO file + -a : Specify ks-addon.cfg file + -p : Specify boot parameter + Examples: + -p rootfs_device=nvme0n1 -p boot_device=nvme0n1 + + -p rootfs_device=/dev/disk/by-path/pci-0000:00:0d.0-ata-1.0 + -p boot_device=/dev/disk/by-path/pci-0000:00:0d.0-ata-1.0 + + -d : + Specify default boot menu option: + 0 - Standard Controller, Serial Console + 1 - Standard Controller, Graphical Console + 2 - AIO, Serial Console + 3 - AIO, Graphical Console + 4 - AIO Low-latency, Serial Console + 5 - AIO Low-latency, Graphical Console + NULL - Clear default selection + -t : + Specify boot menu timeout, in seconds + +Example ks-addon.cfg, to define a VLAN on initial OAM interface setup: +#### start ks-addon.cfg +OAM_DEV=enp0s3 +OAM_VLAN=1234 + + cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV +DEVICE=\$OAM_DEV +BOOTPROTO=none +ONBOOT=yes +LINKDELAY=20 +EOF + + cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV.\$OAM_VLAN +DEVICE=\$OAM_DEV.\$OAM_VLAN +BOOTPROTO=dhcp +ONBOOT=yes +VLAN=yes +LINKDELAY=20 +EOF +#### end ks-addon.cfg + +ENDUSAGE +} + +function cleanup { + common_cleanup +} + +function check_requirements { + common_check_requirements +} + +function set_default_label { + local isodir=$1 + + if [ -z "${EFI_MOUNT}" ]; then + mount_efiboot_img ${isodir} + fi + + for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do + if [ "${DEFAULT_LABEL}" = "NULL" ]; then + # Remove default, if set + grep -q '^default' ${f} + if [ $? -eq 0 ]; then + sed -i '/^default/d' ${f} + fi + else + grep -q '^default' ${f} + if [ $? -ne 0 ]; then + cat <> ${f} + +default ${DEFAULT_LABEL} +EOF + else + sed -i "s/^default.*/default ${DEFAULT_LABEL}/" ${f} + fi + fi + done + + for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do + sed -i "s/^default=.*/default=\"${DEFAULT_GRUB_ENTRY}\"/" ${f} + done +} + +function set_timeout { + local isodir=$1 + + if [ -z "${EFI_MOUNT}" ]; then + mount_efiboot_img ${isodir} + fi + + for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do + sed -i "s/^timeout.*/timeout ${TIMEOUT}/" ${f} + done + + for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do + sed -i "s/^timeout=.*/timeout=${GRUB_TIMEOUT}/" ${f} + + grep -q "^ set timeout=" ${f} + if [ $? -eq 0 ]; then + # Submenu timeout is already added. Update the value + sed -i -e "s#^ set timeout=.*# set timeout=${GRUB_TIMEOUT}#" ${f} + if [ $? -ne 0 ]; then + echo "Failed to update grub timeout" + exit 1 + fi + else + # Parameter doesn't exist. Add it to the cmdline + sed -i -e "/^submenu/a \ \ set timeout=${GRUB_TIMEOUT}" ${f} + if [ $? -ne 0 ]; then + echo "Failed to add grub timeout" + exit 1 + fi + fi + done +} + +declare INPUT_ISO= +declare OUTPUT_ISO= +declare ORIG_PWD=$PWD +declare ADDON= +declare -a PARAMS +declare DEFAULT_LABEL= +declare DEFAULT_GRUB_ENTRY= +declare UPDATE_TIMEOUT="no" +declare -i TIMEOUT=0 +declare GRUB_TIMEOUT=-1 + +while getopts "hi:o:a:p:d:t:" opt; do + case $opt in + i) + INPUT_ISO=$OPTARG + ;; + o) + OUTPUT_ISO=$OPTARG + ;; + a) + ADDON=$OPTARG + ;; + p) + PARAMS+=(${OPTARG}) + ;; + d) + DEFAULT_LABEL=${OPTARG} + + case ${DEFAULT_LABEL} in + 0) + DEFAULT_GRUB_ENTRY="standard>serial" + ;; + 1) + DEFAULT_GRUB_ENTRY="standard>graphical" + ;; + 2) + DEFAULT_GRUB_ENTRY="aio>serial" + ;; + 3) + DEFAULT_GRUB_ENTRY="aio>graphical" + ;; + 4) + DEFAULT_GRUB_ENTRY="aio-lowlat>serial" + ;; + 5) + DEFAULT_GRUB_ENTRY="aio-lowlat>graphical" + ;; + 'NULL') + DEFAULT_GRUB_ENTRY=2 + ;; + *) + echo "Invalid default boot menu option: ${DEFAULT_LABEL}" >&2 + usage + exit 1 + ;; + esac + ;; + t) + let -i timeout_arg=${OPTARG} + if [ ${timeout_arg} -gt 0 ]; then + let -i TIMEOUT=${timeout_arg}*10 + GRUB_TIMEOUT=${timeout_arg} + elif [ ${timeout_arg} -eq 0 ]; then + GRUB_TIMEOUT=0.001 + fi + + UPDATE_TIMEOUT="yes" + ;; + *) + usage + exit 1 + ;; + esac +done + +if [ "${DEFAULT_LABEL}" = "NULL" ]; then + # Reset timeouts to default + TIMEOUT=0 + GRUB_TIMEOUT=-1 + UPDATE_TIMEOUT="yes" +fi + +check_requirements + +check_required_param "-i" "${INPUT_ISO}" +check_required_param "-o" "${OUTPUT_ISO}" + +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)) + +trap cleanup EXIT + +BUILDDIR=$(mktemp -d -p $PWD updateiso_build_XXXXXX) +if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then + echo "Failed to create builddir. Aborting..." + exit $rc +fi + +mount_iso ${INPUT_ISO} + +rsync -a ${MNTDIR}/ ${BUILDDIR}/ +rc=$? +if [ $rc -ne 0 ]; then + echo "Call to rsync ISO content. Aborting..." + exit $rc +fi + +unmount_iso + +if [ ${#PARAMS[@]} -gt 0 ]; then + for p in ${PARAMS[@]}; do + param=${p%%=*} # Strip from the first '=' on + value=${p#*=} # Strip to the first '=' + + update_parameter ${BUILDDIR} "${param}" "${value}" + done +fi + +if [ -n "${DEFAULT_LABEL}" ]; then + set_default_label ${BUILDDIR} +fi + +if [ "${UPDATE_TIMEOUT}" = "yes" ]; then + set_timeout ${BUILDDIR} +fi + +if [ -n "${ADDON}" ]; then + \rm -f ${BUILDDIR}/ks-addon.cfg + \cp ${ADDON} ${BUILDDIR}/ks-addon.cfg + if [ $? -ne 0 ]; then + echo "Error: Failed to copy ${ADDON}" + exit 1 + fi +fi + +unmount_efiboot_img + +# 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} + +echo "Updated ISO: ${OUTPUT_ISO}" + diff --git a/utilities/platform-util/scripts/update-iso.sh b/utilities/platform-util/scripts/update-iso.sh index 76bae631..51cd35e3 100755 --- a/utilities/platform-util/scripts/update-iso.sh +++ b/utilities/platform-util/scripts/update-iso.sh @@ -1,41 +1,61 @@ #!/bin/bash # -# Copyright (c) 2019 Wind River Systems, Inc. +# Copyright (c) 2019-2022 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # -# Utility for updating an ISO +############################################################################# +# +# Utility for updating a starlingX Debian ISO +# +# This utility supports the following update options: +# +# 1. Add a custom kickstart post addon script to the root directory +# of the ISO, allowing the user to add some custom configuration, +# such as custom network interface config. # -# This utility supports the following: -# 1. Provide a custom kickstart post addon, allowing the user -# to add some custom configuration, such as custom network -# interface config # 2. Add or modify installation boot parameters, such as changing -# the default boot_device and rootfs_device disks +# the default install storage device. +# Note: Recommend using by-path notation for storage device names. +# Note: Added or modified boot parameters must be delimited by '=' +# For example: = # +# 3. Modify the default USB install type ; Standard Controller or +# either standard or realtime All-In-One graphical or serial modes. +# +# 4. Clear the default USB install type with -d|--default NULL. +# Note: This will clear the default timeout ; set to no timeout. +# +############################################################################# # Source shared utility functions -source $(dirname $0)/stx-iso-utils.sh +source "$(dirname "$0")/stx-iso-utils.sh" -function log_error { - echo "$@" >&2 -} +# add new line before tool output +echo "" function usage { cat < -o - [ -a ] [ -p param=value ] - [ -d ] [ -t ] - -i : Specify input ISO file - -o : Specify output ISO file - -a : Specify ks-addon.cfg file - -p : Specify boot parameter - Examples: - -p rootfs_device=nvme0n1 -p boot_device=nvme0n1 + $(basename "$0") \ +-i|--input '/path/to/input/.iso' + -o|--output '/path/to/output/.iso' + [ -a|--addon '/path/to/.cfg ] + [ -p|--param param=value ] + [ -d|--default ] + [ -t|--timeout ] + [ -v|--verbose ] + [ -h|--help ] - -p rootfs_device=/dev/disk/by-path/pci-0000:00:0d.0-ata-1.0 - -p boot_device=/dev/disk/by-path/pci-0000:00:0d.0-ata-1.0 +Options Descriptions: + + -i : Specify input ISO file + -o : Specify output ISO file + -a : Specify ks-addon.cfg file + -p : Specify boot parameter + + Example: + -p instdev=/dev/disk/by-path/pci-0000:00:0d.0-ata-1.0 -d : Specify default boot menu option: @@ -46,22 +66,30 @@ Usage: 4 - AIO Low-latency, Serial Console 5 - AIO Low-latency, Graphical Console NULL - Clear default selection + -t : Specify boot menu timeout, in seconds -Example ks-addon.cfg, to define a VLAN on initial OAM interface setup: + -v Verbose mode + -h Display this help + +Kickstart Addon Example: + What: Define a VLAN on initial OAM interface setup: + How : Create and pass a file containing the following + kind of code using the -a option. + #### start ks-addon.cfg OAM_DEV=enp0s3 OAM_VLAN=1234 - cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV +cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV DEVICE=\$OAM_DEV BOOTPROTO=none ONBOOT=yes LINKDELAY=20 EOF - cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV.\$OAM_VLAN +cat << EOF > /etc/sysconfig/network-scripts/ifcfg-\$OAM_DEV.\$OAM_VLAN DEVICE=\$OAM_DEV.\$OAM_VLAN BOOTPROTO=dhcp ONBOOT=yes @@ -71,6 +99,7 @@ EOF #### end ks-addon.cfg ENDUSAGE + exit 0 } function cleanup { @@ -82,73 +111,95 @@ function check_requirements { } function set_default_label { - local isodir=$1 + local isodir="$1" + + ilog "updating default menu selection to ${DEFAULT_GRUB_ENTRY}" if [ -z "${EFI_MOUNT}" ]; then - mount_efiboot_img ${isodir} + mount_efiboot_img "${isodir}" fi - for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do + for f in "${isodir}"/isolinux/isolinux.cfg; do if [ "${DEFAULT_LABEL}" = "NULL" ]; then # Remove default, if set - grep -q '^default' ${f} + grep -q '^default' "${f}" if [ $? -eq 0 ]; then - sed -i '/^default/d' ${f} + sed -i '/^default/d' "${f}" fi else - grep -q '^default' ${f} + # Need to increment this value by 1 for the isolinux (BIOS) case. + # This is because LAT starts the isolinux grub menu at 1 rather than 0. + # Doing this avoids a customer visable menu selection numbering change. + DEFAULT_LABEL=$((DEFAULT_LABEL+1)) + grep -q '^default' "${f}" if [ $? -ne 0 ]; then - cat <> ${f} + cat <> "${f}" default ${DEFAULT_LABEL} EOF else - sed -i "s/^default.*/default ${DEFAULT_LABEL}/" ${f} + sed -i "s/^default.*/default ${DEFAULT_LABEL}/" "${f}" + fi + + # The Debian isolinux grub menus from LAT have a 'ontimoeout + # setting that gets defaulted to 1=Controller Install. This + # setting needs to be updated as well. + grep -q '^ontimeout' "${f}" + if [ $? -eq 0 ]; then + ilog "updating ontimeout label to ${DEFAULT_LABEL}" + sed -i "s/^ontimeout.*/ontimeout ${DEFAULT_LABEL}/" "${f}" fi fi done for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do - sed -i "s/^default=.*/default=\"${DEFAULT_GRUB_ENTRY}\"/" ${f} + sed -i "s/^set default=.*/set default=\"${DEFAULT_GRUB_ENTRY}\"/" "${f}" + # Now update the other cases that LAT adds to the grub file that + # will override the above case if not dealt with similarly + sed -i "s/^ set default=.*/ set default=\"${DEFAULT_GRUB_ENTRY}\"/" "${f}" + sed -i "s/^ set default=.*/ set default=\"${DEFAULT_GRUB_ENTRY}\"/" "${f}" + done } function set_timeout { - local isodir=$1 + local isodir="$1" + + ilog "updating default menu timeout to ${GRUB_TIMEOUT} secs" if [ -z "${EFI_MOUNT}" ]; then - mount_efiboot_img ${isodir} + mount_efiboot_img "${isodir}" fi - for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do - sed -i "s/^timeout.*/timeout ${TIMEOUT}/" ${f} + for f in "${isodir}"/isolinux/isolinux.cfg; do + sed -i "s/^TIMEOUT.*/TIMEOUT ${TIMEOUT}/" "${f}" done for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do - sed -i "s/^timeout=.*/timeout=${GRUB_TIMEOUT}/" ${f} + sed -i "s/^set timeout=.*/set timeout=${GRUB_TIMEOUT}/" "${f}" - grep -q "^ set timeout=" ${f} + grep -q "^ set timeout=" "${f}" if [ $? -eq 0 ]; then # Submenu timeout is already added. Update the value - sed -i -e "s#^ set timeout=.*# set timeout=${GRUB_TIMEOUT}#" ${f} + sed -i -e "s#^ set timeout=.*# set timeout=${GRUB_TIMEOUT}#" "${f}" if [ $? -ne 0 ]; then - echo "Failed to update grub timeout" - exit 1 + elog "Failed to update grub timeout" fi else # Parameter doesn't exist. Add it to the cmdline - sed -i -e "/^submenu/a \ \ set timeout=${GRUB_TIMEOUT}" ${f} + sed -i -e "/^submenu/a \ \ set timeout=${GRUB_TIMEOUT}" "${f}" if [ $? -ne 0 ]; then - echo "Failed to add grub timeout" - exit 1 + elog "Failed to add grub timeout" fi fi done } +# print usage when there are no arguements provided +[ "${*}" == "" ] && usage + declare INPUT_ISO= declare OUTPUT_ISO= -declare ORIG_PWD=$PWD declare ADDON= declare -a PARAMS declare DEFAULT_LABEL= @@ -156,27 +207,53 @@ declare DEFAULT_GRUB_ENTRY= declare UPDATE_TIMEOUT="no" declare -i TIMEOUT=0 declare GRUB_TIMEOUT=-1 +declare VERBOSE=false -while getopts "hi:o:a:p:d:t:" opt; do - case $opt in - i) - INPUT_ISO=$OPTARG - ;; - o) - OUTPUT_ISO=$OPTARG - ;; - a) - ADDON=$OPTARG - ;; - p) - PARAMS+=(${OPTARG}) - ;; - d) - DEFAULT_LABEL=${OPTARG} +script=$(basename "$0") +OPTS=$(getopt -o a:d:hi:o:p:t:v \ + --long addon:,default:,help,input:,output:,param:,timeout:,verbose \ + -n "${script}" -- "$@") +if [ $? != 0 ]; then + echo "Failed parsing options." >&2 + usage +fi +eval set -- "$OPTS" +while true; do + [ ${VERBOSE} = true ] && ilog "Parsing Option: $1 $2" + case "$1" in + + -v|--verbose) + VERBOSE=true + shift 1 + ;; + -h|--help) + usage + shift 1 + ;; + -i|--input) + INPUT_ISO="${2}" + shift 2 + ;; + -o|--output) + OUTPUT_ISO="${2}" + rm -rf "${OUTPUT_ISO}" + shift 2 + ;; + -a|--addon) + ADDON="${2}" + shift 2 + ;; + -p|--param) + PARAMS+=( "${2}" ) + shift 2 + ;; + -d|--default) + DEFAULT_LABEL=${2} case ${DEFAULT_LABEL} in 0) DEFAULT_GRUB_ENTRY="standard>serial" + ;; 1) DEFAULT_GRUB_ENTRY="standard>graphical" @@ -194,29 +271,30 @@ while getopts "hi:o:a:p:d:t:" opt; do DEFAULT_GRUB_ENTRY="aio-lowlat>graphical" ;; 'NULL') - DEFAULT_GRUB_ENTRY=2 + DEFAULT_GRUB_ENTRY="standard>serial" ;; *) - echo "Invalid default boot menu option: ${DEFAULT_LABEL}" >&2 - usage - exit 1 + msg_info="Invalid default boot menu option" + msg_help="needs to be value from 0..5 ; see --help screen" + elog "${msg_info}: ${DEFAULT_LABEL} ; ${msg_help}" >&2 ;; esac + shift 2 ;; - t) - let -i timeout_arg=${OPTARG} - if [ ${timeout_arg} -gt 0 ]; then - let -i TIMEOUT=${timeout_arg}*10 + -t|--timeout) + declare -i timeout_arg=${2} + if [ "${timeout_arg}" -gt 0 ]; then + (( TIMEOUT=timeout_arg*10 )) GRUB_TIMEOUT=${timeout_arg} - elif [ ${timeout_arg} -eq 0 ]; then + elif [ "${timeout_arg}" -eq 0 ]; then GRUB_TIMEOUT=0.001 fi UPDATE_TIMEOUT="yes" + shift 2 ;; - *) - usage - exit 1 + --) + break ;; esac done @@ -233,78 +311,89 @@ check_requirements check_required_param "-i" "${INPUT_ISO}" check_required_param "-o" "${OUTPUT_ISO}" -if [ ! -f ${INPUT_ISO} ]; then - echo "Input file does not exist: ${INPUT_ISO}" - exit 1 +if [ ! -f "${INPUT_ISO}" ]; then + elog "Input file does not exist: ${INPUT_ISO}" fi -if [ -f ${OUTPUT_ISO} ]; then - echo "Output file already exists: ${OUTPUT_ISO}" - exit 1 +if [ -f "${OUTPUT_ISO}" ]; then + elog "Output file already exists: ${OUTPUT_ISO}" fi -shift $((OPTIND-1)) - trap cleanup EXIT -BUILDDIR=$(mktemp -d -p $PWD updateiso_build_XXXXXX) -if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then - echo "Failed to create builddir. Aborting..." - exit $rc +BUILDDIR=$(mktemp -d -p "$PWD" updateiso_build_XXXXXX) +if [ -z "${BUILDDIR}" ] || [ ! -d "${BUILDDIR}" ]; then + elog "Failed to create mount temp dir. Aborting..." fi -mount_iso ${INPUT_ISO} +mount_iso "${INPUT_ISO}" -rsync -a ${MNTDIR}/ ${BUILDDIR}/ +ilog "rsync mounted content to ${BUILDDIR}" +rsync -a "${MNTDIR}/" "${BUILDDIR}/" rc=$? -if [ $rc -ne 0 ]; then - echo "Call to rsync ISO content. Aborting..." - exit $rc -fi +[ ${rc} -ne 0 ] && elog "rsync ISO content failed rc=${rc}. Aborting..." unmount_iso if [ ${#PARAMS[@]} -gt 0 ]; then - for p in ${PARAMS[@]}; do + for p in "${PARAMS[@]}"; do param=${p%%=*} # Strip from the first '=' on value=${p#*=} # Strip to the first '=' - update_parameter ${BUILDDIR} "${param}" "${value}" + update_parameter "${BUILDDIR}" "${param}" "${value}" done fi if [ -n "${DEFAULT_LABEL}" ]; then - set_default_label ${BUILDDIR} + set_default_label "${BUILDDIR}" fi if [ "${UPDATE_TIMEOUT}" = "yes" ]; then - set_timeout ${BUILDDIR} + set_timeout "${BUILDDIR}" fi +# TODO: Remove before merge +# cp "${BUILDDIR}"/EFI/BOOT/grub.cfg /localdisk/$(basename "$0")_iso_grub.cfg +# cp "${BUILDDIR}"/isolinux/isolinux.cfg /localdisk/$(basename "$0")_isolinux.cfg +# if [ -n "${EFI_MOUNT}" ] ; then +# cp "${EFI_MOUNT}"/EFI/BOOT/grub.cfg /localdisk/$(basename "$0")_efi_grub.cfg +# fi + if [ -n "${ADDON}" ]; then - \rm -f ${BUILDDIR}/ks-addon.cfg - \cp ${ADDON} ${BUILDDIR}/ks-addon.cfg + ilog "adding ${ADDON} to ${BUILDDIR}/ks-addon.cfg" + \rm -f "${BUILDDIR}"/ks-addon.cfg + \cp "${ADDON}" "${BUILDDIR}"/ks-addon.cfg if [ $? -ne 0 ]; then - echo "Error: Failed to copy ${ADDON}" - exit 1 + elog "Failed to copy ${ADDON}" fi fi unmount_efiboot_img -# 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} +ilog "making iso filesystem with mkisofs in ${OUTPUT_ISO}" +mkisofs -o "${OUTPUT_ISO}" \ + -A 'instboot' -V 'instboot' \ + -quiet -U -J -joliet-long -r -iso-level 2 \ + -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot \ + -boot-load-size 4 -boot-info-table \ + -eltorito-alt-boot -e efi.img -no-emul-boot \ + "${BUILDDIR}" -isohybrid --uefi ${OUTPUT_ISO} -implantisomd5 ${OUTPUT_ISO} - -echo "Updated ISO: ${OUTPUT_ISO}" +if [ -e "${OUTPUT_ISO}" ] ; then + if [ "${VERBOSE}" = true ] ; then + isohybrid --uefi "${OUTPUT_ISO}" + else + isohybrid --uefi "${OUTPUT_ISO}" >&/dev/null + fi + if [ "${VERBOSE}" = true ] ; then + implantisomd5 "${OUTPUT_ISO}" + else + implantisomd5 "${OUTPUT_ISO}" >&/dev/null + fi + rc=$? + ilog "updated ISO: ${OUTPUT_ISO}" + exit ${rc} +else + elog "the ${OUTPUT_ISO} file was not created" +fi