Last active 4 weeks ago

partition_gbl.sh Raw
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
12set -euo pipefail
13
14ESP_SIZE="${ESP_SIZE:-8M}"
15MISC_SIZE="${MISC_SIZE:-4M}"
16BOOT_SIZE="${BOOT_SIZE:-128M}"
17VENDOR_BOOT_SIZE="${VENDOR_BOOT_SIZE:-128M}"
18INIT_BOOT_SIZE="${INIT_BOOT_SIZE:-8M}"
19VBMETA_SIZE="${VBMETA_SIZE:-4M}"
20DTBO_SIZE="${DTBO_SIZE:-32M}"
21SUPER_SIZE="${SUPER_SIZE:-8G}"
22METADATA_SIZE="${METADATA_SIZE:-64M}"
23
24die() {
25 echo "error: $*" >&2
26 exit 1
27}
28
29usage() {
30 cat >&2 <<EOF
31Usage:
32 sudo $0 [--efi /path/to/BOOTAA64.EFI] /dev/sdX
33
34Creates 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
38Options:
39 --efi FILE Copy FILE to both ESPs as /EFI/BOOT/BOOTAA64.EFI
40 -h, --help Show this help
41
42Environment 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
53EOF
54}
55
56require_cmd() {
57 command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
58}
59
60cleanup() {
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
74partition_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
84EFI_PAYLOAD=""
85ARGS=()
86
87while [[ $# -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
111done
112
113[[ ${#ARGS[@]} -eq 1 ]] || {
114 usage
115 exit 2
116}
117
118DISK="${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"
122if [[ -n "$EFI_PAYLOAD" ]]; then
123 [[ -f "$EFI_PAYLOAD" ]] || die "--efi payload does not exist or is not a regular file: $EFI_PAYLOAD"
124fi
125
126require_cmd sfdisk
127require_cmd lsblk
128require_cmd findmnt
129if [[ -n "$EFI_PAYLOAD" ]]; then
130 require_cmd mount
131 require_cmd umount
132 require_cmd mkfs.vfat
133fi
134
135if [[ "$(lsblk -dn -o TYPE "$DISK")" != "disk" ]]; then
136 die "$DISK is not a whole disk according to lsblk"
137fi
138
139if findmnt --source "$DISK" >/dev/null 2>&1; then
140 die "$DISK itself is mounted; unmount it first"
141fi
142
143while 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
148done < <(lsblk -nrpo NAME "$DISK" | tail -n +2)
149
150cat <<EOF
151About to DESTROY ALL DATA on:
152 $DISK
153
154Planned 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
172EOF
173if [[ -n "$EFI_PAYLOAD" ]]; then
174 cat <<EOF
175GBL EFI payload:
176 $EFI_PAYLOAD
177
178The payload will be copied to both Android ESPs as:
179 /EFI/BOOT/BOOTAA64.EFI
180
181EOF
182fi
183cat <<EOF
184This cannot be undone by this script.
185EOF
186
187read -r -p "Continue and destroy all data on $DISK? [y/N]: " CONFIRMATION
188case "$CONFIRMATION" in
189 y | Y | yes | YES)
190 ;;
191 *)
192 die "aborting"
193 ;;
194esac
195
196SFDISK_SCRIPT="$(mktemp)"
197trap 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.
201cat >"$SFDISK_SCRIPT" <<EOF
202label: gpt
203
204name="android_esp_a", size=$ESP_SIZE,type=uefi, name="EFI"
205name="android_esp_b", size=$ESP_SIZE,type=uefi, name="EFI"
206name="misc", size=$MISC_SIZE
207name="boot_a", size=$BOOT_SIZE
208name="boot_b", size=$BOOT_SIZE
209name="vendor_boot_a", size=$VENDOR_BOOT_SIZE
210name="vendor_boot_b", size=$VENDOR_BOOT_SIZE
211name="init_boot_a", size=$INIT_BOOT_SIZE
212name="init_boot_b", size=$INIT_BOOT_SIZE
213name="vbmeta_a", size=$VBMETA_SIZE
214name="vbmeta_b", size=$VBMETA_SIZE
215name="dtbo_a", size=$DTBO_SIZE
216name="dtbo_b", size=$DTBO_SIZE
217name="super", size=$SUPER_SIZE
218name="metadata", size=$METADATA_SIZE
219name="userdata"
220EOF
221
222echo "Writing GPT with sfdisk..."
223sfdisk "$DISK" <"$SFDISK_SCRIPT"
224
225if command -v partprobe >/dev/null 2>&1; then
226 partprobe "$DISK" || true
227fi
228if command -v udevadm >/dev/null 2>&1; then
229 udevadm settle || true
230fi
231blockdev --rereadpt "$DISK" 2>/dev/null || true
232
233ESP_A="$(partition_path "$DISK" 1)"
234ESP_B="$(partition_path "$DISK" 2)"
235
236if 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"
240else
241 echo "warning: mkfs.fat not found; format $ESP_A and $ESP_B as FAT32 manually" >&2
242fi
243
244if [[ -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=""
263fi
264
265echo
266echo "Done. Resulting partition table:"
267sfdisk -d "$DISK"
268echo
269if [[ -n "$EFI_PAYLOAD" ]]; then
270 echo "GBL EFI payload copied to both ESPs as /EFI/BOOT/BOOTAA64.EFI."
271else
272 echo "Copy GBL to both ESPs as /EFI/BOOT/BOOTAA64.EFI before booting."
273fi
274