partition_gbl.sh
· 6.5 KiB · Bash
Raw
#!/usr/bin/env bash
# Partition a whole disk with a bringup-oriented Android GBL GPT layout.
#
# Usage:
# sudo ./partition_gbl_disk.sh [--efi /path/to/BOOTAA64.EFI] /dev/sdX
#
# Optional environment overrides:
# SUPER_SIZE=8G ./partition_gbl_disk.sh /dev/sdX
#
# The script intentionally asks for confirmation once before touching the disk.
set -euo pipefail
ESP_SIZE="${ESP_SIZE:-8M}"
MISC_SIZE="${MISC_SIZE:-4M}"
BOOT_SIZE="${BOOT_SIZE:-128M}"
VENDOR_BOOT_SIZE="${VENDOR_BOOT_SIZE:-128M}"
INIT_BOOT_SIZE="${INIT_BOOT_SIZE:-8M}"
VBMETA_SIZE="${VBMETA_SIZE:-4M}"
DTBO_SIZE="${DTBO_SIZE:-32M}"
SUPER_SIZE="${SUPER_SIZE:-8G}"
METADATA_SIZE="${METADATA_SIZE:-64M}"
die() {
echo "error: $*" >&2
exit 1
}
usage() {
cat >&2 <<EOF
Usage:
sudo $0 [--efi /path/to/BOOTAA64.EFI] /dev/sdX
Creates a destructive GPT layout for Android GBL bringup:
android_esp_a/b, misc, boot_a/b, vendor_boot_a/b, init_boot_a/b,
vbmeta_a/b, dtbo_a/b, dtb_a/b, pvmfw_a/b, super, metadata, userdata.
Options:
--efi FILE Copy FILE to both ESPs as /EFI/BOOT/BOOTAA64.EFI
-h, --help Show this help
Environment overrides:
ESP_SIZE=$ESP_SIZE
MISC_SIZE=$MISC_SIZE
BOOT_SIZE=$BOOT_SIZE
VENDOR_BOOT_SIZE=$VENDOR_BOOT_SIZE
INIT_BOOT_SIZE=$INIT_BOOT_SIZE
VBMETA_SIZE=$VBMETA_SIZE
DTBO_SIZE=$DTBO_SIZE
PVMFW_SIZE=$PVMFW_SIZE
SUPER_SIZE=$SUPER_SIZE
METADATA_SIZE=$METADATA_SIZE
EOF
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
}
cleanup() {
if [[ -n "${ESP_A_MNT:-}" && -d "${ESP_A_MNT:-}" ]]; then
umount "$ESP_A_MNT" 2>/dev/null || true
rmdir "$ESP_A_MNT" 2>/dev/null || true
fi
if [[ -n "${ESP_B_MNT:-}" && -d "${ESP_B_MNT:-}" ]]; then
umount "$ESP_B_MNT" 2>/dev/null || true
rmdir "$ESP_B_MNT" 2>/dev/null || true
fi
if [[ -n "${SFDISK_SCRIPT:-}" ]]; then
rm -f "$SFDISK_SCRIPT"
fi
}
partition_path() {
local disk="$1"
local number="$2"
case "$disk" in
*[0-9]) printf '%sp%s\n' "$disk" "$number" ;;
*) printf '%s%s\n' "$disk" "$number" ;;
esac
}
EFI_PAYLOAD=""
ARGS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--efi)
[[ $# -ge 2 ]] || die "--efi requires a file path"
EFI_PAYLOAD="$2"
shift 2
;;
-h | --help)
usage
exit 0
;;
--)
shift
ARGS+=("$@")
break
;;
-*)
die "unknown argument: $1"
;;
*)
ARGS+=("$1")
shift
;;
esac
done
[[ ${#ARGS[@]} -eq 1 ]] || {
usage
exit 2
}
DISK="${ARGS[0]}"
[[ $EUID -eq 0 ]] || die "run as root, for example: sudo $0 $DISK"
[[ -b "$DISK" ]] || die "$DISK is not a block device"
if [[ -n "$EFI_PAYLOAD" ]]; then
[[ -f "$EFI_PAYLOAD" ]] || die "--efi payload does not exist or is not a regular file: $EFI_PAYLOAD"
fi
require_cmd sfdisk
require_cmd lsblk
require_cmd findmnt
if [[ -n "$EFI_PAYLOAD" ]]; then
require_cmd mount
require_cmd umount
require_cmd mkfs.vfat
fi
if [[ "$(lsblk -dn -o TYPE "$DISK")" != "disk" ]]; then
die "$DISK is not a whole disk according to lsblk"
fi
if findmnt --source "$DISK" >/dev/null 2>&1; then
die "$DISK itself is mounted; unmount it first"
fi
while read -r child; do
[[ -n "$child" ]] || continue
if findmnt --source "$child" >/dev/null 2>&1; then
die "$child is mounted; unmount all partitions on $DISK first"
fi
done < <(lsblk -nrpo NAME "$DISK" | tail -n +2)
cat <<EOF
About to DESTROY ALL DATA on:
$DISK
Planned GPT layout:
1 android_esp_a $ESP_SIZE EFI System, FAT32
2 android_esp_b $ESP_SIZE EFI System, FAT32
3 misc $MISC_SIZE
4 boot_a $BOOT_SIZE
5 boot_b $BOOT_SIZE
6 vendor_boot_a $VENDOR_BOOT_SIZE
7 vendor_boot_b $VENDOR_BOOT_SIZE
8 init_boot_a $INIT_BOOT_SIZE
9 init_boot_b $INIT_BOOT_SIZE
10 vbmeta_a $VBMETA_SIZE
11 vbmeta_b $VBMETA_SIZE
12 dtbo_a $DTBO_SIZE
13 dtbo_b $DTBO_SIZE
14 super $SUPER_SIZE
15 metadata $METADATA_SIZE
16 userdata remaining space
EOF
if [[ -n "$EFI_PAYLOAD" ]]; then
cat <<EOF
GBL EFI payload:
$EFI_PAYLOAD
The payload will be copied to both Android ESPs as:
/EFI/BOOT/BOOTAA64.EFI
EOF
fi
cat <<EOF
This cannot be undone by this script.
EOF
read -r -p "Continue and destroy all data on $DISK? [y/N]: " CONFIRMATION
case "$CONFIRMATION" in
y | Y | yes | YES)
;;
*)
die "aborting"
;;
esac
SFDISK_SCRIPT="$(mktemp)"
trap cleanup EXIT
# Declarative GPT layout for sfdisk. Omitted start sectors let sfdisk choose
# aligned starts. Omitted userdata size consumes the remaining disk.
cat >"$SFDISK_SCRIPT" <<EOF
label: gpt
name="android_esp_a", size=$ESP_SIZE,type=uefi, name="EFI"
name="android_esp_b", size=$ESP_SIZE,type=uefi, name="EFI"
name="misc", size=$MISC_SIZE
name="boot_a", size=$BOOT_SIZE
name="boot_b", size=$BOOT_SIZE
name="vendor_boot_a", size=$VENDOR_BOOT_SIZE
name="vendor_boot_b", size=$VENDOR_BOOT_SIZE
name="init_boot_a", size=$INIT_BOOT_SIZE
name="init_boot_b", size=$INIT_BOOT_SIZE
name="vbmeta_a", size=$VBMETA_SIZE
name="vbmeta_b", size=$VBMETA_SIZE
name="dtbo_a", size=$DTBO_SIZE
name="dtbo_b", size=$DTBO_SIZE
name="super", size=$SUPER_SIZE
name="metadata", size=$METADATA_SIZE
name="userdata"
EOF
echo "Writing GPT with sfdisk..."
sfdisk "$DISK" <"$SFDISK_SCRIPT"
if command -v partprobe >/dev/null 2>&1; then
partprobe "$DISK" || true
fi
if command -v udevadm >/dev/null 2>&1; then
udevadm settle || true
fi
blockdev --rereadpt "$DISK" 2>/dev/null || true
ESP_A="$(partition_path "$DISK" 1)"
ESP_B="$(partition_path "$DISK" 2)"
if command -v mkfs.fat >/dev/null 2>&1; then
echo "Formatting Android ESP partitions as FAT32..."
mkfs.vfat -n EFI "$ESP_A"
mkfs.vfat -n EFI "$ESP_B"
else
echo "warning: mkfs.fat not found; format $ESP_A and $ESP_B as FAT32 manually" >&2
fi
if [[ -n "$EFI_PAYLOAD" ]]; then
echo "Copying GBL EFI payload to Android ESP partitions..."
ESP_A_MNT="$(mktemp -d /tmp/gbl-esp-a.XXXXXX)"
ESP_B_MNT="$(mktemp -d /tmp/gbl-esp-b.XXXXXX)"
mount "$ESP_A" "$ESP_A_MNT"
mount "$ESP_B" "$ESP_B_MNT"
mkdir -p "$ESP_A_MNT/EFI/BOOT"
mkdir -p "$ESP_B_MNT/EFI/BOOT"
cp "$EFI_PAYLOAD" "$ESP_A_MNT/EFI/BOOT/BOOTAA64.EFI"
cp "$EFI_PAYLOAD" "$ESP_B_MNT/EFI/BOOT/BOOTAA64.EFI"
sync
umount "$ESP_A_MNT"
umount "$ESP_B_MNT"
rmdir "$ESP_A_MNT" "$ESP_B_MNT"
ESP_A_MNT=""
ESP_B_MNT=""
fi
echo
echo "Done. Resulting partition table:"
sfdisk -d "$DISK"
echo
if [[ -n "$EFI_PAYLOAD" ]]; then
echo "GBL EFI payload copied to both ESPs as /EFI/BOOT/BOOTAA64.EFI."
else
echo "Copy GBL to both ESPs as /EFI/BOOT/BOOTAA64.EFI before booting."
fi
| 1 | #!/usr/bin/env bash |
| 2 | # Partition a whole disk with a bringup-oriented Android GBL GPT layout. |
| 3 | # |
| 4 | # Usage: |
| 5 | # sudo ./partition_gbl_disk.sh [--efi /path/to/BOOTAA64.EFI] /dev/sdX |
| 6 | # |
| 7 | # Optional environment overrides: |
| 8 | # SUPER_SIZE=8G ./partition_gbl_disk.sh /dev/sdX |
| 9 | # |
| 10 | # The script intentionally asks for confirmation once before touching the disk. |
| 11 | |
| 12 | set -euo pipefail |
| 13 | |
| 14 | ESP_SIZE="${ESP_SIZE:-8M}" |
| 15 | MISC_SIZE="${MISC_SIZE:-4M}" |
| 16 | BOOT_SIZE="${BOOT_SIZE:-128M}" |
| 17 | VENDOR_BOOT_SIZE="${VENDOR_BOOT_SIZE:-128M}" |
| 18 | INIT_BOOT_SIZE="${INIT_BOOT_SIZE:-8M}" |
| 19 | VBMETA_SIZE="${VBMETA_SIZE:-4M}" |
| 20 | DTBO_SIZE="${DTBO_SIZE:-32M}" |
| 21 | SUPER_SIZE="${SUPER_SIZE:-8G}" |
| 22 | METADATA_SIZE="${METADATA_SIZE:-64M}" |
| 23 | |
| 24 | die() { |
| 25 | echo "error: $*" >&2 |
| 26 | exit 1 |
| 27 | } |
| 28 | |
| 29 | usage() { |
| 30 | cat >&2 <<EOF |
| 31 | Usage: |
| 32 | sudo $0 [--efi /path/to/BOOTAA64.EFI] /dev/sdX |
| 33 | |
| 34 | Creates a destructive GPT layout for Android GBL bringup: |
| 35 | android_esp_a/b, misc, boot_a/b, vendor_boot_a/b, init_boot_a/b, |
| 36 | vbmeta_a/b, dtbo_a/b, dtb_a/b, pvmfw_a/b, super, metadata, userdata. |
| 37 | |
| 38 | Options: |
| 39 | --efi FILE Copy FILE to both ESPs as /EFI/BOOT/BOOTAA64.EFI |
| 40 | -h, --help Show this help |
| 41 | |
| 42 | Environment overrides: |
| 43 | ESP_SIZE=$ESP_SIZE |
| 44 | MISC_SIZE=$MISC_SIZE |
| 45 | BOOT_SIZE=$BOOT_SIZE |
| 46 | VENDOR_BOOT_SIZE=$VENDOR_BOOT_SIZE |
| 47 | INIT_BOOT_SIZE=$INIT_BOOT_SIZE |
| 48 | VBMETA_SIZE=$VBMETA_SIZE |
| 49 | DTBO_SIZE=$DTBO_SIZE |
| 50 | PVMFW_SIZE=$PVMFW_SIZE |
| 51 | SUPER_SIZE=$SUPER_SIZE |
| 52 | METADATA_SIZE=$METADATA_SIZE |
| 53 | EOF |
| 54 | } |
| 55 | |
| 56 | require_cmd() { |
| 57 | command -v "$1" >/dev/null 2>&1 || die "missing required command: $1" |
| 58 | } |
| 59 | |
| 60 | cleanup() { |
| 61 | if [[ -n "${ESP_A_MNT:-}" && -d "${ESP_A_MNT:-}" ]]; then |
| 62 | umount "$ESP_A_MNT" 2>/dev/null || true |
| 63 | rmdir "$ESP_A_MNT" 2>/dev/null || true |
| 64 | fi |
| 65 | if [[ -n "${ESP_B_MNT:-}" && -d "${ESP_B_MNT:-}" ]]; then |
| 66 | umount "$ESP_B_MNT" 2>/dev/null || true |
| 67 | rmdir "$ESP_B_MNT" 2>/dev/null || true |
| 68 | fi |
| 69 | if [[ -n "${SFDISK_SCRIPT:-}" ]]; then |
| 70 | rm -f "$SFDISK_SCRIPT" |
| 71 | fi |
| 72 | } |
| 73 | |
| 74 | partition_path() { |
| 75 | local disk="$1" |
| 76 | local number="$2" |
| 77 | |
| 78 | case "$disk" in |
| 79 | *[0-9]) printf '%sp%s\n' "$disk" "$number" ;; |
| 80 | *) printf '%s%s\n' "$disk" "$number" ;; |
| 81 | esac |
| 82 | } |
| 83 | |
| 84 | EFI_PAYLOAD="" |
| 85 | ARGS=() |
| 86 | |
| 87 | while [[ $# -gt 0 ]]; do |
| 88 | case "$1" in |
| 89 | --efi) |
| 90 | [[ $# -ge 2 ]] || die "--efi requires a file path" |
| 91 | EFI_PAYLOAD="$2" |
| 92 | shift 2 |
| 93 | ;; |
| 94 | -h | --help) |
| 95 | usage |
| 96 | exit 0 |
| 97 | ;; |
| 98 | --) |
| 99 | shift |
| 100 | ARGS+=("$@") |
| 101 | break |
| 102 | ;; |
| 103 | -*) |
| 104 | die "unknown argument: $1" |
| 105 | ;; |
| 106 | *) |
| 107 | ARGS+=("$1") |
| 108 | shift |
| 109 | ;; |
| 110 | esac |
| 111 | done |
| 112 | |
| 113 | [[ ${#ARGS[@]} -eq 1 ]] || { |
| 114 | usage |
| 115 | exit 2 |
| 116 | } |
| 117 | |
| 118 | DISK="${ARGS[0]}" |
| 119 | |
| 120 | [[ $EUID -eq 0 ]] || die "run as root, for example: sudo $0 $DISK" |
| 121 | [[ -b "$DISK" ]] || die "$DISK is not a block device" |
| 122 | if [[ -n "$EFI_PAYLOAD" ]]; then |
| 123 | [[ -f "$EFI_PAYLOAD" ]] || die "--efi payload does not exist or is not a regular file: $EFI_PAYLOAD" |
| 124 | fi |
| 125 | |
| 126 | require_cmd sfdisk |
| 127 | require_cmd lsblk |
| 128 | require_cmd findmnt |
| 129 | if [[ -n "$EFI_PAYLOAD" ]]; then |
| 130 | require_cmd mount |
| 131 | require_cmd umount |
| 132 | require_cmd mkfs.vfat |
| 133 | fi |
| 134 | |
| 135 | if [[ "$(lsblk -dn -o TYPE "$DISK")" != "disk" ]]; then |
| 136 | die "$DISK is not a whole disk according to lsblk" |
| 137 | fi |
| 138 | |
| 139 | if findmnt --source "$DISK" >/dev/null 2>&1; then |
| 140 | die "$DISK itself is mounted; unmount it first" |
| 141 | fi |
| 142 | |
| 143 | while read -r child; do |
| 144 | [[ -n "$child" ]] || continue |
| 145 | if findmnt --source "$child" >/dev/null 2>&1; then |
| 146 | die "$child is mounted; unmount all partitions on $DISK first" |
| 147 | fi |
| 148 | done < <(lsblk -nrpo NAME "$DISK" | tail -n +2) |
| 149 | |
| 150 | cat <<EOF |
| 151 | About to DESTROY ALL DATA on: |
| 152 | $DISK |
| 153 | |
| 154 | Planned GPT layout: |
| 155 | 1 android_esp_a $ESP_SIZE EFI System, FAT32 |
| 156 | 2 android_esp_b $ESP_SIZE EFI System, FAT32 |
| 157 | 3 misc $MISC_SIZE |
| 158 | 4 boot_a $BOOT_SIZE |
| 159 | 5 boot_b $BOOT_SIZE |
| 160 | 6 vendor_boot_a $VENDOR_BOOT_SIZE |
| 161 | 7 vendor_boot_b $VENDOR_BOOT_SIZE |
| 162 | 8 init_boot_a $INIT_BOOT_SIZE |
| 163 | 9 init_boot_b $INIT_BOOT_SIZE |
| 164 | 10 vbmeta_a $VBMETA_SIZE |
| 165 | 11 vbmeta_b $VBMETA_SIZE |
| 166 | 12 dtbo_a $DTBO_SIZE |
| 167 | 13 dtbo_b $DTBO_SIZE |
| 168 | 14 super $SUPER_SIZE |
| 169 | 15 metadata $METADATA_SIZE |
| 170 | 16 userdata remaining space |
| 171 | |
| 172 | EOF |
| 173 | if [[ -n "$EFI_PAYLOAD" ]]; then |
| 174 | cat <<EOF |
| 175 | GBL EFI payload: |
| 176 | $EFI_PAYLOAD |
| 177 | |
| 178 | The payload will be copied to both Android ESPs as: |
| 179 | /EFI/BOOT/BOOTAA64.EFI |
| 180 | |
| 181 | EOF |
| 182 | fi |
| 183 | cat <<EOF |
| 184 | This cannot be undone by this script. |
| 185 | EOF |
| 186 | |
| 187 | read -r -p "Continue and destroy all data on $DISK? [y/N]: " CONFIRMATION |
| 188 | case "$CONFIRMATION" in |
| 189 | y | Y | yes | YES) |
| 190 | ;; |
| 191 | *) |
| 192 | die "aborting" |
| 193 | ;; |
| 194 | esac |
| 195 | |
| 196 | SFDISK_SCRIPT="$(mktemp)" |
| 197 | trap cleanup EXIT |
| 198 | |
| 199 | # Declarative GPT layout for sfdisk. Omitted start sectors let sfdisk choose |
| 200 | # aligned starts. Omitted userdata size consumes the remaining disk. |
| 201 | cat >"$SFDISK_SCRIPT" <<EOF |
| 202 | label: gpt |
| 203 | |
| 204 | name="android_esp_a", size=$ESP_SIZE,type=uefi, name="EFI" |
| 205 | name="android_esp_b", size=$ESP_SIZE,type=uefi, name="EFI" |
| 206 | name="misc", size=$MISC_SIZE |
| 207 | name="boot_a", size=$BOOT_SIZE |
| 208 | name="boot_b", size=$BOOT_SIZE |
| 209 | name="vendor_boot_a", size=$VENDOR_BOOT_SIZE |
| 210 | name="vendor_boot_b", size=$VENDOR_BOOT_SIZE |
| 211 | name="init_boot_a", size=$INIT_BOOT_SIZE |
| 212 | name="init_boot_b", size=$INIT_BOOT_SIZE |
| 213 | name="vbmeta_a", size=$VBMETA_SIZE |
| 214 | name="vbmeta_b", size=$VBMETA_SIZE |
| 215 | name="dtbo_a", size=$DTBO_SIZE |
| 216 | name="dtbo_b", size=$DTBO_SIZE |
| 217 | name="super", size=$SUPER_SIZE |
| 218 | name="metadata", size=$METADATA_SIZE |
| 219 | name="userdata" |
| 220 | EOF |
| 221 | |
| 222 | echo "Writing GPT with sfdisk..." |
| 223 | sfdisk "$DISK" <"$SFDISK_SCRIPT" |
| 224 | |
| 225 | if command -v partprobe >/dev/null 2>&1; then |
| 226 | partprobe "$DISK" || true |
| 227 | fi |
| 228 | if command -v udevadm >/dev/null 2>&1; then |
| 229 | udevadm settle || true |
| 230 | fi |
| 231 | blockdev --rereadpt "$DISK" 2>/dev/null || true |
| 232 | |
| 233 | ESP_A="$(partition_path "$DISK" 1)" |
| 234 | ESP_B="$(partition_path "$DISK" 2)" |
| 235 | |
| 236 | if command -v mkfs.fat >/dev/null 2>&1; then |
| 237 | echo "Formatting Android ESP partitions as FAT32..." |
| 238 | mkfs.vfat -n EFI "$ESP_A" |
| 239 | mkfs.vfat -n EFI "$ESP_B" |
| 240 | else |
| 241 | echo "warning: mkfs.fat not found; format $ESP_A and $ESP_B as FAT32 manually" >&2 |
| 242 | fi |
| 243 | |
| 244 | if [[ -n "$EFI_PAYLOAD" ]]; then |
| 245 | echo "Copying GBL EFI payload to Android ESP partitions..." |
| 246 | ESP_A_MNT="$(mktemp -d /tmp/gbl-esp-a.XXXXXX)" |
| 247 | ESP_B_MNT="$(mktemp -d /tmp/gbl-esp-b.XXXXXX)" |
| 248 | |
| 249 | mount "$ESP_A" "$ESP_A_MNT" |
| 250 | mount "$ESP_B" "$ESP_B_MNT" |
| 251 | |
| 252 | mkdir -p "$ESP_A_MNT/EFI/BOOT" |
| 253 | mkdir -p "$ESP_B_MNT/EFI/BOOT" |
| 254 | cp "$EFI_PAYLOAD" "$ESP_A_MNT/EFI/BOOT/BOOTAA64.EFI" |
| 255 | cp "$EFI_PAYLOAD" "$ESP_B_MNT/EFI/BOOT/BOOTAA64.EFI" |
| 256 | sync |
| 257 | |
| 258 | umount "$ESP_A_MNT" |
| 259 | umount "$ESP_B_MNT" |
| 260 | rmdir "$ESP_A_MNT" "$ESP_B_MNT" |
| 261 | ESP_A_MNT="" |
| 262 | ESP_B_MNT="" |
| 263 | fi |
| 264 | |
| 265 | echo |
| 266 | echo "Done. Resulting partition table:" |
| 267 | sfdisk -d "$DISK" |
| 268 | echo |
| 269 | if [[ -n "$EFI_PAYLOAD" ]]; then |
| 270 | echo "GBL EFI payload copied to both ESPs as /EFI/BOOT/BOOTAA64.EFI." |
| 271 | else |
| 272 | echo "Copy GBL to both ESPs as /EFI/BOOT/BOOTAA64.EFI before booting." |
| 273 | fi |
| 274 |