Yegor Timoshenko | c2e4941 | 2018-10-07 01:58:27 +0000 | [diff] [blame] | 1 | #!/usr/bin/env bash |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 2 | # |
Patrick Georgi | 7333a11 | 2020-05-08 20:48:04 +0200 | [diff] [blame] | 3 | # SPDX-License-Identifier: GPL-2.0-only |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 4 | |
Tristan Corrick | df90c62 | 2018-12-31 20:34:36 +1300 | [diff] [blame] | 5 | # On some systems, `parted` and `debugfs` are located in /sbin. |
| 6 | export PATH="$PATH:/sbin" |
| 7 | |
Tristan Corrick | d80607d | 2018-12-31 20:54:42 +1300 | [diff] [blame] | 8 | exit_if_uninstalled() { |
| 9 | local cmd_name="$1" |
| 10 | local deb_pkg_name="$2" |
| 11 | |
| 12 | if type "$cmd_name" >/dev/null 2>&1; then |
| 13 | return |
| 14 | fi |
| 15 | |
| 16 | printf '`%s` was not found. ' "$cmd_name" >&2 |
| 17 | printf 'On Debian-based systems, it can be installed\n' >&2 |
| 18 | printf 'by running `apt install %s`.\n' "$deb_pkg_name" >&2 |
| 19 | |
| 20 | exit 1 |
| 21 | } |
| 22 | |
| 23 | exit_if_dependencies_are_missing() { |
| 24 | exit_if_uninstalled "uudecode" "sharutils" |
| 25 | exit_if_uninstalled "debugfs" "e2fsprogs" |
| 26 | exit_if_uninstalled "parted" "parted" |
| 27 | exit_if_uninstalled "curl" "curl" |
Mete Balci | 63cdea2 | 2019-03-08 11:13:45 +0000 | [diff] [blame] | 28 | exit_if_uninstalled "unzip" "unzip" |
Tristan Corrick | d80607d | 2018-12-31 20:54:42 +1300 | [diff] [blame] | 29 | } |
| 30 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 31 | get_inventory() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 32 | _conf=$1 |
| 33 | _url=https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf |
| 34 | |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 35 | echo "Downloading recovery image inventory..." |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 36 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 37 | curl -s "$_url" >$_conf |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 38 | } |
| 39 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 40 | download_image() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 41 | _url=$1 |
| 42 | _file=$2 |
| 43 | |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 44 | echo "Downloading recovery image" |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 45 | curl "$_url" >"$_file.zip" |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 46 | echo "Decompressing recovery image" |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 47 | unzip -q "$_file.zip" |
| 48 | rm "$_file.zip" |
| 49 | } |
| 50 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 51 | extract_partition() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 52 | NAME=$1 |
| 53 | FILE=$2 |
| 54 | ROOTFS=$3 |
| 55 | _bs=1024 |
| 56 | |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 57 | echo "Extracting ROOT-A partition" |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 58 | ROOTP=$(printf "unit\nB\nprint\nquit\n" | |
| 59 | parted $FILE 2>/dev/null | grep $NAME) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 60 | |
Matt DeVillier | b084449 | 2022-02-03 21:31:34 -0600 | [diff] [blame] | 61 | if [ "$ROOTP" == "" ]; then |
| 62 | # Automatic extraction failed, likely due to parted detecting |
| 63 | # overlapping partitions. Fall back to using fdisk and assume |
| 64 | # ROOT-A is partition #3 |
| 65 | echo "(Extracting via parted failed; falling back to fdisk)" |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 66 | _ssize=$(printf "p q" | fdisk $FILE | grep "Sector size" | |
Matt DeVillier | b084449 | 2022-02-03 21:31:34 -0600 | [diff] [blame] | 67 | cut -f2 -d: | cut -f2 -d ' ') |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 68 | _start=$(printf "p q" | fdisk $FILE | grep "bin3" | tr -s ' ' | |
Matt DeVillier | b084449 | 2022-02-03 21:31:34 -0600 | [diff] [blame] | 69 | cut -f2 -d ' ') |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 70 | _nsec=$(printf "p q" | fdisk $FILE | grep "bin3" | tr -s ' ' | |
Matt DeVillier | b084449 | 2022-02-03 21:31:34 -0600 | [diff] [blame] | 71 | cut -f4 -d ' ') |
| 72 | START=$(($_ssize * $_start)) |
| 73 | SIZE=$(($_ssize * $_nsec)) |
| 74 | else |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 75 | START=$(($(echo $ROOTP | cut -f2 -d\ | tr -d "B"))) |
| 76 | SIZE=$(($(echo $ROOTP | cut -f4 -d\ | tr -d "B"))) |
Matt DeVillier | b084449 | 2022-02-03 21:31:34 -0600 | [diff] [blame] | 77 | fi |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 78 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 79 | dd if=$FILE of=$ROOTFS bs=$_bs skip=$(($START / $_bs)) \ |
| 80 | count=$(($SIZE / $_bs)) >/dev/null 2>&1 |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 81 | } |
| 82 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 83 | extract_shellball() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 84 | ROOTFS=$1 |
| 85 | SHELLBALL=$2 |
| 86 | |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 87 | echo "Extracting chromeos-firmwareupdate" |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 88 | printf "cd /usr/sbin\ndump chromeos-firmwareupdate $SHELLBALL\nquit" | |
| 89 | debugfs $ROOTFS >/dev/null 2>&1 |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 90 | } |
| 91 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 92 | extract_coreboot() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 93 | _shellball=$1 |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 94 | _unpacked=$(mktemp -d) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 95 | |
Tristan Corrick | f50bd6d | 2018-12-31 20:58:43 +1300 | [diff] [blame] | 96 | echo "Extracting coreboot image" |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 97 | if ! sh $_shellball --unpack $_unpacked >/dev/null 2>&1; then |
| 98 | sh $_shellball --sb_extract $_unpacked >/dev/null 2>&1 |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 99 | fi |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 100 | |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 101 | if [ -d $_unpacked/models/ ]; then |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 102 | _version=$(cat $_unpacked/VERSION | grep -m 1 -e Model.*$_board -A5 | |
| 103 | grep "BIOS (RW) version:" | cut -f2 -d: | tr -d \ ) |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 104 | if [ "$_version" == "" ]; then |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 105 | _version=$(cat $_unpacked/VERSION | grep -m 1 -e Model.*$_board -A5 | |
| 106 | grep "BIOS version:" | cut -f2 -d: | tr -d \ ) |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 107 | fi |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 108 | _bios_image=$(grep "IMAGE_MAIN" $_unpacked/models/$_board/setvars.sh | |
| 109 | cut -f2 -d\") |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 110 | else |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 111 | _version=$(cat $_unpacked/VERSION | grep BIOS\ version: | |
| 112 | cut -f2 -d: | tr -d \ ) |
Matt DeVillier | e427316 | 2022-02-03 19:18:29 -0600 | [diff] [blame] | 113 | _bios_image=bios.bin |
| 114 | fi |
| 115 | if cp $_unpacked/$_bios_image coreboot-$_version.bin; then |
| 116 | echo "Extracted coreboot-$_version.bin" |
| 117 | fi |
| 118 | rm -rf "$_unpacked" |
| 119 | rm $_shellball |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 120 | } |
| 121 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 122 | do_one_board() { |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 123 | _board=$1 |
| 124 | _url=$2 |
| 125 | _file=$3 |
| 126 | |
| 127 | download_image $_url $_file |
| 128 | |
| 129 | extract_partition ROOT-A $_file root-a.ext2 |
| 130 | extract_shellball root-a.ext2 chromeos-firmwareupdate-$_board |
| 131 | rm $_file root-a.ext2 |
| 132 | |
| 133 | extract_coreboot chromeos-firmwareupdate-$_board |
| 134 | } |
| 135 | |
| 136 | # |
| 137 | # Main |
| 138 | # |
| 139 | |
Matt DeVillier | 5470ae7 | 2024-05-07 08:40:41 -0500 | [diff] [blame] | 140 | BOARD=${1,,} |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 141 | |
Tristan Corrick | d80607d | 2018-12-31 20:54:42 +1300 | [diff] [blame] | 142 | exit_if_dependencies_are_missing |
| 143 | |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 144 | if [ "$BOARD" == "all" ]; then |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 145 | CONF=$(mktemp) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 146 | get_inventory $CONF |
| 147 | |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 148 | grep ^name= $CONF | while read _line; do |
| 149 | name=$(echo $_line | cut -f2 -d=) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 150 | echo Processing board $name |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 151 | eval $(grep -v hwid= $CONF | grep -A11 "$_line" | |
| 152 | grep '\(url=\|file=\)') |
| 153 | BOARD=$(echo $url | cut -f3 -d_) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 154 | do_one_board $BOARD $url $file |
| 155 | done |
| 156 | |
| 157 | rm "$CONF" |
| 158 | elif [ "$BOARD" != "" ]; then |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 159 | CONF=$(mktemp) |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 160 | get_inventory $CONF |
| 161 | |
| 162 | echo Processing board $BOARD |
Matt DeVillier | 1dc1a56 | 2022-02-03 21:43:00 -0600 | [diff] [blame] | 163 | eval $(grep -i $BOARD -A8 $CONF | grep '\(url=\|file=\)') |
Joe Pillow | 9a4881a | 2016-02-19 15:18:14 -0800 | [diff] [blame] | 164 | do_one_board $BOARD $url $file |
| 165 | |
| 166 | rm "$CONF" |
| 167 | else |
| 168 | echo "Usage: $0 <boardname>" |
| 169 | echo " $0 all" |
| 170 | echo |
| 171 | exit 1 |
| 172 | fi |