[meta-intel] [PATCHv3 4/6] EFI installer: deploy board-specific data and kernel cmdline
Tom Zanussi
tom.zanussi at linux.intel.com
Thu Jul 21 16:21:18 PDT 2016
On 07/21/2016 03:37 AM, Jianxun Zhang wrote:
> Extend the existing init-install-efi.sh in OE to call RMC tool
> so that it can deploy file blobs and a global kernel cmdline
> fragment associated to the type of current running board.
>
> At first, it tries to retrieve a special configuration file
> INSTALLER.CONFIG associated to the board from RMC database file
> on ESP.
>
> If the config file is fetched successfully, installer parses
> configuration file to know which file blobs should be deployed
> from database to target, also with other necessary information
> like FS attributes of deployed file.
>
> If a rule in config file is to create a directory, installer
> creates it accordingly. Developer must direct installer to create
> new directory first if destination of a file is in that directory
> by adding a '/' at the end of a line.
>
> The below is an example of INSTALLER.CONFIG. It directs installer to
> deploy a boot entry boot.conf to EFI partition, create a
> directory /etc/mylib/ on target's rootfs, and deploy a config
> file mylib.conf in the created directory. The first several lines
> started with '#' are comment.
>
> efi_entry_dir:root:disk:770:/boot/loader/entries/
> boot.conf:root:disk:770:/boot/loader/entries/rmcboot.conf
> mylibdir:root:root:770:/tgt_root/etc/mylib/
> mylib.conf:root:root:660:/tgt_root/etc/mylib/mylib.conf
>
> When installer cannot get config file for the type of running board,
> it skips any board-specific deployment. If a command fails for a file,
> installer simply move to the next file.
>
> After all the boot entries are deployed, installer seeks a config file
> KBOOTPARAM from RMC database file. In success, it appends the content
> of KBOOTPARAM to the end of kernel command line of every deployed
> entry. KBOOTPARAM works as a global kernel command line fragment
> specific to the type of running board.
>
> The installer is a copy of EFI installer script in OE meta:
> ./recipes-core/initrdscripts/files/init-install-efi.sh
> (1f2a01b02e9e175cad4cf05b3ff7430bba232eb6)
>
It seems like this is the wrong way to go - to have another copy of the
same exact file, which is quite large, somewhere else in the system.
Besides the obvious duplication, what happens when bugs are found in one
- is this going to track all patches to the original?
I suppose that since having rmc in meta-intel is just a stopover to
oe-core, it's a temporary situation, but even still, it would be nice if
it would be possible to make and submit changes to the original (I guess
when rmc is in oe-core, it will need them anyway) and use them from rmc
in meta-intel..
Tom
> Signed-off-by: Jianxun Zhang <jianxun.zhang at linux.intel.com>
> ---
> .../initrdscripts/files/init-install-efi.sh | 315 +++++++++++++++++++++
> .../initramfs-live-install-efi_%.bbappend | 1 +
> 2 files changed, 316 insertions(+)
> create mode 100644 common/recipes-core/initrdscripts/files/init-install-efi.sh
> create mode 100644 common/recipes-core/initrdscripts/initramfs-live-install-efi_%.bbappend
>
> diff --git a/common/recipes-core/initrdscripts/files/init-install-efi.sh b/common/recipes-core/initrdscripts/files/init-install-efi.sh
> new file mode 100644
> index 0000000..ec685d3
> --- /dev/null
> +++ b/common/recipes-core/initrdscripts/files/init-install-efi.sh
> @@ -0,0 +1,315 @@
> +#!/bin/sh -e
> +#
> +# Copyright (c) 2016, Intel Corporation.
> +# All rights reserved.
> +#
> +# install.sh [device_name] [rootfs_name]
> +#
> +# This file is a copy of file with same name in OE:
> +# meta/recipes-core/initrdscripts/files/. We modify
> +# it for RMC feature to deploy file blobs from RMC
> +# database file to target.
> +
> +PATH=/sbin:/bin:/usr/sbin:/usr/bin
> +
> +# We need 20 Mb for the boot partition
> +boot_size=20
> +
> +# 5% for swap
> +swap_ratio=5
> +
> +# Get a list of hard drives
> +hdnamelist=""
> +live_dev_name=`cat /proc/mounts | grep ${1%/} | awk '{print $1}'`
> +live_dev_name=${live_dev_name#\/dev/}
> +# Only strip the digit identifier if the device is not an mmc
> +case $live_dev_name in
> + mmcblk*)
> + ;;
> + *)
> + live_dev_name=${live_dev_name%%[0-9]*}
> + ;;
> +esac
> +
> +echo "Searching for hard drives ..."
> +
> +for device in `ls /sys/block/`; do
> + case $device in
> + loop*)
> + # skip loop device
> + ;;
> + sr*)
> + # skip CDROM device
> + ;;
> + ram*)
> + # skip ram device
> + ;;
> + *)
> + # skip the device LiveOS is on
> + # Add valid hard drive name to the list
> + case $device in
> + $live_dev_name*)
> + # skip the device we are running from
> + ;;
> + *)
> + hdnamelist="$hdnamelist $device"
> + ;;
> + esac
> + ;;
> + esac
> +done
> +
> +if [ -z "${hdnamelist}" ]; then
> + echo "You need another device (besides the live device /dev/${live_dev_name}) to install the image. Installation aborted."
> + exit 1
> +fi
> +
> +TARGET_DEVICE_NAME=""
> +for hdname in $hdnamelist; do
> + # Display found hard drives and their basic info
> + echo "-------------------------------"
> + echo /dev/$hdname
> + if [ -r /sys/block/$hdname/device/vendor ]; then
> + echo -n "VENDOR="
> + cat /sys/block/$hdname/device/vendor
> + fi
> + if [ -r /sys/block/$hdname/device/model ]; then
> + echo -n "MODEL="
> + cat /sys/block/$hdname/device/model
> + fi
> + if [ -r /sys/block/$hdname/device/uevent ]; then
> + echo -n "UEVENT="
> + cat /sys/block/$hdname/device/uevent
> + fi
> + echo
> + # Get user choice
> + while true; do
> + echo -n "Do you want to install this image there? [y/n] "
> + read answer
> + if [ "$answer" = "y" -o "$answer" = "n" ]; then
> + break
> + fi
> + echo "Please answer y or n"
> + done
> + if [ "$answer" = "y" ]; then
> + TARGET_DEVICE_NAME=$hdname
> + break
> + fi
> +done
> +
> +if [ -n "$TARGET_DEVICE_NAME" ]; then
> + echo "Installing image on /dev/$TARGET_DEVICE_NAME ..."
> +else
> + echo "No hard drive selected. Installation aborted."
> + exit 1
> +fi
> +
> +device=/dev/$TARGET_DEVICE_NAME
> +
> +#
> +# The udev automounter can cause pain here, kill it
> +#
> +rm -f /etc/udev/rules.d/automount.rules
> +rm -f /etc/udev/scripts/mount*
> +
> +#
> +# Unmount anything the automounter had mounted
> +#
> +umount ${device}* 2> /dev/null || /bin/true
> +
> +mkdir -p /tmp
> +
> +# Create /etc/mtab if not present
> +if [ ! -e /etc/mtab ]; then
> + cat /proc/mounts > /etc/mtab
> +fi
> +
> +disk_size=$(parted ${device} unit mb print | grep '^Disk .*: .*MB' | cut -d" " -f 3 | sed -e "s/MB//")
> +
> +swap_size=$((disk_size*swap_ratio/100))
> +rootfs_size=$((disk_size-boot_size-swap_size))
> +
> +rootfs_start=$((boot_size))
> +rootfs_end=$((rootfs_start+rootfs_size))
> +swap_start=$((rootfs_end))
> +
> +# MMC devices are special in a couple of ways
> +# 1) they use a partition prefix character 'p'
> +# 2) they are detected asynchronously (need rootwait)
> +rootwait=""
> +part_prefix=""
> +if [ ! "${device#/dev/mmcblk}" = "${device}" ]; then
> + part_prefix="p"
> + rootwait="rootwait"
> +fi
> +bootfs=${device}${part_prefix}1
> +rootfs=${device}${part_prefix}2
> +swap=${device}${part_prefix}3
> +
> +echo "*****************"
> +echo "Boot partition size: $boot_size MB ($bootfs)"
> +echo "Rootfs partition size: $rootfs_size MB ($rootfs)"
> +echo "Swap partition size: $swap_size MB ($swap)"
> +echo "*****************"
> +echo "Deleting partition table on ${device} ..."
> +dd if=/dev/zero of=${device} bs=512 count=35
> +
> +echo "Creating new partition table on ${device} ..."
> +parted ${device} mklabel gpt
> +
> +echo "Creating boot partition on $bootfs"
> +parted ${device} mkpart boot fat32 0% $boot_size
> +parted ${device} set 1 boot on
> +
> +echo "Creating rootfs partition on $rootfs"
> +parted ${device} mkpart root ext3 $rootfs_start $rootfs_end
> +
> +echo "Creating swap partition on $swap"
> +parted ${device} mkpart swap linux-swap $swap_start 100%
> +
> +parted ${device} print
> +
> +echo "Formatting $bootfs to vfat..."
> +mkfs.vfat $bootfs
> +
> +echo "Formatting $rootfs to ext3..."
> +mkfs.ext3 $rootfs
> +
> +echo "Formatting swap partition...($swap)"
> +mkswap $swap
> +
> +mkdir /tgt_root
> +mkdir /src_root
> +mkdir -p /boot
> +
> +# Handling of the target root partition
> +mount $rootfs /tgt_root
> +mount -o rw,loop,noatime,nodiratime /run/media/$1/$2 /src_root
> +echo "Copying rootfs files..."
> +cp -a /src_root/* /tgt_root
> +if [ -d /tgt_root/etc/ ] ; then
> + boot_uuid=$(blkid -o value -s UUID ${bootfs})
> + swap_part_uuid=$(blkid -o value -s PARTUUID ${swap})
> + echo "/dev/disk/by-partuuid/$swap_part_uuid swap swap defaults 0 0" >> /tgt_root/etc/fstab
> + echo "UUID=$boot_uuid /boot vfat defaults 1 2" >> /tgt_root/etc/fstab
> + # We dont want udev to mount our root device while we're booting...
> + if [ -d /tgt_root/etc/udev/ ] ; then
> + echo "${device}" >> /tgt_root/etc/udev/mount.blacklist
> + fi
> +fi
> +
> +# Handling of the target boot partition
> +mount $bootfs /boot
> +echo "Preparing boot partition..."
> +
> +# RMC deployment
> +RMC_CMD=/src_root/usr/bin/rmc
> +RMC_DB=/run/media/$1/rmc.db
> +
> +# We don't want to quit when there is an operation failed. For example,
> +# a file system could not support some operations.
> +set +e
> +
> +if [ -f "${RMC_DB}" ] && [ -f "${RMC_CMD}" ]; then
> + echo "Found RMC database and tool, start RMC deployment"
> + # query INSTALLER.CONFIG from RMC DB
> + if ${RMC_CMD} -B INSTALLER.CONFIG -d "${RMC_DB}" -o /tmp/installer.config; then
> + while IFS=':' read -r NAME TGT_UID TGT_GID TGT_MODE TGT_PATH; do
> + # skip comment
> + # The regexp in grep works with busybox grep which doesn't
> + # seem to have a -P to recognize '\t'. But this expression could not
> + # work with gnu grep...
> + if echo "$NAME"|grep -q $'^[ \t]*#'; then
> + continue
> + fi
> + # check if we should create a directory (last char in target path is '/')
> + # or deploy a file
> + LAST_CHAR=$(echo "${TGT_PATH:$((${#TGT_PATH}-1)):1}")
> +
> + # Do not bail out for failures but user should get stderr message
> + if [ ${LAST_CHAR} = "/" ]; then
> + # name field is skipped for directory
> + echo "DIR: ${TGT_UID}:${TGT_GID}:${TGT_MODE} => ${TGT_PATH}"
> + mkdir -p "$TGT_PATH"
> + chown "${TGT_UID}:${TGT_GID}" "$TGT_PATH"
> + chmod "${TGT_MODE}" "$TGT_PATH"
> + else
> + ${RMC_CMD} -B "${NAME}" -d "${RMC_DB}" -o "${TGT_PATH}"
> + echo "FILE: ${NAME}:${TGT_UID}:${TGT_GID}:${TGT_MODE} => ${TGT_PATH}"
> + chown "${TGT_UID}:${TGT_GID}" "$TGT_PATH"
> + chmod "${TGT_MODE}" "$TGT_PATH"
> + fi
> + done < /tmp/installer.config
> + rm -rf /tmp/installer.config
> +
> + # remove rmc from target since we don't think it is a valid
> + # case to run rmc after installation.
> + rm -rf /tgt_root/usr/bin/rmc
> + echo "RMC deployment finished"
> + else
> + echo "INSTALLER.CONFIG is not found, skip RMC deployment"
> + fi
> +fi
> +set -e
> +
> +EFIDIR="/boot/EFI/BOOT"
> +mkdir -p $EFIDIR
> +# Copy the efi loader
> +cp /run/media/$1/EFI/BOOT/*.efi $EFIDIR
> +
> +if [ -f /run/media/$1/EFI/BOOT/grub.cfg ]; then
> + root_part_uuid=$(blkid -o value -s PARTUUID ${rootfs})
> + GRUBCFG="$EFIDIR/grub.cfg"
> + cp /run/media/$1/EFI/BOOT/grub.cfg $GRUBCFG
> + # Update grub config for the installed image
> + # Delete the install entry
> + sed -i "/menuentry 'install'/,/^}/d" $GRUBCFG
> + # Delete the initrd lines
> + sed -i "/initrd /d" $GRUBCFG
> + # Delete any LABEL= strings
> + sed -i "s/ LABEL=[^ ]*/ /" $GRUBCFG
> + # Delete any root= strings
> + sed -i "s/ root=[^ ]*/ /g" $GRUBCFG
> + # Add the root= and other standard boot options
> + sed -i "s at linux /vmlinuz *@linux /vmlinuz root=PARTUUID=$root_part_uuid rw $rootwait quiet @" $GRUBCFG
> +fi
> +
> +if [ -d /run/media/$1/loader ]; then
> + rootuuid=$(blkid -o value -s PARTUUID ${rootfs})
> + GUMMIBOOT_CFGS="/boot/loader/entries/*.conf"
> + # copy config files for gummiboot
> + cp -dr /run/media/$1/loader /boot
> + # delete the install entry
> + # fixme: If RMC did deploy install.conf at previous steps, it is purged here...
> + rm -f /boot/loader/entries/install.conf
> + # delete the initrd lines
> + sed -i "/initrd /d" $GUMMIBOOT_CFGS
> + # delete any LABEL= strings
> + sed -i "s/ LABEL=[^ ]*/ /" $GUMMIBOOT_CFGS
> + # delete any root= strings
> + sed -i "s/ root=[^ ]*/ /" $GUMMIBOOT_CFGS
> + # add the root= and other standard boot options
> + sed -i "s at options *@options root=PARTUUID=$rootuuid rw $rootwait quiet @" $GUMMIBOOT_CFGS
> + # if RMC feature presents, append global kernel command line fragment when it exists.
> + if [ -f "${RMC_DB}" ] && [ -f "${RMC_CMD}" ]; then
> + if ${RMC_CMD} -B KBOOTPARAM -d "${RMC_DB}" -o /tmp/kbootparam; then
> + sed -i "/^[ \t]*options/ s/$/ $(cat /tmp/kbootparam)/" $GUMMIBOOT_CFGS
> + rm /tmp/kbootparam
> + fi
> + fi
> +fi
> +
> +cp /run/media/$1/vmlinuz /boot
> +
> +umount /src_root
> +umount /tgt_root
> +umount /boot
> +
> +sync
> +
> +echo "Remove your installation media, and press ENTER"
> +
> +read enter
> +
> +echo "Rebooting..."
> +reboot -f
> diff --git a/common/recipes-core/initrdscripts/initramfs-live-install-efi_%.bbappend b/common/recipes-core/initrdscripts/initramfs-live-install-efi_%.bbappend
> new file mode 100644
> index 0000000..81fe7b7
> --- /dev/null
> +++ b/common/recipes-core/initrdscripts/initramfs-live-install-efi_%.bbappend
> @@ -0,0 +1 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
>
More information about the meta-intel
mailing list