blob: 672b34ff2cb7b83fca2e0fb00631d76ce57f12ac [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
15# This returns the size of a file or device in 512-byte sectors, rounded up if
16# needed.
17# Invoke as: subshell
18# Args: FILENAME
19# Return: whole number of sectors needed to fully contain FILENAME
20numsectors() {
Jie Sun1f9d4122010-04-12 17:04:36 -070021 if [ -b "${1}" ]; then
Bill Richardsoneff5b062010-03-30 14:17:34 -070022 dev=${1##*/}
Jie Sun1f9d4122010-04-12 17:04:36 -070023 if [ -e /sys/block/$dev/size ]; then
24 cat /sys/block/$dev/size
25 else
26 part=${1##*/}
27 block=$(get_block_dev_from_partition_dev "${1}")
28 block=${block##*/}
29 cat /sys/block/$block/$part/size
30 fi
31 else
Bill Richardsoneff5b062010-03-30 14:17:34 -070032 local bytes=$(stat -c%s "$1")
33 local sectors=$(( $bytes / 512 ))
34 local rem=$(( $bytes % 512 ))
35 if [ $rem -ne 0 ]; then
36 sectors=$(( $sectors + 1 ))
37 fi
38 echo $sectors
Jie Sun1f9d4122010-04-12 17:04:36 -070039 fi
Bill Richardsoneff5b062010-03-30 14:17:34 -070040}
41
Bill Richardson7c358a92010-06-11 09:16:03 -070042# Locate the cgpt tool. It should already be installed in the build chroot,
robotboya7684292010-04-21 14:46:00 -070043# but some of these functions may be invoked outside the chroot (by
Bill Richardsoneff5b062010-03-30 14:17:34 -070044# image_to_usb or similar), so we need to find it.
robotboya7684292010-04-21 14:46:00 -070045GPT=""
Yusuke Satod55cea92010-04-21 10:46:59 +090046
robotboya7684292010-04-21 14:46:00 -070047locate_gpt() {
48 if [ -z "$GPT" ]; then
Bill Richardsonf67f8442010-12-01 08:27:37 -080049 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
50 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
51 else
52 GPT=$(which cgpt 2>/dev/null) || /bin/true
53 if [ -z "$GPT" ]; then
Bill Richardson7c358a92010-06-11 09:16:03 -070054 echo "can't find cgpt tool" 1>&2
robotboya7684292010-04-21 14:46:00 -070055 exit 1
56 fi
57 fi
58 fi
59}
Bill Richardsoneff5b062010-03-30 14:17:34 -070060
Bill Richardsoneff5b062010-03-30 14:17:34 -070061# Read GPT table to find the starting location of a specific partition.
62# Invoke as: subshell
63# Args: DEVICE PARTNUM
64# Returns: offset (in sectors) of partition PARTNUM
65partoffset() {
Elly Jones7f1dc652011-08-12 15:44:18 -040066 sudo $GPT show -b -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070067}
68
69# Read GPT table to find the size of a specific partition.
70# Invoke as: subshell
71# Args: DEVICE PARTNUM
72# Returns: size (in sectors) of partition PARTNUM
73partsize() {
Elly Jones7f1dc652011-08-12 15:44:18 -040074 sudo $GPT show -s -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070075}
76
Jie Sun1f9d4122010-04-12 17:04:36 -070077# Extract the whole disk block device from the partition device.
78# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
79# (-> /dev/mmcblk0).
80get_block_dev_from_partition_dev() {
81 local partition=$1
82 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
83 echo "Invalid partition name: $partition" >&2
84 exit 1
85 fi
Will Drewry056e9c82010-08-06 16:10:59 -050086 # Removes any trailing digits.
87 local block=$(echo "$partition" | sed -e 's/[0-9]*$//')
Jie Sun1f9d4122010-04-12 17:04:36 -070088 # If needed, strip the trailing 'p'.
89 if (expr match "$block" ".*[0-9]p$" >/dev/null); then
90 echo "${block%p}"
91 else
92 echo "$block"
93 fi
94}
95
96# Extract the partition number from the partition device.
97# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
98get_partition_number() {
99 local partition=$1
100 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
101 echo "Invalid partition name: $partition" >&2
102 exit 1
103 fi
104 # Extract the last digit.
105 echo "$partition" | sed -e 's/^.*\([0-9]\)$/\1/'
106}
107
108# Construct a partition device name from a whole disk block device and a
109# partition number.
110# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
111# (-> /dev/mmcblk0p2).
112make_partition_dev() {
113 local block=$1
114 local num=$2
115 # If the disk block device ends with a number, we add a 'p' before the
116 # partition number.
117 if (expr match "$block" ".*[0-9]$" >/dev/null) ; then
118 echo "${block}p${num}"
119 else
120 echo "${block}${num}"
121 fi
122}
123
Gwendal Grignou732af512014-04-07 20:07:29 +0000124# List target devices functions.
Paul Stewart04f3ef12010-05-27 15:56:42 -0700125list_usb_disks() {
126 local sd
Gwendal Grignou732af512014-04-07 20:07:29 +0000127 local remo
128 local size
129
Paul Stewart04f3ef12010-05-27 15:56:42 -0700130 for sd in /sys/block/sd*; do
Gwendal Grignou732af512014-04-07 20:07:29 +0000131 if [ ! -r "${sd}/size" ]; then
132 continue
133 fi
134 size=$(cat "${sd}/size")
135 remo=$(cat "${sd}/removable")
Paul Stewart248f4642010-06-09 10:11:15 -0700136 if readlink -f ${sd}/device | grep -q usb &&
Gwendal Grignou732af512014-04-07 20:07:29 +0000137 [ ${remo:-0} -eq 1 -a ${size:-0} -gt 0 ]; then
138 echo "${sd##*/}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700139 fi
140 done
141}
142
Gwendal Grignou732af512014-04-07 20:07:29 +0000143# list mmc devices, including sd cards (for installation support candidates).
Mario Limonciello80d52762011-05-24 19:30:55 -0500144list_mmc_disks() {
145 local mmc
146 for mmc in /sys/block/mmcblk*; do
Gwendal Grignou732af512014-04-07 20:07:29 +0000147 # We only select deivce that are 1GB or larger.
148 if [ "$(cat "${mmc}/size")" -ge 2097152 ]; then
149 echo "${mmc##*/}"
Mario Limonciello80d52762011-05-24 19:30:55 -0500150 fi
151 done
152}
153
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700154# Return the type of device.
155#
156# The type can be:
157# MMC, SD for device managed by the MMC stack
158# ATA for ATA disk
159# OTHER for other devices.
160get_device_type() {
161 local dev="$(basename "$1")"
162 local vdr
163 local type_file
164 local vendor_file
165 type_file="/sys/block/${dev}/device/type"
166 # To detect device managed by the MMC stack
167 case $(readlink -f "${type_file}") in
168 *mmc*)
169 cat "${type_file}"
170 ;;
171 *usb*)
172 # Now if it contains 'usb', it is managed through
173 # a USB controller.
174 echo "USB"
175 ;;
176 *target*)
177 # Other SCSI devices.
178 # Check if it is an ATA device.
179 vdr="$(cat "/sys/block/${dev}/device/vendor")"
180 if [ "${vdr%% *}" = "ATA" ]; then
181 echo "ATA"
182 else
183 echo "OTHER"
184 fi
185 ;;
186 *)
187 echo "OTHER"
188 esac
189}
190
Gwendal Grignou732af512014-04-07 20:07:29 +0000191# ATA disk have ATA as vendor.
192# They may not contain ata in their device path if behind a SAS
193# controller.
194# Exclude disks with size 0, it means they did not spin up properly.
195list_fixed_ata_disks() {
196 local sd
197 local remo
198 local vdr
199 local size
200
201 for sd in /sys/block/sd*; do
202 if [ ! -r "${sd}/size" ]; then
203 continue
Paul Stewart04f3ef12010-05-27 15:56:42 -0700204 fi
Gwendal Grignou732af512014-04-07 20:07:29 +0000205 size=$(cat "${sd}/size")
206 remo=$(cat "${sd}/removable")
207 vdr=$(cat "${sd}/device/vendor")
208 if [ "${vdr%% *}" = "ATA" -a ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
209 echo "${sd##*/}"
210 fi
Paul Stewart04f3ef12010-05-27 15:56:42 -0700211 done
Gwendal Grignou732af512014-04-07 20:07:29 +0000212}
213
214# We assume we only have eMMC devices, not removable MMC devices.
215# also, do not consider special hardware partitions non the eMMC, like boot.
216# These devices are built on top of the eMMC sysfs path:
217# /sys/block/mmcblk0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0
218# /sys/block/mmcblk0boot0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot0
219# /sys/block/mmcblk0boot1 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot1
220# /sys/block/mmcblk0rpmb -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0rpmb
221#
222# Their device link points back to mmcblk0, not to the hardware
223# device (mmc0:0001). Therefore there is no type in their device link.
224# (it should be /device/device/type)
225list_fixed_mmc_disks() {
226 local mmc
227 local type_file
228 for mmc in /sys/block/mmcblk*; do
229 type_file="${mmc}/device/type"
230 if [ -r "${type_file}" ]; then
231 if [ "$(cat "${type_file}")" = "MMC" ]; then
232 echo "${mmc##*/}"
233 fi
234 fi
235 done
236}
237
238# Find the drive to install based on the build write_cgpt.sh
239# script. If not found, return ""
240get_fixed_dst_drive() {
241 local dev
242 if [ -z "${DEFAULT_ROOTDEV}" ]; then
243 dev=""
244 else
245 # No " here, the variable may contain wildcards.
246 dev="/dev/$(basename ${DEFAULT_ROOTDEV})"
247 if [ ! -b "${dev}" ]; then
248 # The device is not found
249 dev=""
250 fi
251 fi
252 echo "${dev}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700253}
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700254
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700255legacy_offset_size_export() {
256 # Exports all the variables that install_gpt did previously.
257 # This should disappear eventually, but it's here to make existing
258 # code work for now.
259
260 START_STATEFUL=$(partoffset $1 1)
261 START_KERN_A=$(partoffset $1 2)
262 START_ROOTFS_A=$(partoffset $1 3)
263 START_KERN_B=$(partoffset $1 4)
Mike Frysinger9a715bf2012-09-24 18:47:05 -0400264 START_ROOTFS_B=$(partoffset $1 5)
Liam McLoughlin87aa6982012-08-13 13:49:34 -0700265 START_OEM=$(partoffset $1 8)
266 START_RWFW=$(partoffset $1 11)
267 START_ESP=$(partoffset $1 12)
268
269 NUM_STATEFUL_SECTORS=$(partsize $1 1)
270 NUM_KERN_SECTORS=$(partsize $1 2)
271 NUM_ROOTFS_SECTORS=$(partsize $1 3)
272 NUM_OEM_SECTORS=$(partsize $1 8)
273 NUM_RWFW_SECTORS=$(partsize $1 11)
274 NUM_ESP_SECTORS=$(partsize $1 12)
275
276 STATEFUL_IMG_SECTORS=$(partsize $1 1)
277 KERNEL_IMG_SECTORS=$(partsize $1 2)
278 ROOTFS_IMG_SECTORS=$(partsize $1 3)
279 OEM_IMG_SECTORS=$(partsize $1 8)
280 ESP_IMG_SECTORS=$(partsize $1 12)
281}
282
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700283install_hybrid_mbr() {
284 # Creates a hybrid MBR which points the MBR partition 1 to GPT
285 # partition 12 (ESP). This is useful on ARM boards that boot
286 # from MBR formatted disks only
Alex Millera4e15ba2013-12-05 17:58:37 -0800287 echo "Creating hybrid MBR"
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700288 locate_gpt
289 local start_esp=$(partoffset "$1" 12)
290 local num_esp_sectors=$(partsize "$1" 12)
291 sudo sfdisk "${1}" <<EOF
292unit: sectors
293
294disk1 : start= $start_esp, size= $num_esp_sectors, Id= c, bootable
295disk2 : start= 1, size= 1, Id= ee
296EOF
297}