xref: /aosp_15_r20/external/vboot_reference/tests/run_cgpt_tests.sh (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1#!/bin/bash -eu
2
3# Copyright 2010 The ChromiumOS Authors
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6#
7# Run tests for cgpt utility.
8
9# Load common constants and variables.
10. "$(dirname "$0")/common.sh"
11
12CGPT=$(readlink -f "$1")
13[ -x ""${CGPT}"" ] || error "Can't execute $CGPT"
14
15MTD=("${@:2}")
16
17# Run tests in a dedicated directory for easy cleanup or debugging.
18DIR="${TEST_DIR}/cgpt_test_dir"
19[ -d "$DIR" ] || mkdir -p "$DIR"
20warning "testing "${CGPT}" in $DIR"
21cd "$DIR"
22
23assert_fail() {
24  set +e
25  if "$@" 2>/dev/null; then
26    error "$*" " should have failed but did not"
27  fi
28  set -e
29}
30
31# Test failure on non existing file.
32assert_fail "${CGPT}" show "${MTD[@]}" blah_404_haha
33
34echo "Create an empty file to use as the device..."
35NUM_SECTORS=1000
36DEV=fake_dev.bin
37rm -f ${DEV}
38dd if=/dev/zero of=${DEV} conv=notrunc bs=512 count=${NUM_SECTORS} 2>/dev/null
39
40DATA_START=100
41DATA_SIZE=20
42DATA_LABEL="data stuff"
43DATA_GUID='0fc63daf-8483-4772-8e79-3d69d8477de4'
44DATA_NUM=1
45
46KERN_START=200
47KERN_SIZE=30
48KERN_LABEL="kernel stuff"
49KERN_GUID='fe3a2a5d-4f32-41a7-b725-accc3285a309'
50KERN_NUM=2
51
52ROOTFS_START=300
53ROOTFS_SIZE=40
54ROOTFS_LABEL="rootfs stuff"
55ROOTFS_GUID='3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec'
56ROOTFS_NUM=3
57
58ESP_START=400
59ESP_SIZE=50
60ESP_LABEL="ESP stuff"
61ESP_GUID='c12a7328-f81f-11d2-ba4b-00a0c93ec93b'
62ESP_NUM=4
63
64FUTURE_START=500
65FUTURE_SIZE=60
66FUTURE_LABEL="future stuff"
67FUTURE_GUID='2e0a753d-9e48-43b0-8337-b15192cb1b5e'
68FUTURE_NUM=5
69
70RANDOM_START=600
71RANDOM_SIZE=70
72RANDOM_LABEL="random stuff"
73RANDOM_GUID='2364a860-bf63-42fb-a83d-9ad3e057fcf5'
74RANDOM_NUM=6
75
76RANDOM_DRIVE_GUID='12345678-0000-1111-2222-123456789ABC'
77
78"${CGPT}" create "${MTD[@]}" ${DEV}
79
80run_basic_tests() {
81  echo "Create a bunch of partitions, using the real GUID types..."
82
83  "${CGPT}" add "${MTD[@]}" -b ${DATA_START} -s ${DATA_SIZE} -t ${DATA_GUID} \
84    -l "${DATA_LABEL}" ${DEV}
85  "${CGPT}" add "${MTD[@]}" -b ${KERN_START} -s ${KERN_SIZE} -t ${KERN_GUID} \
86    -l "${KERN_LABEL}" ${DEV}
87  "${CGPT}" add "${MTD[@]}" -b ${ROOTFS_START} -s ${ROOTFS_SIZE} \
88    -t ${ROOTFS_GUID} -l "${ROOTFS_LABEL}" ${DEV}
89  "${CGPT}" add "${MTD[@]}" -b ${ESP_START} -s ${ESP_SIZE} -t ${ESP_GUID} \
90    -l "${ESP_LABEL}" ${DEV}
91  "${CGPT}" add "${MTD[@]}" -b ${FUTURE_START} -s ${FUTURE_SIZE} \
92    -t ${FUTURE_GUID} -l "${FUTURE_LABEL}" ${DEV}
93  "${CGPT}" add "${MTD[@]}" -b ${RANDOM_START} -s ${RANDOM_SIZE} \
94    -t ${RANDOM_GUID} -l "${RANDOM_LABEL}" ${DEV}
95
96
97  echo "Extract the start and size of given partitions..."
98
99  X=$("${CGPT}" show "${MTD[@]}" -b -i $DATA_NUM ${DEV})
100  Y=$("${CGPT}" show "${MTD[@]}" -s -i $DATA_NUM ${DEV})
101  [ "$X $Y" = "$DATA_START $DATA_SIZE" ] || error
102
103  X=$("${CGPT}" show "${MTD[@]}" -b -i $KERN_NUM ${DEV})
104  Y=$("${CGPT}" show "${MTD[@]}" -s -i $KERN_NUM ${DEV})
105  [ "$X $Y" = "$KERN_START $KERN_SIZE" ] || error
106
107  X=$("${CGPT}" show "${MTD[@]}" -b -i $ROOTFS_NUM ${DEV})
108  Y=$("${CGPT}" show "${MTD[@]}" -s -i $ROOTFS_NUM ${DEV})
109  [ "$X $Y" = "$ROOTFS_START $ROOTFS_SIZE" ] || error
110
111  X=$("${CGPT}" show "${MTD[@]}" -b -i $ESP_NUM ${DEV})
112  Y=$("${CGPT}" show "${MTD[@]}" -s -i $ESP_NUM ${DEV})
113  [ "$X $Y" = "$ESP_START $ESP_SIZE" ] || error
114
115  X=$("${CGPT}" show "${MTD[@]}" -b -i $FUTURE_NUM ${DEV})
116  Y=$("${CGPT}" show "${MTD[@]}" -s -i $FUTURE_NUM ${DEV})
117  [ "$X $Y" = "$FUTURE_START $FUTURE_SIZE" ] || error
118
119  X=$("${CGPT}" show "${MTD[@]}" -b -i $RANDOM_NUM ${DEV})
120  Y=$("${CGPT}" show "${MTD[@]}" -s -i $RANDOM_NUM ${DEV})
121  [ "$X $Y" = "$RANDOM_START $RANDOM_SIZE" ] || error
122
123
124  echo "Change the beginning..."
125  DATA_START=$((DATA_START + 10))
126  "${CGPT}" add "${MTD[@]}" -i 1 -b ${DATA_START} ${DEV} || error
127  X=$("${CGPT}" show "${MTD[@]}" -b -i 1 ${DEV})
128  [ "$X" = "$DATA_START" ] || error
129
130  echo "Change the size..."
131  DATA_SIZE=$((DATA_SIZE + 10))
132  "${CGPT}" add "${MTD[@]}" -i 1 -s ${DATA_SIZE} ${DEV} || error
133  X=$("${CGPT}" show "${MTD[@]}" -s -i 1 ${DEV})
134  [ "$X" = "$DATA_SIZE" ] || error
135
136  echo "Change the type..."
137  "${CGPT}" add "${MTD[@]}" -i 1 -t reserved ${DEV} || error
138  X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV} | tr '[:upper:]' '[:lower:]')
139  [ "$X" = "$FUTURE_GUID" ] || error
140  # arbitrary value
141  "${CGPT}" add "${MTD[@]}" -i 1 -t 610a563a-a55c-4ae0-ab07-86e5bb9db67f \
142    ${DEV} || error
143  X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV})
144  [ "$X" = "610A563A-A55C-4AE0-AB07-86E5BB9DB67F" ] || error
145
146  "${CGPT}" add "${MTD[@]}" -i 1 -t data ${DEV} || error
147  X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV} | tr '[:upper:]' '[:lower:]')
148  [ "$X" = "$DATA_GUID" ] || error
149
150  ORIG_ID=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | \
151    grep -i "disk uuid" | head -1 | awk ' { print $3 } ' )
152  [ ! "$ORIG_ID" = "$RANDOM_DRIVE_GUID" ] || error
153  "${CGPT}" edit "${MTD[@]}" -u ${RANDOM_DRIVE_GUID} ${DEV} || error
154  X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \
155    head -1 | awk ' { print $3 } ' )
156  [ "$X" = "${RANDOM_DRIVE_GUID}" ] || error
157  "${CGPT}" edit "${MTD[@]}" -u "${ORIG_ID}" ${DEV} || error
158  X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \
159    head -1 | awk ' { print $3 } ' )
160  [ "$X" = "${ORIG_ID}" ] || error
161}
162run_basic_tests
163
164ORIG_ID=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | \
165  grep -i "disk uuid" | awk ' { print $3 } ' )
166[ ! "$ORIG_ID" = "$RANDOM_DRIVE_GUID" ] || error
167"${CGPT}" edit "${MTD[@]}" -u ${RANDOM_DRIVE_GUID} ${DEV} || error
168X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \
169  head -1 | awk ' { print $3 } ' )
170[ "$X" = "${RANDOM_DRIVE_GUID}" ] || error
171"${CGPT}" edit "${MTD[@]}" -u "${ORIG_ID}" ${DEV} || error
172X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \
173  awk ' { print $3 } ' )
174[ "$X" = "${ORIG_ID}" ] || error
175
176echo "Set the boot partition.."
177"${CGPT}" boot "${MTD[@]}" -i ${KERN_NUM} ${DEV} >/dev/null
178
179echo "Check the PMBR's idea of the boot partition..."
180X=$("${CGPT}" boot "${MTD[@]}" ${DEV})
181Y=$("${CGPT}" show "${MTD[@]}" -u -i $KERN_NUM $DEV)
182[ "$X" = "$Y" ] || error
183
184# Input: sequence of priorities
185# Output: ${DEV} has kernel partitions with the given priorities
186make_pri() {
187  local idx=0
188  "${CGPT}" create "${MTD[@]}" ${DEV}
189  for pri in "$@"; do
190    idx=$((idx+1))
191    "${CGPT}" add "${MTD[@]}" -t kernel -l "kern$idx" -b $((100 + 2 * idx)) \
192      -s 1 -P $pri ${DEV}
193  done
194}
195
196# Output: returns string containing priorities of all kernels
197get_pri() {
198  local output=()
199  for idx in $("${CGPT}" find "${MTD[@]}" -t kernel ${DEV} | sed -e s@${DEV}@@);
200  do
201    output+=("$("${CGPT}" show "${MTD[@]}" -i "$idx" -P ${DEV})")
202  done
203  echo "${output[@]}"
204}
205
206# Input: list of priorities
207# Operation: expects ${DEV} to contain those kernel priorities
208assert_pri() {
209  local expected="$*"
210  local actual
211  actual=$(get_pri)
212  [ "$actual" = "$expected" ] || \
213    error 1 "expected priority \"$expected\", actual priority \"$actual\""
214}
215
216# no kernels at all. This should do nothing.
217"${CGPT}" create "${MTD[@]}" ${DEV}
218
219run_prioritize_tests() {
220  echo "Test the cgpt prioritize command..."
221  "${CGPT}" add "${MTD[@]}" -t rootfs -b 100 -s 1 ${DEV}
222  "${CGPT}" prioritize "${MTD[@]}" ${DEV}
223  assert_pri ""
224
225  # common install/upgrade sequence
226  make_pri   2 0 0
227  "${CGPT}" prioritize "${MTD[@]}" -i 1 ${DEV}
228  assert_pri 1 0 0
229  "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV}
230  assert_pri 1 2 0
231  "${CGPT}" prioritize "${MTD[@]}" -i 1 ${DEV}
232  assert_pri 2 1 0
233  "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV}
234  assert_pri 1 2 0
235  # lots of kernels, all same starting priority, should go to priority 1
236  make_pri   8 8 8 8 8 8 8 8 8 8 8 0 0 8
237  "${CGPT}" prioritize "${MTD[@]}" ${DEV}
238  assert_pri 1 1 1 1 1 1 1 1 1 1 1 0 0 1
239
240  # now raise them all up again
241  "${CGPT}" prioritize "${MTD[@]}" -P 4 ${DEV}
242  assert_pri 4 4 4 4 4 4 4 4 4 4 4 0 0 4
243
244  # set one of them higher, should leave the rest alone
245  "${CGPT}" prioritize "${MTD[@]}" -P 5 -i 3 ${DEV}
246  assert_pri 4 4 5 4 4 4 4 4 4 4 4 0 0 4
247
248  # set one of them lower, should bring the rest down
249  "${CGPT}" prioritize "${MTD[@]}" -P 3 -i 4 ${DEV}
250  assert_pri 1 1 2 3 1 1 1 1 1 1 1 0 0 1
251
252  # raise a group by including the friends of one partition
253  "${CGPT}" prioritize "${MTD[@]}" -P 6 -i 1 -f ${DEV}
254  assert_pri 6 6 4 5 6 6 6 6 6 6 6 0 0 6
255
256  # resurrect one, should not affect the others
257  make_pri   0 0 0 0 0 0 0 0 0 0 0 0 0 0
258  "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV}
259  assert_pri 0 1 0 0 0 0 0 0 0 0 0 0 0 0
260
261  # resurrect one and all its friends
262  make_pri   0 0 0 0 0 0 0 0 1 2 0 0 0 0
263  "${CGPT}" prioritize "${MTD[@]}" -P 5 -i 2 -f ${DEV}
264  assert_pri 5 5 5 5 5 5 5 5 3 4 5 5 5 5
265
266  # no options should maintain the same order
267  "${CGPT}" prioritize "${MTD[@]}" ${DEV}
268  assert_pri 3 3 3 3 3 3 3 3 1 2 3 3 3 3
269
270  # squish all the ranks
271  make_pri   1 1 2 2 3 3 4 4 5 5 0 6 7 7
272  "${CGPT}" prioritize "${MTD[@]}" -P 6 ${DEV}
273  assert_pri 1 1 1 1 2 2 3 3 4 4 0 5 6 6
274
275  # squish the ranks by not leaving room
276  make_pri   1 1 2 2 3 3 4 4 5 5 0 6 7 7
277  "${CGPT}" prioritize "${MTD[@]}" -P 7 -i 3 ${DEV}
278  assert_pri 1 1 7 1 2 2 3 3 4 4 0 5 6 6
279
280  # squish the ranks while bringing the friends along
281  make_pri   1 1 2 2 3 3 4 4 5 5 0 6 7 7
282  "${CGPT}" prioritize "${MTD[@]}" -P 6 -i 3 -f ${DEV}
283  assert_pri 1 1 6 6 1 1 2 2 3 3 0 4 5 5
284
285  # squish them pretty hard
286  make_pri   1 1 2 2 3 3 4 4 5 5 0 6 7 7
287  "${CGPT}" prioritize "${MTD[@]}" -P 2 ${DEV}
288  assert_pri 1 1 1 1 1 1 1 1 1 1 0 1 2 2
289
290  # squish them really really hard (nobody gets reduced to zero, though)
291  make_pri   1 1 2 2 3 3 4 4 5 5 0 6 7 7
292  "${CGPT}" prioritize "${MTD[@]}" -P 1 -i 3 ${DEV}
293  assert_pri 1 1 1 1 1 1 1 1 1 1 0 1 1 1
294
295  make_pri   15 15 14 14 13 13 12 12 11 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 0
296  "${CGPT}" prioritize "${MTD[@]}" -i 3 ${DEV}
297  assert_pri 14 14 15 13 12 12 11 11 10 10  9  9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 0
298  "${CGPT}" prioritize "${MTD[@]}" -i 5 ${DEV}
299  assert_pri 13 13 14 12 15 11 10 10  9  9  8  8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 1 1 0
300  # but if I bring friends I don't have to squish
301  "${CGPT}" prioritize "${MTD[@]}" -i 1 -f ${DEV}
302  assert_pri 15 15 13 12 14 11 10 10  9  9  8  8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 1 1 0
303}
304run_prioritize_tests
305
306echo "Test cgpt repair command"
307"${CGPT}" repair "${MTD[@]}" ${DEV}
308("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error
309
310# Zero primary header and partition table and try to repair it.
311dd if=/dev/zero of=${DEV} conv=notrunc bs=512 count=33 2>/dev/null
312"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID
313"${CGPT}" repair "${MTD[@]}" ${DEV}
314("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error
315
316# Zero secondary header and partition table and try to repair it.
317dd if=/dev/zero of=${DEV} seek=$((NUM_SECTORS - 33)) conv=notrunc bs=512 \
318  count=33 2>/dev/null
319"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID
320"${CGPT}" repair "${MTD[@]}" ${DEV}
321("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error
322
323echo "Test with IGNOREME primary GPT..."
324"${CGPT}" create "${MTD[@]}" ${DEV}
325"${CGPT}" legacy "${MTD[@]}" -p ${DEV}
326"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT" 2>/dev/null
327("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && \
328  error
329"${CGPT}" repair "${MTD[@]}" ${DEV} 2>/dev/null
330"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT" 2>/dev/null
331("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && \
332  error
333"${CGPT}" legacy "${MTD[@]}" -e ${DEV} 2>/dev/null
334("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT") && error
335"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table"
336
337"${CGPT}" create "${MTD[@]}" ${DEV}
338"${CGPT}" legacy "${MTD[@]}" -p ${DEV}
339run_basic_tests 2>/dev/null
340
341"${CGPT}" create "${MTD[@]}" ${DEV}
342"${CGPT}" legacy "${MTD[@]}" -p ${DEV}
343run_prioritize_tests 2>/dev/null
344
345# Now make sure that we don't need write access if we're just looking.
346echo "Test read vs read-write access..."
347chmod 0444 ${DEV}
348
349# These should fail
350"${CGPT}" create "${MTD[@]}" -z ${DEV} 2>/dev/null && error
351"${CGPT}" add "${MTD[@]}" -i 2 -P 3 ${DEV} 2>/dev/null && error
352"${CGPT}" repair "${MTD[@]}" ${DEV} 2>/dev/null && error
353"${CGPT}" prioritize "${MTD[@]}" -i 3 ${DEV} 2>/dev/null && error
354
355# Most 'boot' usage should fail too.
356"${CGPT}" boot "${MTD[@]}" -p ${DEV} 2>/dev/null && error
357dd if=/dev/zero of=fake_mbr.bin bs=100 count=1 2>/dev/null
358"${CGPT}" boot "${MTD[@]}" -b fake_mbr.bin ${DEV} 2>/dev/null && error
359"${CGPT}" boot "${MTD[@]}" -i 2 ${DEV} 2>/dev/null && error
360
361"${CGPT}" boot "${MTD[@]}" ${DEV} >/dev/null
362"${CGPT}" show "${MTD[@]}" ${DEV} >/dev/null
363"${CGPT}" find "${MTD[@]}" -t kernel ${DEV} >/dev/null
364
365# Enable write access again to test boundary in off device storage
366chmod 600 ${DEV}
367# GPT too small
368dd if=/dev/zero of=${DEV} bs=5632 count=1
369assert_fail ""${CGPT}"" create -D 1024 ${DEV}
370# GPT is just right for 16 entries (512 + 512 + 16 * 128) * 2 = 6144
371dd if=/dev/zero of=${DEV} bs=6144 count=1
372"${CGPT}" create -D 1024 ${DEV}
373# Create a small 8K file to simulate Flash NOR section
374dd if=/dev/zero of=${DEV} bs=8K count=1
375# Drive size is not multiple of 512
376assert_fail ""${CGPT}"" create -D 511 ${DEV}
377assert_fail ""${CGPT}"" create -D 513 ${DEV}
378# Create a GPT table for a device of 1024 bytes (2 sectors)
379"${CGPT}" create -D 1024 ${DEV}
380# Make sure number of entries is reasonable for 8KiB GPT
381X=$("${CGPT}" show -D 1024 -d ${DEV} | grep -c "Number of entries: 24")
382[ "$X" = "2" ] || error
383# This fails because header verification is off due to different drive size
384assert_fail ""${CGPT}"" show ${DEV}
385# But this passes because we pass in correct drive size
386"${CGPT}" show -D 1024 ${DEV}
387# This fails because beginning sector is over the size of the device
388assert_fail ""${CGPT}"" add -D 1024 -b 2 -s 1 -t data ${DEV}
389# This fails because partition size is over the size of the device
390assert_fail ""${CGPT}"" add -D 1024 -b 0 -s 3 -t data ${DEV}
391
392
393echo "Done."
394
395happy "All tests passed."
396