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.
No comments to display
No comments to display