blob: 02e790a881ffb1b4769cba52e66b814aaaf01182 [file] [log] [blame]
Mike Frysinger1963df12013-06-03 14:01:35 -04001#!/bin/sh
Bill Richardsoneff5b062010-03-30 14:17:34 -07002# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5#
6# This contains common constants and functions for installer scripts. This must
7# evaluate properly for both /bin/bash and /bin/sh, since it's used both to
8# create the initial image at compile time and to install or upgrade a running
9# image.
10
Bill Richardsoneff5b062010-03-30 14:17:34 -070011# The GPT tables describe things in terms of 512-byte sectors, but some
12# filesystems prefer 4096-byte blocks. These functions help with alignment
13# issues.
14
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -040015PARTITION_NUM_STATE=1
16PARTITION_NUM_KERN_A=2
17PARTITION_NUM_ROOT_A=3
18PARTITION_NUM_KERN_B=4
19PARTITION_NUM_ROOT_B=5
20PARTITION_NUM_KERN_C=6
21PARTITION_NUM_ROOT_C=7
22PARTITION_NUM_OEM=8
23PARTITION_NUM_RWFW=11
24PARTITION_NUM_EFI_SYSTEM=12
25
Bill Richardsoneff5b062010-03-30 14:17:34 -070026# This returns the size of a file or device in 512-byte sectors, rounded up if
27# needed.
28# Invoke as: subshell
29# Args: FILENAME
30# Return: whole number of sectors needed to fully contain FILENAME
31numsectors() {
Jie Sun1f9d4122010-04-12 17:04:36 -070032 if [ -b "${1}" ]; then
Bill Richardsoneff5b062010-03-30 14:17:34 -070033 dev=${1##*/}
Jie Sun1f9d4122010-04-12 17:04:36 -070034 if [ -e /sys/block/$dev/size ]; then
35 cat /sys/block/$dev/size
36 else
37 part=${1##*/}
38 block=$(get_block_dev_from_partition_dev "${1}")
39 block=${block##*/}
40 cat /sys/block/$block/$part/size
41 fi
42 else
Bill Richardsoneff5b062010-03-30 14:17:34 -070043 local bytes=$(stat -c%s "$1")
44 local sectors=$(( $bytes / 512 ))
45 local rem=$(( $bytes % 512 ))
46 if [ $rem -ne 0 ]; then
47 sectors=$(( $sectors + 1 ))
48 fi
49 echo $sectors
Jie Sun1f9d4122010-04-12 17:04:36 -070050 fi
Bill Richardsoneff5b062010-03-30 14:17:34 -070051}
52
Bill Richardson7c358a92010-06-11 09:16:03 -070053# Locate the cgpt tool. It should already be installed in the build chroot,
robotboya7684292010-04-21 14:46:00 -070054# but some of these functions may be invoked outside the chroot (by
Bill Richardsoneff5b062010-03-30 14:17:34 -070055# image_to_usb or similar), so we need to find it.
robotboya7684292010-04-21 14:46:00 -070056GPT=""
Yusuke Satod55cea92010-04-21 10:46:59 +090057
robotboya7684292010-04-21 14:46:00 -070058locate_gpt() {
59 if [ -z "$GPT" ]; then
Bill Richardsonf67f8442010-12-01 08:27:37 -080060 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
61 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
62 else
63 GPT=$(which cgpt 2>/dev/null) || /bin/true
64 if [ -z "$GPT" ]; then
Bill Richardson7c358a92010-06-11 09:16:03 -070065 echo "can't find cgpt tool" 1>&2
robotboya7684292010-04-21 14:46:00 -070066 exit 1
67 fi
68 fi
69 fi
70}
Bill Richardsoneff5b062010-03-30 14:17:34 -070071
Bill Richardsoneff5b062010-03-30 14:17:34 -070072# Read GPT table to find the starting location of a specific partition.
73# Invoke as: subshell
74# Args: DEVICE PARTNUM
75# Returns: offset (in sectors) of partition PARTNUM
76partoffset() {
Elly Jones7f1dc652011-08-12 15:44:18 -040077 sudo $GPT show -b -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070078}
79
80# Read GPT table to find the size of a specific partition.
81# Invoke as: subshell
82# Args: DEVICE PARTNUM
83# Returns: size (in sectors) of partition PARTNUM
84partsize() {
Elly Jones7f1dc652011-08-12 15:44:18 -040085 sudo $GPT show -s -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070086}
87
Jie Sun1f9d4122010-04-12 17:04:36 -070088# Extract the whole disk block device from the partition device.
89# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
90# (-> /dev/mmcblk0).
91get_block_dev_from_partition_dev() {
92 local partition=$1
93 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
94 echo "Invalid partition name: $partition" >&2
95 exit 1
96 fi
Will Drewry056e9c82010-08-06 16:10:59 -050097 # Removes any trailing digits.
98 local block=$(echo "$partition" | sed -e 's/[0-9]*$//')
Jie Sun1f9d4122010-04-12 17:04:36 -070099 # If needed, strip the trailing 'p'.
100 if (expr match "$block" ".*[0-9]p$" >/dev/null); then
101 echo "${block%p}"
102 else
103 echo "$block"
104 fi
105}
106
107# Extract the partition number from the partition device.
108# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
109get_partition_number() {
110 local partition=$1
111 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
112 echo "Invalid partition name: $partition" >&2
113 exit 1
114 fi
115 # Extract the last digit.
116 echo "$partition" | sed -e 's/^.*\([0-9]\)$/\1/'
117}
118
119# Construct a partition device name from a whole disk block device and a
120# partition number.
121# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
122# (-> /dev/mmcblk0p2).
123make_partition_dev() {
124 local block=$1
125 local num=$2
126 # If the disk block device ends with a number, we add a 'p' before the
127 # partition number.
128 if (expr match "$block" ".*[0-9]$" >/dev/null) ; then
129 echo "${block}p${num}"
130 else
131 echo "${block}${num}"
132 fi
133}
134
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700135# Return the type of device.
136#
137# The type can be:
138# MMC, SD for device managed by the MMC stack
139# ATA for ATA disk
Deepti Patildf2d2692016-03-04 15:24:58 +0530140# NVME for NVMe device
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700141# OTHER for other devices.
142get_device_type() {
143 local dev="$(basename "$1")"
144 local vdr
145 local type_file
146 local vendor_file
Deepti Patildf2d2692016-03-04 15:24:58 +0530147 # True device path of a NVMe device is just a simple PCI device.
148 # (there are no other buses),
149 # Use the device name to identify the type precisely.
150 case "${dev}" in
151 nvme*)
152 echo "NVME"
153 return
154 ;;
155 esac
156
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700157 type_file="/sys/block/${dev}/device/type"
158 # To detect device managed by the MMC stack
159 case $(readlink -f "${type_file}") in
160 *mmc*)
161 cat "${type_file}"
162 ;;
163 *usb*)
164 # Now if it contains 'usb', it is managed through
165 # a USB controller.
166 echo "USB"
167 ;;
168 *target*)
169 # Other SCSI devices.
170 # Check if it is an ATA device.
171 vdr="$(cat "/sys/block/${dev}/device/vendor")"
172 if [ "${vdr%% *}" = "ATA" ]; then
173 echo "ATA"
174 else
175 echo "OTHER"
176 fi
177 ;;
178 *)
179 echo "OTHER"
180 esac
181}
182
Gwendal Grignou732af512014-04-07 20:07:29 +0000183# ATA disk have ATA as vendor.
184# They may not contain ata in their device path if behind a SAS
185# controller.
186# Exclude disks with size 0, it means they did not spin up properly.
187list_fixed_ata_disks() {
188 local sd
189 local remo
190 local vdr
191 local size
192
193 for sd in /sys/block/sd*; do
194 if [ ! -r "${sd}/size" ]; then
195 continue
Paul Stewart04f3ef12010-05-27 15:56:42 -0700196 fi
Gwendal Grignou732af512014-04-07 20:07:29 +0000197 size=$(cat "${sd}/size")
198 remo=$(cat "${sd}/removable")
199 vdr=$(cat "${sd}/device/vendor")
200 if [ "${vdr%% *}" = "ATA" -a ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
201 echo "${sd##*/}"
202 fi
Paul Stewart04f3ef12010-05-27 15:56:42 -0700203 done
Gwendal Grignou732af512014-04-07 20:07:29 +0000204}
205
206# We assume we only have eMMC devices, not removable MMC devices.
207# also, do not consider special hardware partitions non the eMMC, like boot.
208# These devices are built on top of the eMMC sysfs path:
209# /sys/block/mmcblk0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0
210# /sys/block/mmcblk0boot0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot0
211# /sys/block/mmcblk0boot1 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot1
212# /sys/block/mmcblk0rpmb -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0rpmb
213#
214# Their device link points back to mmcblk0, not to the hardware
215# device (mmc0:0001). Therefore there is no type in their device link.
216# (it should be /device/device/type)
217list_fixed_mmc_disks() {
218 local mmc
219 local type_file
220 for mmc in /sys/block/mmcblk*; do
221 type_file="${mmc}/device/type"
222 if [ -r "${type_file}" ]; then
223 if [ "$(cat "${type_file}")" = "MMC" ]; then
224 echo "${mmc##*/}"
225 fi
226 fi
227 done
228}
229
230# Find the drive to install based on the build write_cgpt.sh
231# script. If not found, return ""
232get_fixed_dst_drive() {
233 local dev
234 if [ -z "${DEFAULT_ROOTDEV}" ]; then
235 dev=""
236 else
237 # No " here, the variable may contain wildcards.
238 dev="/dev/$(basename ${DEFAULT_ROOTDEV})"
239 if [ ! -b "${dev}" ]; then
240 # The device is not found
241 dev=""
242 fi
243 fi
244 echo "${dev}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700245}
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700246
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700247legacy_offset_size_export() {
248 # Exports all the variables that install_gpt did previously.
249 # This should disappear eventually, but it's here to make existing
250 # code work for now.
251
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400252 START_STATEFUL=$(partoffset $1 ${PARTITION_NUM_STATE})
253 START_KERN_A=$(partoffset $1 ${PARTITION_NUM_KERN_A})
254 START_ROOTFS_A=$(partoffset $1 ${PARTITION_NUM_ROOT_A})
255 START_KERN_B=$(partoffset $1 ${PARTITION_NUM_KERN_B})
256 START_ROOTFS_B=$(partoffset $1 ${PARTITION_NUM_ROOT_B})
257 START_OEM=$(partoffset $1 ${PARTITION_NUM_OEM})
258 START_RWFW=$(partoffset $1 ${PARTITION_NUM_RWFW})
259 START_ESP=$(partoffset $1 ${PARTITION_NUM_EFI_SYSTEM})
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700260
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400261 NUM_STATEFUL_SECTORS=$(partsize $1 ${PARTITION_NUM_STATE})
262 NUM_KERN_SECTORS=$(partsize $1 ${PARTITION_NUM_KERN_A})
263 NUM_ROOTFS_SECTORS=$(partsize $1 ${PARTITION_NUM_ROOT_A})
264 NUM_OEM_SECTORS=$(partsize $1 ${PARTITION_NUM_OEM})
265 NUM_RWFW_SECTORS=$(partsize $1 ${PARTITION_NUM_RWFW})
266 NUM_ESP_SECTORS=$(partsize $1 ${PARTITION_NUM_EFI_SYSTEM})
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700267
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400268 STATEFUL_IMG_SECTORS=$(partsize $1 ${PARTITION_NUM_STATE})
269 KERNEL_IMG_SECTORS=$(partsize $1 ${PARTITION_NUM_KERN_A})
270 ROOTFS_IMG_SECTORS=$(partsize $1 ${PARTITION_NUM_ROOT_A})
271 OEM_IMG_SECTORS=$(partsize $1 ${PARTITION_NUM_OEM})
272 ESP_IMG_SECTORS=$(partsize $1 ${PARTITION_NUM_EFI_SYSTEM})
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700273}
274
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700275edit_mbr() {
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700276 locate_gpt
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400277 local start_esp=$(partoffset "$1" ${PARTITION_NUM_EFI_SYSTEM})
278 local num_esp_sectors=$(partsize "$1" ${PARTITION_NUM_EFI_SYSTEM})
Victor Dodonf3888602016-04-21 10:36:15 -0700279 sfdisk -X dos "${1}" <<EOF
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700280unit: sectors
281
282disk1 : start= $start_esp, size= $num_esp_sectors, Id= c, bootable
283disk2 : start= 1, size= 1, Id= ee
284EOF
285}
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700286
287install_hybrid_mbr() {
288 # Creates a hybrid MBR which points the MBR partition 1 to GPT
289 # partition 12 (ESP). This is useful on ARM boards that boot
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700290 # from MBR formatted disks only.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700291 #
292 # Currently, this code path is used principally to install to
293 # SD cards using chromeos-install run from inside the chroot.
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700294 # In that environment, `sfdisk` can be racing with udev, leading
295 # to EBUSY when it calls BLKRRPART for the target disk. We avoid
296 # the conflict by using `udevadm settle`, so that udev goes first.
297 # cf. crbug.com/343681.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700298
299 echo "Creating hybrid MBR"
300 if ! edit_mbr "${1}"; then
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700301 udevadm settle
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700302 blockdev --rereadpt "${1}"
303 fi
304}