Skip to main content

Installing the Remote Reimage Utility

Installing the Remote Reimage Utility

Now that we have our reimage utility, we need a way to install it on our target computer(s). The solution to this problem boils down to these objectives:

  • Shrink the root filesystem
  • Shrink the root partition
  • Format the extra space for our recovery partition
  • Unpack the reimage utility to the recovery partition
  • Activate the recovery partition for the next boot cycle and reboot the computer

That sounds like a lot, right? Fortunately, we have a script that will handle all of these objectives.

install-ukit.sh (click to expand)
#! /bin/bash
  
## This script shrinks the filesystem and OS partition to make room for a recovery partition
## Recovery partition contains a modified copy of HP's thinstate/ukit utility
## The script will automatically add a boot option for ukit and mark it as active for the next boot cycle
## Author: Newb
  
#### Define Variables ####
blk_dev=$(lsblk -lf | sort | sed '/boot/d' | grep -i btrfs -B 1 | head -n 1) # <-- System disk
reimage_folder=/reimage-files # <-- HPDM will dump upgrade files here
md5sum=$(ls $reimage_folder | grep ukit.md5) # <-- Checksum for ukit.tar
part_two_end="" # <-- Defined in shrink_thinpro function
ukit_part="" # <-- Defined in unmount_and_format_ukit function
boot_order="" # <-- Defined in adjust_boot_order function
new_boot_order="" # <-- Defined in adjust_boot_order function
ukit_bootnum="" # <-- Defined in adjust_boot_order function
  
#### Define Echo Colors ####
red='\033[0;31m'; green='\033[0;32m'; yellow='\033[0;33m'
blue='\033[1;34m'; white='\033[1;37m'
nc='\033[0m' # <-- No color
  
#### Define Functions ####
verify_files() # Confirm tarball matches the provided checksum
{
    cd $reimage_folder
    echo -ne "[ INFO ] Verifying files \r"
    if md5sum -c --quiet $md5sum
    then
        echo -e "${green}[    OK    ]${nc} Verifying files"
    else
        echo -e "${red}[FAILED]${nc} Verifying files"
        echo -e "${red}Aborting installation${nc}"
        exit
    fi
}
  
reset_disk() # Clean up any previous reimage attempts
{
    echo -ne "[ INFO ] Removing previous ukit partition \r"
    parted ---pretend-input-tty /dev/$blk_dev rm 3 yes ignore > /dev/null 2>&1 &&
    echo -e "${green}[    OK    ]${nc} Removing previous ukit partition"    ||
    echo -e "${red}[FAILED]${nc} Removing previous ukit partition"
    echo -ne "[ INFO ] Expanding root partition \r"
    parted ---pretend-input-tty -a optimal /dev/$blk_dev resizepart 2 yes 100% > /dev/null 2>&1 &&
    echo -e "${green}[    OK    ]${nc} Expanding root partition" ||
    echo -e "${red}[FAILED]${nc} Expanding root partition"
    echo -ne "[ INFO ] Expanding root filesystem \r"
    btrfs filesystem resize max /root > /dev/null &&
    echo -e "${green}[    OK    ]${nc} Expanding root filesystem" ||
    echo -e "${red}[FAILED]${nc} Expanding root filesystem"
}
  
shrink_thinpro() # Make room for recovery partition
{
# It is worth noting that the btrfs filesystem shrink uses GiB while parted is using GB
# This leaves some extra space at the end of the root partition
# The gap at the end does not cause any trouble and the disk is getting completely overwritten anyway
    echo -ne "[ INFO ] Shrinking root filesystem \r"
    btrfs filesystem resize -2G /root >/dev/null &&
    echo -e "${green}[    OK    ]${nc} Shrinking root filesystem" ||
    echo -e "${red}[FAILED]${nc} Shrinking root filesystem"
    echo -ne "[ INFO ] Shrinking root partition \r"
    part_two_end=$(parted /dev/$blk_dev unit GB print | grep -i btrfs | cut -d " " -f 10 | tr -d [:alpha:])
    part_two_end=$(echo "scale=1; $part_two_end - 2" | bc)
    parted ---pretend-input-tty /dev/$blk_dev resizepart 2 yes $part_two_end"GB" yes 2> /dev/null &&
    echo -e "${green}[    OK    ]${nc} Shrinking root partition" ||
    echo -e "${red}[FAILED]${nc} Shrinking root partition"
}
  
create_ukit_partition() # Create recovery partition where ukit will live
{
    echo -ne "[ INFO ] Creating ukit partition \r"
    parted ---pretend-input-tty -a optimal /dev/$blk_dev mkpart primary $part_two_end"GB" 100% 2> /dev/null &&
    echo -e "${green}[    OK    ]${nc} Creating ukit partition" ||
    echo -e "${red}[FAILED]${nc} Creating ukit partition"
}
  
unmount_and_format_ukit() # Format partition with FAT32
{
    echo -ne "[ INFO ] Formatting ukit partition \r"
    ukit_part=$(lsblk -l | grep $blk_dev | cut -d " " -f 1 | grep 3)
    umount /dev/$ukit_part 2> /dev/null > /dev/null 2>&1 # <-- Need to unmount before formatting because of residual filesystem structures from any previous attempts
    mkfs.vfat -F32 /dev/$ukit_part > /dev/null &&
    echo -e "${green}[    OK    ]${nc} Formatting ukit partition" ||
    echo -e "${red}[FAILED]${nc} Formatting ukit partition"
}
  
unpack_ukit() # Unpack ukit.tar to the newly formatted partition
{
    echo -ne "[ INFO ] Mounting ukit partition and unpacking files \r"
    mkdir /tmp/ukit/ 2> /dev/null # <-- Kick error output to null in case the folder already exists
    mount /dev/$ukit_part /tmp/ukit/ &&
    cd /tmp/ukit/
    tar xfz /$reimage_folder/*ukit.tar > /dev/null 2>&1 &&
    echo -e "${green}[    OK    ]${nc} Mounting ukit partition and unpacking files" ||
    echo -e "${red}[FAILED]${nc} Mounting ukit partition and unpacking files"
}
  
adjust_boot_order() # Adjust EFI boot order for only the next boot cycle
{
    echo -e "${blue}Activating ukit partition for next boot${nc}"
    ukit_bootnum=$(efibootmgr | grep -i ukit)
    if [[ -n $ukit_bootnum ]]
    then
        echo -ne "[ INFO ] Removing previous boot entry \r"
        efibootmgr -B -b $(echo $ukit_bootnum | tr -dC [:digit:]) > /dev/null && # <-- ThinPro 7.2 doesn't like reusing previous boot entries, so we remove it
        echo -e "${green}[    OK    ]${nc} Removing previous boot entry" ||
        echo -e "${red}[FAILED]${nc} Removing previous boot entry"
        echo -ne "[ INFO ] Creating new ukit boot entry \r"
        efibootmgr -c -d /dev/$blk_dev -p 3 -L "ukit" -l "\EFI\BOOT\BOOTX64.EFI" > /dev/null 2>&1 &&
        boot_order=$(efibootmgr | grep -i bootorder | cut -d " " -f 2 | cut -d "," -f 1-50)
        new_boot_order=${boot_order:5:50},${boot_order:0:4}
        efibootmgr -o $new_boot_order > /dev/null 2>&1 &&
        efibootmgr -n 0000 > /dev/null 2>&1 &&
        echo -e "${green}[    OK    ]${nc} Creating new ukit boot entry" ||
        echo -e "${red}[FAILED]${nc} Creating new ukit boot entry"
    else
        echo -ne "[ INFO ] Creating new ukit boot entry \r"
        efibootmgr -c -d /dev/$blk_dev -p 3 -L "ukit" -l "\EFI\BOOT\BOOTX64.EFI" > /dev/null 2>&1 &&
        boot_order=$(efibootmgr | grep -i bootorder | cut -d " " -f 2 | cut -d "," -f 1-50)
        new_boot_order=${boot_order:5:50},${boot_order:0:4}
        efibootmgr -o $new_boot_order > /dev/null 2>&1 &&
        efibootmgr -n 0000 > /dev/null 2>&1 &&
        echo -e "${green}[    OK    ]${nc} Creating new ukit boot entry" ||
        echo -e "${red}[FAILED]${nc} Creating new ukit boot entry"
    fi
}
  
#### Run Script ####
if [[ $(lsblk -lf | sort | sed '/boot/d' | grep $blk_dev | wc -l) -lt 3 ]]
then
    echo -e "${blue}Installing ukit${nc}"
    verify_files
    shrink_thinpro
    create_ukit_partition
    unmount_and_format_ukit
    unpack_ukit
    adjust_boot_order
else
    echo -e "${blue}Cleaning up previous upgrade attempt${nc}"
    unmount_and_format_ukit
    reset_disk
    echo -e "${blue}Installing ukit${nc}"
    verify_files
    shrink_thinpro
    create_ukit_partition
    unmount_and_format_ukit
    unpack_ukit
    adjust_boot_order
fi

As always, you should read through the script to get a handle on its basic function and flow. There are plenty of comments to help you along your way. There is also a lot of color output to aid with testing and troubleshooting, but you won't really see that from HPDM during deployment.

For the sake of completeness, it is worth discussing why this works, and the reason for that is BTRFS. This is the filesystem that ThinPro uses, and it allows you to shrink a live filesystem that is currently in use! Without that functionality, this process would be much more difficult.

The other big element worth calling out is efibootmgr. This is a command which allows you to manipulate the boot order from a running OS. The best part is that we can temporarily mark a partition as active for the next boot only, so if the reimage utility fails, the computer will be returned to it's normal running state.