[meta-intel] [PATCHv3 4/6] EFI installer: deploy board-specific data and kernel cmdline

Jianxun Zhang jianxun.zhang at linux.intel.com
Thu Jul 21 16:56:13 PDT 2016


> On Jul 21, 2016, at 4:21 PM, Tom Zanussi <tom.zanussi at linux.intel.com> wrote:
> 
> 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..
The installer is a copy from OE but modified for RMC. Diff this file and OE’s will show you the delta for RMC.

I don’t have a better way so far to just have a fragment of this script in meta-intel based on OE’s. Yes, ideally,
we don’t need to carry this bit if RMC is in OE. But it looks strange to submit this RMC delta to OE without
other pieces now. I can try to change this file into a patch, but I don’t know if it can work.

We should pursue upstreaming it into OE although my initial thought is taking meta-intel as RMC’s home.

V4 just merged latest OE version, BTW.




> 
> 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