#!/bin/bash COLOR_RESET="\033[0m" COLOR_BLACK_B="\033[1;30m" COLOR_RED="\033[0;31m" COLOR_RED_B="\033[1;31m" COLOR_GREEN="\033[0;32m" COLOR_GREEN_B="\033[1;32m" COLOR_YELLOW="\033[0;33m" COLOR_YELLOW_B="\033[1;33m" COLOR_BLUE="\033[0;34m" COLOR_BLUE_B="\033[1;34m" COLOR_MAGENTA="\033[0;35m" COLOR_MAGENTA_B="\033[1;35m" COLOR_CYAN="\033[0;36m" COLOR_CYAN_B="\033[1;36m" readlink /proc/$$/exe | grep -q bash || error "You MUST execute this with Bash!" safesync(){ sync sleep 0.2 } log() { printf "%b\n" "${COLOR_BLUE_B}Info: $*${COLOR_RESET}" } cleanup(){ suppress umount "$ROOT_MNT" rm -rf "$ROOT_MNT" suppress umount "$STATE_MNT" rm -rf "$STATE_MNT" suppress umount -R "$LOOPDEV"* losetup -d "$LOOPDEV" losetup -D #in case of cmd above failing } error(){ printf "${COLOR_RED_B}ERR: %b${COLOR_RESET}\n" "$*" >&2 || : printf "${COLOR_RED}Exiting... ${COLOR_RESET}\n" >&2 || : exit 1 } suppress() { if [ "${FLAGS_debug:-0}" = "${FLAGS_TRUE:-1}" ]; then "$@" else "$@" &>/dev/null fi } get_sector_size() { "$SFDISK" -l "$1" | grep "Sector size" | awk '{print $4}' } get_final_sector() { "$SFDISK" -l -o end "$1" | grep "^\s*[0-9]" | awk '{print $1}' | sort -nr | head -n 1 } is_ext2() { local rootfs="$1" local offset="${2-0}" local sb_magic_offset=$((0x438)) local sb_value=$(dd if="$rootfs" skip=$((offset + sb_magic_offset)) \ count=2 bs=1 2>/dev/null) local expected_sb_value=$(printf '\123\357') if [ "$sb_value" = "$expected_sb_value" ]; then return 0 fi return 1 } enable_rw_mount() { local rootfs="$1" local offset="${2-0}" if ! is_ext2 "$rootfs" $offset; then echo "enable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 return 1 fi local ro_compat_offset=$((0x464 + 3)) printf '\000' | dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ conv=notrunc count=1 bs=1 2>/dev/null } disable_rw_mount() { local rootfs="$1" local offset="${2-0}" if ! is_ext2 "$rootfs" $offset; then echo "disable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 return 1 fi local ro_compat_offset=$((0x464 + 3)) printf '\377' | dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ conv=notrunc count=1 bs=1 2>/dev/null } shrink_partitions() { local shim="$1" fdisk "$shim" <&1 | sed 's/\a//g' } format_bytes() { numfmt --to=iec-i --suffix=B "$@" } create_stateful(){ log "Creating KVS/Stateful Partition" local final_sector=$(get_final_sector "$LOOPDEV") local sector_size=$(get_sector_size "$LOOPDEV") "$CGPT" add "$LOOPDEV" -i 1 -b $((final_sector + 1)) -s $((STATE_SIZE / sector_size)) -t data partx -u -n 1 "$LOOPDEV" suppress mkfs.ext4 -F -L KVS "$LOOPDEV"p1 safesync } inject_stateful(){ log "Injecting KVS/Stateful Partition" echo "Mounting stateful.." mount "$LOOPDEV"p1 "$STATE_MNT" echo "Copying files.." mkdir -p "${STATE_MNT}/dev_image/etc" touch "${STATE_MNT}/dev_image/etc/lsb-factory" umount "$STATE_MNT" } shrink_root() { log "Shrinking ROOT-A Partition" enable_rw_mount "${LOOPDEV}p3" suppress e2fsck -fy "${LOOPDEV}p3" suppress resize2fs -M "${LOOPDEV}p3" disable_rw_mount "${LOOPDEV}p3" local sector_size=$(get_sector_size "$LOOPDEV") local block_size=$(tune2fs -l "${LOOPDEV}p3" | grep "Block size" | awk '{print $3}') local block_count=$(tune2fs -l "${LOOPDEV}p3" | grep "Block count" | awk '{print $3}') local original_sectors=$("$CGPT" show -i 3 -s -n -q "$LOOPDEV") local original_bytes=$((original_sectors * sector_size)) local resized_bytes=$((block_count * block_size)) local resized_sectors=$((resized_bytes / sector_size)) echo "Resizing ROOT from $(format_bytes ${original_bytes}) to $(format_bytes ${resized_bytes})" "$CGPT" add -i 3 -s "$resized_sectors" "$LOOPDEV" partx -u -n 3 "$LOOPDEV" } detect_arch() { MNT_ROOT=$(mktemp -d) mount -o ro "${LOOPDEV}p3" "$MNT_ROOT" TARGET_ARCH=x86_64 if [ -f "$MNT_ROOT/bin/bash" ]; then case "$(file -b "$MNT_ROOT/bin/bash" | awk -F ', ' '{print $2}' | tr '[:upper:]' '[:lower:]')" in # for now assume arm has aarch64 kernel # this only assumes since theres no armv7 (arm32) shims leaked *aarch64* | *armv8* | *arm*) TARGET_ARCH=aarch64 ;; esac fi echo "Detected architecture: $TARGET_ARCH" umount "$MNT_ROOT" rmdir "$MNT_ROOT" } inject_root(){ log "Injecting ROOT-A Partition" detect_arch echo "Mounting root.." suppress enable_rw_mount "$LOOPDEV"p3 suppress mount "$LOOPDEV"p3 "$ROOT_MNT" echo "Copying files.." cp -r "$SCRIPT_DIR/../build/$TARGET_ARCH/." "$ROOT_MNT" suppress cp -r "$SCRIPT_DIR/root/factory_install.sh" "$ROOT_MNT/usr/sbin/factory_install.sh" mkdir -p "$ROOT_MNT"/opt/kvs/bin mv "$ROOT_MNT"/bin/is_ti50 "$ROOT_MNT"/opt/kvs/bin/is_ti50 echo 'export PATH=$PATH:/opt/kvs/bin' >> "$ROOT_MNT"/root/.bashrc echo "Removing tcsd & trunksd.." rm -rf "$ROOT_MNT"/etc/init/tcsd.conf rm -rf "$ROOT_MNT"/etc/init/trunksd.conf echo "$(date +'%m-%d-%Y %I:%M%p %Z')" > "$ROOT_MNT"/DATE_COMPILED suppress umount "$ROOT_MNT" } get_parts_physical_order() { local part_table=$("$CGPT" show -q "$1") local physical_parts=$(awk '{print $1}' <<<"$part_table" | sort -n) for part in $physical_parts; do grep "^\s*${part}\s" <<<"$part_table" | awk '{print $3}' done } squash_partitions() { log "Squashing partitions" for part in $(get_parts_physical_order "$1"); do echo "Squashing ${1}p${part}" suppress "$SFDISK" -N "$part" --move-data "$1" <<<"+,-" || : done } umount_all(){ suppress umount -R "$LOOPDEV"* }