#!/bin/bash
#
# ChromeOS Automated Partitioning (CRAP)
# https://github.com/chrultrabook/crap
# Copyright (C) 2023 - BinBashBanana
# Contributors add their names here
#
# License pending...
#
# Thanks to the following projects/files for reference:
# https://github.com/MrChromebox/scripts
# https://chromium.googlesource.com/chromiumos/platform2/+/main/chromeos-common-script/share/chromeos-common.sh
# https://github.com/reynhout/chrx/blob/master/chrx-setup-storage
# https://gist.github.com/bendavis78/5929b46efd26232d7e9e
#

set -eE

# variable variables
SCRIPT_DATE="[2024-01-13]"

# optional variables
[ -z "$CRAP_TESTING" ] && CRAP_TESTING=0
[ -z "$CRAP_DEBUG" ] && CRAP_DEBUG=0

# internal variables
COLOR_RESET="\033[0m"
COLOR_BLACK_B="\033[1;30m"
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_B="\033[1;34m"
COLOR_MAGENTA_B="\033[1;35m"
COLOR_CYAN_B="\033[1;36m"

fail() {
	printf "${COLOR_RED_B}%b${COLOR_RESET}\n" "$*" >&2 || :
	exit 1
}

log_debug() {
	[ "$CRAP_DEBUG" -eq 1 ] && printf "%b\n" "$*" >&2 || :
}

suppress() {
	if [ "$CRAP_DEBUG" -eq 1 ]; then
		"$@"
	else
		"$@" &>/dev/null
	fi
}

suppress_out() {
	if [ "$CRAP_DEBUG" -eq 1 ]; then
		"$@"
	else
		"$@" >/dev/null
	fi
}

IS_CROS=0
[ -f /etc/lsb-release ] && grep -q '\(Chrome OS\|Chromium OS\|neverware\)' /etc/lsb-release && IS_CROS=1

readlink /proc/$$/exe | grep -q bash || fail "Please run with bash"
[ "$EUID" -ne 0 ] && fail "Please run as root"
grandparent_pid=$(ps -o ppid= $PPID | tr -d '[:space:]')
[ -n "$grandparent_pid" ] && readlink /proc/$grandparent_pid/exe | grep -q crosh && fail "Please run from a VT, not from crosh. Press [ Ctrl ] [ Alt ] [ -> ] (F2) to switch to VT2."

format_bytes() {
	numfmt --to=iec-i --suffix=B "$@"
}

check_deps() {
	for dep in "$@"; do
		command -v "$dep" &>/dev/null || echo "$dep"
	done
}

missing_deps=$(check_deps sfdisk cgpt partx blockdev e2fsck resize2fs)
[ -n "$missing_deps" ] && fail "The following required commands weren't found in PATH:\n${missing_deps}"

get_largest_blockdev() {
	local largest size dev_name tmp_size remo
	size=0
	for blockdev in /sys/block/*; do
		dev_name="${blockdev##*/}"
		echo "$dev_name" | grep -q '^\(loop\|ram\)' && continue
		tmp_size=$(cat "$blockdev"/size)
		remo=$(cat "$blockdev"/removable)
		if [ "$tmp_size" -gt "$size" ] && [ "${remo:-0}" -eq 0 ]; then
			largest="/dev/$dev_name"
			size="$tmp_size"
		fi
	done
	echo "$largest"
}

get_largest_cros_blockdev() {
	local largest size dev_name tmp_size remo
	size=0
	for blockdev in /sys/block/*; do
		dev_name="${blockdev##*/}"
		echo "$dev_name" | grep -q '^\(loop\|ram\)' && continue
		tmp_size=$(cat "$blockdev"/size)
		remo=$(cat "$blockdev"/removable)
		if [ "$tmp_size" -gt "$size" ] && [ "${remo:-0}" -eq 0 ]; then
			case "$(sfdisk -l -o name "/dev/$dev_name" 2>/dev/null)" in
				*STATE*KERN-A*ROOT-A*KERN-B*ROOT-B*)
					largest="/dev/$dev_name"
					size="$tmp_size"
					;;
			esac
		fi
	done
	echo "$largest"
}

get_largest_free_space_size() {
	local size
	size=$(sfdisk -F "$1" | grep "^\s*[0-9]" | awk '{if ($2 >= $1) print $3}' | sort -nr | head -n 1)
	echo "${size:-0}"
}

format_part_number() {
	echo -n "$1"
	echo "$1" | grep -q '[0-9]$' && echo -n p
	echo "$2"
}

clear_screen() {
	clear
	echo ""
}

wait_on_enter() {
	echo "Press enter."
	read -res
}

wait_on_enter_menu() {
	echo "Press enter to return to the main menu."
	read -res
}

check_stateful_mount() {
	if grep -q "^${STATEFUL_PART}\s" /proc/mounts; then
		STATEFUL_MOUNTED=1
	else
		STATEFUL_MOUNTED=0
	fi
}

unmount_stateful() {
	[ "$CRAP_TESTING" -eq 1 ] && return 0
	check_stateful_mount
	[ "$STATEFUL_MOUNTED" -eq 0 ] && return 0
	echo "Unmounting stateful"

	# note that we CANNOT lazy unmount.
	if [ "$IS_CROS" -eq 1 ]; then
		# this took me about 2 weeks to figure out :sob:
		suppress initctl start pre-shutdown || :
		suppress chromeos_shutdown || :
	fi
	# fall back to this, we're not in CrOS, or maybe in a recovery image?
	suppress umount -A "$STATEFUL_PART" || :

	check_stateful_mount
	[ "$STATEFUL_MOUNTED" -eq 1 ] && return 1
	echo "Unmounted successfully"
}

refresh_stateful() {
	local stateful_start all_starts
	check_stateful_mount
	stateful_start=$(cgpt show -i 1 -b -n -q "$CRAP_DISK")
	# important to not use -q here
	all_starts=($(cgpt show "$CRAP_DISK" | grep "^\s*[0-9]" | awk '{print $1}' | sort -n))
	for i in "${!all_starts[@]}"; do
		if [ "${all_starts[$i]}" = "$stateful_start" ]; then
			STATEFUL_MAX_SECTORS=$((${all_starts[$((i + 1))]} - stateful_start - 1))
			STATEFUL_MAX_SIZE=$((CRAP_DISK_SECTOR_SIZE * STATEFUL_MAX_SECTORS))
			STATEFUL_MAX_SIZE_HR=$(format_bytes "$STATEFUL_MAX_SIZE")
			break
		fi
	done
	STATEFUL_SECTORS=$(cgpt show -i 1 -s -n -q "$CRAP_DISK")
	STATEFUL_SIZE=$((CRAP_DISK_SECTOR_SIZE * STATEFUL_SECTORS))
	STATEFUL_SIZE_HR="$(format_bytes "$STATEFUL_SIZE") ($((STATEFUL_SIZE / (STATEFUL_MAX_SIZE / 100)))% of available)"
	if STATEFUL_TUNE2FS=$(tune2fs -l "$STATEFUL_PART" 2>&1); then
		STATEFUL_VALID_FS=1
		STATEFUL_BLOCK_SIZE=$(echo "$STATEFUL_TUNE2FS" | grep "Block size" | awk '{print $3}')
		STATEFUL_MIN_BLOCKS=$(resize2fs -P "$STATEFUL_PART" 2>/dev/null | grep "Estimated minimum size" | awk '{print $NF}')
		# fallback for when resize2fs breaks for some reason...
		[ -z "$STATEFUL_MIN_BLOCKS" ] && STATEFUL_MIN_BLOCKS=$(($(echo "$STATEFUL_TUNE2FS" | grep "Block count" | awk '{print $3}') - $(echo "$STATEFUL_TUNE2FS" | grep "Free blocks" | awk '{print $3}')))
		STATEFUL_FS_USAGE=$((STATEFUL_BLOCK_SIZE * STATEFUL_MIN_BLOCKS))
		STATEFUL_FS_USAGE_HR="$(format_bytes "$STATEFUL_FS_USAGE") ($((STATEFUL_FS_USAGE / (STATEFUL_SIZE / 100)))%)"
	else
		STATEFUL_VALID_FS=0
		STATEFUL_BLOCK_SIZE=
		STATEFUL_MIN_BLOCKS=
		STATEFUL_FS_USAGE=
		STATEFUL_FS_USAGE_HR=
	fi
	# also check free space here
	CRAP_DISK_LARGEST_FREE_SECTORS=$(get_largest_free_space_size "$CRAP_DISK")
	CRAP_DISK_LARGEST_FREE_SIZE=$((CRAP_DISK_SECTOR_SIZE * CRAP_DISK_LARGEST_FREE_SECTORS))
	CRAP_DISK_LARGEST_FREE_SIZE_HR=$(format_bytes "$CRAP_DISK_LARGEST_FREE_SIZE")
}

print_disk_info() {
	echo -e "║ ${COLOR_YELLOW}Disk:${COLOR_RESET} $(printf "%-60.60s" "$CRAP_DISK") ║"
	echo -e "║ ${COLOR_YELLOW}Disk size:${COLOR_RESET} $(printf "%-55.55s" "$CRAP_DISK_SIZE_HR") ║"
	echo -e "║ ${COLOR_YELLOW}Largest free space:${COLOR_RESET} $(printf "%-46.46s" "$CRAP_DISK_LARGEST_FREE_SIZE_HR") ║"
	echo -e "║ ${COLOR_YELLOW}Stateful size:${COLOR_RESET} $(printf "%-51.51s" "$STATEFUL_SIZE_HR") ║"
}

resize_stateful_menu() {
	local num_action new_bytes new_sectors new_blocks resize2fs_out
	if ! unmount_stateful ; then
		clear_screen
		echo -e "${COLOR_RED_B}Failed to unmount stateful."
		echo -e "You may proceed, but shrinking of the partition will DESTROY YOUR DATA.${COLOR_RESET}"
		echo -e "${COLOR_CYAN_B}Would you like to continue? ${COLOR_YELLOW_B}(y/N)${COLOR_RESET}"
		read -re action
		case "$action" in
			[yY]) : ;;
			*) return ;;
		esac
	fi
	refresh_stateful
	while true; do
		clear_screen
		echo -e "╔════════════════════════════════════════════════════════════════════╗"
		print_disk_info
		echo -e "║ ${COLOR_YELLOW}Maximum stateful size:${COLOR_RESET} $(printf "%-43.43s" "$STATEFUL_MAX_SIZE_HR") ║"
		if [ "$STATEFUL_VALID_FS" -eq 1 ]; then
			echo -e "║ ${COLOR_YELLOW}Stateful FS usage (min size):${COLOR_RESET} $(printf "%-36.36s" "$STATEFUL_FS_USAGE_HR") ║"
		else
			echo "║ Stateful does not contain a valid filesystem.                      ║"
		fi
		echo -e "╠════════════════════════════════════════════════════════════════════╣"
		if [ "$STATEFUL_MOUNTED" -eq 0 ]; then
			echo -e "║ ${COLOR_CYAN_B}Resizing stateful partition${COLOR_RESET}                                        ║"
		else
			echo -e "║ ${COLOR_RED_B}Resizing stateful partition (destructive)${COLOR_RESET}                          ║"
		fi
		echo -e "║ ${COLOR_YELLOW}Acceptable units (integer only):${COLOR_RESET}                                   ║"
		echo -e "║ % - % total disk space                                             ║"
		echo -e "║ %a - % total available space                                       ║"
		echo -e "║ G - size in gibibytes                                              ║"
		echo -e "║ M - size in mebibytes                                              ║"
		echo -e "╚════════════════════════════════════════════════════════════════════╝"
		echo -e "Enter a new size for the stateful partition or press ${COLOR_YELLOW_B}Q${COLOR_RESET} to cancel."
		read -re action
		num_action="${action//[^0-9]/}"
		case "$action" in
			[qQ]) return ;;
			# decimals
			*.*) continue ;;
			# octal/hex
			0*) continue ;;
			[0-9]*%) new_bytes=$(((num_action * CRAP_DISK_SIZE) / 100)) ;;
			[0-9]*%[aA]) new_bytes=$(((num_action * STATEFUL_MAX_SIZE) / 100)) ;;
			[0-9]*[gG]) new_bytes=$((num_action * (1024 ** 3))) ;;
			[0-9]*[mM]) new_bytes=$((num_action * (1024 ** 2))) ;;
			*) continue ;;
		esac

		if [ "$new_bytes" -eq "$STATEFUL_SIZE" ]; then
			echo -e "${COLOR_BLUE_B}Stateful is already that size. What are you doing?${COLOR_RESET}"
			wait_on_enter
			continue
		fi
		if [ "$new_bytes" -gt "$STATEFUL_MAX_SIZE" ]; then
			echo -e "${COLOR_RED_B}The size you entered ($(format_bytes "$new_bytes")) is too large.${COLOR_RESET}"
			wait_on_enter
			continue
		fi
		if [ "$STATEFUL_VALID_FS" -eq 1 ] && [ "$new_bytes" -lt "$STATEFUL_FS_USAGE" ]; then
			echo -e "${COLOR_RED_B}The size you entered ($(format_bytes "$new_bytes")) is smaller than the filesystem."
			echo -e "You may proceed, but this will DESTROY YOUR DATA.${COLOR_RESET}"
			echo -e "${COLOR_CYAN_B}Would you like to continue? ${COLOR_YELLOW_B}(y/N)${COLOR_RESET}"
			read -re action
			case "$action" in
				[yY]) STATEFUL_VALID_FS=0 ;;
				*) continue ;;
			esac
		else
			echo -e "${COLOR_CYAN_B}Stateful will be resized to $(format_bytes "$new_bytes"). Is this ok? ${COLOR_YELLOW_B}(y/N)${COLOR_RESET}"
			read -re action
			case "$action" in
				[yY]) : ;;
				*) continue ;;
			esac
		fi

		new_sectors=$((new_bytes / CRAP_DISK_SECTOR_SIZE))
		# grow partition
		if [ "$new_sectors" -gt "$STATEFUL_SECTORS" ]; then
			cgpt add -i 1 -s "$new_sectors" "$CRAP_DISK"
			partx -u -n 1 "$CRAP_DISK"
		fi
		# resize filesystem
		if [ "$STATEFUL_VALID_FS" -eq 1 ] && [ "$STATEFUL_MOUNTED" -eq 0 ]; then
			# multiply again to ensure floor
			new_blocks=$(((new_sectors * CRAP_DISK_SECTOR_SIZE) / STATEFUL_BLOCK_SIZE))
			echo "Resizing filesystem..."
			suppress e2fsck -fy "$STATEFUL_PART" || :
			if ! resize2fs_out=$(resize2fs "$STATEFUL_PART" "$new_blocks" 2>&1); then
				# failure, shrink partition back to original size
				if [ "$new_sectors" -gt "$STATEFUL_SECTORS" ]; then
					cgpt add -i 1 -s "$STATEFUL_SECTORS" "$CRAP_DISK"
					partx -u -n 1 "$CRAP_DISK"
				fi
				echo -e "${COLOR_RED_B}resize2fs failed, command output is shown below:${COLOR_RESET}"
				echo "$resize2fs_out"
				break
			fi
		fi
		# shrink partition
		if [ "$new_sectors" -lt "$STATEFUL_SECTORS" ]; then
			cgpt add -i 1 -s "$new_sectors" "$CRAP_DISK"
			partx -u -n 1 "$CRAP_DISK"
		fi
		echo -e "${COLOR_GREEN_B}Success.${COLOR_RESET}"
		break
	done
	refresh_stateful
	wait_on_enter_menu
}

# try to accurately detect/mimic the problematic behavior of libparted
check_1s_parts_need_fix() {
	local part_table part_starts physical_part_table needs_move you_do_it this_num this_start this_size next_num next_start next_size
	part_table=$(cgpt show -q -n "$CRAP_DISK")
	part_starts=$(echo "$part_table" | awk '{print $1}' | sort -n)
	physical_part_table=()
	for part in $part_starts; do
		physical_part_table+=("$(echo "$part_table" | grep "^\s*${part}\s")")
	done

	needs_move=()
	you_do_it=0
	for i in "${!physical_part_table[@]}"; do
		this_num=$(echo "${physical_part_table[$i]}" | awk '{print $3}')
		if [ "$you_do_it" -eq 1 ]; then
			log_debug "[accepting defer: $this_num]"
			needs_move+=("$this_num")
			you_do_it=0
			continue
		fi
		this_start=$(echo "${physical_part_table[$i]}" | awk '{print $1}')
		this_size=$(echo "${physical_part_table[$i]}" | awk '{print $2}')
		next_num=$(echo "${physical_part_table[$((i + 1))]}" | awk '{print $3}')
		next_start=$(echo "${physical_part_table[$((i + 1))]}" | awk '{print $1}')
		next_size=$(echo "${physical_part_table[$((i + 1))]}" | awk '{print $2}')
		log_debug "me:   ${physical_part_table[$i]}"
		log_debug "next: ${physical_part_table[$((i + 1))]}"
		if [ -n "$next_num" ] && [ "$next_num" -lt "$this_num" ] && [ "$this_size" -eq 1 ] && [ "$next_start" -eq "$((this_start + 1))" ]; then
			log_debug "[problem]"
			# defer to next partition
			if [ "$next_size" -eq 1 ]; then
				log_debug "[deferring]"
				you_do_it=1
				continue
			fi
			log_debug "[not deferring: $this_num]"
			needs_move+=("$this_num")
		else
			log_debug "[no problem]"
		fi
	done
	log_debug "[needs move]:" "${needs_move[@]}"

	NEEDS_1S_FIX=$(printf '%s\n' "${needs_move[@]}" | sort -n)
}

find_unallocated_sectors() {
	local allgaps gapstart
	if allgaps=$(sfdisk -F "$1" | grep "^\s*[0-9]"); then
		while read gap; do
			gapstart=$(echo "$gap" | awk '{print $1}')
			if [ "$(echo "$gap" | awk '{print $2}')" -ge "$gapstart" ] && [ "$(echo "$gap" | awk '{print $3}')" -ge "$2" ]; then
				echo "$gapstart"
				return
			fi
		done <<<"$allgaps"
	fi
	return 1
}

fix_1s_parts() {
	local p1s_n gapstart
	clear_screen
	check_1s_parts_need_fix
	if [ -z "$NEEDS_1S_FIX" ]; then
		echo "You do not appear to need the fix,"
		echo "but if you are having issues you can choose to force it."
		echo -e "${COLOR_CYAN_B}Would you like to force the fix? ${COLOR_YELLOW_B}(y/N)${COLOR_RESET}"
		read -re action
		case "$action" in
			[yY]) p1s_n=($(cgpt show -q -n "$CRAP_DISK" | awk '{if ($2 == 1) print $3}')) ;;
			*) return ;;
		esac
	else
		p1s_n=($NEEDS_1S_FIX)
	fi

	# 1 extra sector needed after, but not before
	gapstart=$(find_unallocated_sectors "$CRAP_DISK" "$((${#p1s_n[@]} + 1))") || :
	if [ -z "$gapstart" ]; then
		echo -e "${COLOR_RED_B}Not enough unpartitioned space on disk. Cannot continue.${COLOR_RESET}"
		wait_on_enter_menu
		return
	fi

	log_debug "parts to move:" "${p1s_n[@]}"
	log_debug "gap min: $((${#p1s_n[@]} + 1))"
	log_debug "gap start: $gapstart"

	echo "Reordering partitions..."
	# move the partitions
	for i in "${!p1s_n[@]}"; do
		log_debug cgpt add -i "${p1s_n[$i]}" -b "$((gapstart + i))" -s 1 "$CRAP_DISK"
		cgpt add -i "${p1s_n[$i]}" -b "$((gapstart + i))" -s 1 "$CRAP_DISK"
	done
	partx -u "$CRAP_DISK"

	check_1s_parts_need_fix
	if [ -z "$NEEDS_1S_FIX" ]; then
		echo -e "${COLOR_GREEN_B}Success.${COLOR_RESET}"
	else
		echo -e "${COLOR_RED_B}An error occured and the partitions were not properly reordered."
		echo -e "Current partition table is shown below:${COLOR_RESET}"
		sfdisk -l "$CRAP_DISK"
	fi
	refresh_stateful
	wait_on_enter_menu
}

check_1s_parts_prompt() {
	[ -z "$NEEDS_1S_FIX" ] && return 0
	clear_screen
	echo "You have not reordered 1-sector partitions --"
	echo "doing so is highly recommended if you're installing linux"
	echo "alongside ChromeOS."
	echo -e "${COLOR_CYAN_B}Would you like to reorder these partitions now? ${COLOR_YELLOW_B}(y/N)${COLOR_RESET}"
	read -re action
	case "$action" in
		[yY]) : ;;
		*) return ;;
	esac
	fix_1s_parts
	main_menu
}

cleanup() {
	[ "$CRAP_TESTING" -eq 1 ] && losetup -d "$CRAP_DISK"
	trap - EXIT INT
}

main_menu() {
	while true; do
		clear_screen
		echo -e " ChromeOS Automated Partitioning (CRAP) $SCRIPT_DATE"
		echo -e " https://github.com/chrultrabook/crap"
		echo -e "╔════════════════════════════════════════════════════════════════════╗"
		print_disk_info
		echo -e "╠════════════════════════════════════════════════════════════════════╣"
		echo -e "║ ${COLOR_YELLOW_B}1) ${COLOR_CYAN_B}Resize stateful partition${COLOR_RESET}                                       ║"
		echo -e "║    Resize the ChromeOS user data partition to make space for an    ║"
		echo -e "║    alternate OS.                                                   ║"
		if [ -n "$NEEDS_1S_FIX" ]; then
			echo -e "║ ${COLOR_YELLOW_B}2) ${COLOR_CYAN_B}Reorder 1-sector partitions${COLOR_RESET}                                     ║"
			echo -e "║    Fix a bug that causes libparted to error and be unable to       ║"
			echo -e "║    detect existing partitions. Highly recommended before           ║"
			echo -e "║    installing linux alongside ChromeOS.                            ║"
		else
			echo -e "║ ${COLOR_BLACK_B}2) Reorder 1-sector partitions${COLOR_GREEN} (Done)${COLOR_RESET}                              ║"
			echo -e "║    ${COLOR_BLACK_B}Fix a bug that causes libparted to error and be unable to${COLOR_RESET}       ║"
			echo -e "║    ${COLOR_BLACK_B}detect existing partitions. Highly recommended before${COLOR_RESET}           ║"
			echo -e "║    ${COLOR_BLACK_B}installing linux alongside ChromeOS.${COLOR_RESET}                            ║"
		fi
		echo -e "║ ${COLOR_RED_B}Q) ${COLOR_CYAN_B}Quit${COLOR_RESET}                                                            ║"
		echo -e "║ ${COLOR_RED_B}R) ${COLOR_CYAN_B}Reboot${COLOR_RESET}                                                          ║"
		echo -e "║ ${COLOR_RED_B}P) ${COLOR_CYAN_B}Poweroff${COLOR_RESET}                                                        ║"
		echo -e "╚════════════════════════════════════════════════════════════════════╝"
		echo -e "Select an option:"
		read -re action
		case "$action" in
			1) resize_stateful_menu ;;
			2) fix_1s_parts ;;
			[qQ])
				check_1s_parts_prompt
				cleanup
				[ "$IS_CROS" -eq 1 ] && [ "$STATEFUL_MOUNTED" -eq 0 ] && echo -e "${COLOR_BLUE_B}Welcome to the void.${COLOR_RESET}"
				exit
				;;
			[rR])
				check_1s_parts_prompt
				echo "Rebooting..."
				cleanup
				[ "$CRAP_TESTING" -eq 0 ] && reboot
				exit
				;;
			[pP])
				check_1s_parts_prompt
				echo "Powering off..."
				cleanup
				[ "$CRAP_TESTING" -eq 0 ] && poweroff
				exit
				;;
		esac
	done
}

if [ "$CRAP_TESTING" -eq 1 ]; then
	[ -f "$1" ] || fail "$1 doesn't exist or isn't a file"
	CRAP_DISK=$(losetup -f)
	losetup -P "$CRAP_DISK" "$1"
else
	CRAP_DISK=$(get_largest_cros_blockdev)
	[ -z "$CRAP_DISK" ] && fail "No CrOS SSD found on device!"
fi

trap 'echo $BASH_COMMAND failed with exit code $?. THIS IS A BUG, PLEASE REPORT!' ERR
trap 'cleanup; exit' EXIT
trap 'echo Abort.; cleanup; exit' INT

CRAP_DISK_SECTOR_SIZE=$(blockdev --getss "$CRAP_DISK")
CRAP_DISK_SECTORS=$(blockdev --getsz "$CRAP_DISK")
CRAP_DISK_SIZE=$((CRAP_DISK_SECTOR_SIZE * CRAP_DISK_SECTORS))
CRAP_DISK_SIZE_HR=$(format_bytes "$CRAP_DISK_SIZE")

STATEFUL_PART=$(format_part_number "$CRAP_DISK" 1)
refresh_stateful

if [ "$IS_CROS" -eq 1 ] && [ "$CRAP_TESTING" -eq 0 ]; then
	suppress initctl stop powerd || :
	suppress ectool autofanctrl || :
	suppress ectool pwmsetkblight 20 || :
fi

check_1s_parts_need_fix
main_menu
