blob: 629c3dfd60889bce55f9b66a06ade81b15f3c0d5 [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
Sam Hurst545e5512018-06-07 11:08:46 -070042# This returns the block size of a file or device in byte
43# Invoke as: subshell
44# Args: FILENAME
45# Return: block size in bytes
46blocksize() {
47 local path="$1"
48 if [ -b "${path}" ]; then
49 local dev="${path##*/}"
50 local sys="/sys/block/${dev}/queue/logical_block_size"
51 if [ -e "${sys}" ]; then
52 cat "${sys}"
53 else
54 local part="${path##*/}"
55 local block="$(get_block_dev_from_partition_dev "${path}")"
56 local block="${block##*/}"
57 cat "/sys/block/${block}/${part}/queue/logical_block_size"
58 fi
59 else
60 echo 512
61 fi
62}
63
Bill Richardson7c358a92010-06-11 09:16:03 -070064# Locate the cgpt tool. It should already be installed in the build chroot,
robotboya7684292010-04-21 14:46:00 -070065# but some of these functions may be invoked outside the chroot (by
Bill Richardsoneff5b062010-03-30 14:17:34 -070066# image_to_usb or similar), so we need to find it.
robotboya7684292010-04-21 14:46:00 -070067GPT=""
Yusuke Satod55cea92010-04-21 10:46:59 +090068
robotboya7684292010-04-21 14:46:00 -070069locate_gpt() {
70 if [ -z "$GPT" ]; then
Bill Richardsonf67f8442010-12-01 08:27:37 -080071 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
72 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
73 else
74 GPT=$(which cgpt 2>/dev/null) || /bin/true
75 if [ -z "$GPT" ]; then
Bill Richardson7c358a92010-06-11 09:16:03 -070076 echo "can't find cgpt tool" 1>&2
robotboya7684292010-04-21 14:46:00 -070077 exit 1
78 fi
79 fi
80 fi
81}
Bill Richardsoneff5b062010-03-30 14:17:34 -070082
Bill Richardsoneff5b062010-03-30 14:17:34 -070083# Read GPT table to find the starting location of a specific partition.
84# Invoke as: subshell
85# Args: DEVICE PARTNUM
86# Returns: offset (in sectors) of partition PARTNUM
87partoffset() {
Elly Jones7f1dc652011-08-12 15:44:18 -040088 sudo $GPT show -b -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070089}
90
91# Read GPT table to find the size of a specific partition.
92# Invoke as: subshell
93# Args: DEVICE PARTNUM
94# Returns: size (in sectors) of partition PARTNUM
95partsize() {
Elly Jones7f1dc652011-08-12 15:44:18 -040096 sudo $GPT show -s -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -070097}
98
Jie Sun1f9d4122010-04-12 17:04:36 -070099# Extract the whole disk block device from the partition device.
100# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
101# (-> /dev/mmcblk0).
102get_block_dev_from_partition_dev() {
103 local partition=$1
104 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
105 echo "Invalid partition name: $partition" >&2
106 exit 1
107 fi
Will Drewry056e9c82010-08-06 16:10:59 -0500108 # Removes any trailing digits.
109 local block=$(echo "$partition" | sed -e 's/[0-9]*$//')
Jie Sun1f9d4122010-04-12 17:04:36 -0700110 # If needed, strip the trailing 'p'.
111 if (expr match "$block" ".*[0-9]p$" >/dev/null); then
112 echo "${block%p}"
113 else
114 echo "$block"
115 fi
116}
117
118# Extract the partition number from the partition device.
119# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
120get_partition_number() {
121 local partition=$1
122 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
123 echo "Invalid partition name: $partition" >&2
124 exit 1
125 fi
126 # Extract the last digit.
127 echo "$partition" | sed -e 's/^.*\([0-9]\)$/\1/'
128}
129
130# Construct a partition device name from a whole disk block device and a
131# partition number.
132# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
133# (-> /dev/mmcblk0p2).
134make_partition_dev() {
135 local block=$1
136 local num=$2
137 # If the disk block device ends with a number, we add a 'p' before the
138 # partition number.
139 if (expr match "$block" ".*[0-9]$" >/dev/null) ; then
140 echo "${block}p${num}"
141 else
142 echo "${block}${num}"
143 fi
144}
145
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700146# Return the type of device.
147#
148# The type can be:
149# MMC, SD for device managed by the MMC stack
150# ATA for ATA disk
Deepti Patildf2d2692016-03-04 15:24:58 +0530151# NVME for NVMe device
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700152# OTHER for other devices.
153get_device_type() {
154 local dev="$(basename "$1")"
155 local vdr
156 local type_file
157 local vendor_file
Deepti Patildf2d2692016-03-04 15:24:58 +0530158 # True device path of a NVMe device is just a simple PCI device.
159 # (there are no other buses),
160 # Use the device name to identify the type precisely.
161 case "${dev}" in
162 nvme*)
163 echo "NVME"
164 return
165 ;;
166 esac
167
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700168 type_file="/sys/block/${dev}/device/type"
169 # To detect device managed by the MMC stack
170 case $(readlink -f "${type_file}") in
171 *mmc*)
172 cat "${type_file}"
173 ;;
174 *usb*)
175 # Now if it contains 'usb', it is managed through
176 # a USB controller.
177 echo "USB"
178 ;;
179 *target*)
180 # Other SCSI devices.
181 # Check if it is an ATA device.
182 vdr="$(cat "/sys/block/${dev}/device/vendor")"
183 if [ "${vdr%% *}" = "ATA" ]; then
184 echo "ATA"
185 else
186 echo "OTHER"
187 fi
188 ;;
189 *)
190 echo "OTHER"
191 esac
192}
193
Gwendal Grignou732af512014-04-07 20:07:29 +0000194# ATA disk have ATA as vendor.
195# They may not contain ata in their device path if behind a SAS
196# controller.
197# Exclude disks with size 0, it means they did not spin up properly.
198list_fixed_ata_disks() {
199 local sd
200 local remo
201 local vdr
202 local size
203
204 for sd in /sys/block/sd*; do
205 if [ ! -r "${sd}/size" ]; then
206 continue
Paul Stewart04f3ef12010-05-27 15:56:42 -0700207 fi
Gwendal Grignou732af512014-04-07 20:07:29 +0000208 size=$(cat "${sd}/size")
209 remo=$(cat "${sd}/removable")
210 vdr=$(cat "${sd}/device/vendor")
211 if [ "${vdr%% *}" = "ATA" -a ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
212 echo "${sd##*/}"
213 fi
Paul Stewart04f3ef12010-05-27 15:56:42 -0700214 done
Gwendal Grignou732af512014-04-07 20:07:29 +0000215}
216
217# We assume we only have eMMC devices, not removable MMC devices.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700218# also, do not consider special hardware partitions on the eMMC, like boot.
Gwendal Grignou732af512014-04-07 20:07:29 +0000219# These devices are built on top of the eMMC sysfs path:
220# /sys/block/mmcblk0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0
221# /sys/block/mmcblk0boot0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot0
222# /sys/block/mmcblk0boot1 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot1
223# /sys/block/mmcblk0rpmb -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0rpmb
224#
225# Their device link points back to mmcblk0, not to the hardware
226# device (mmc0:0001). Therefore there is no type in their device link.
227# (it should be /device/device/type)
228list_fixed_mmc_disks() {
229 local mmc
230 local type_file
231 for mmc in /sys/block/mmcblk*; do
232 type_file="${mmc}/device/type"
233 if [ -r "${type_file}" ]; then
234 if [ "$(cat "${type_file}")" = "MMC" ]; then
235 echo "${mmc##*/}"
236 fi
237 fi
238 done
239}
240
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700241# NVMe device
242# Exclude disks with size 0, it means they did not spin up properly.
243list_fixed_nvme_disks() {
Gwendal Grignoudc0a2072017-07-11 09:57:57 -0700244 local nvme remo size nvme_base
245 local all_nvme=''
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700246
247 for nvme in /sys/block/nvme*; do
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700248 if [ ! -r "${nvme}/size" ]; then
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700249 continue
250 fi
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700251 size=$(cat "${nvme}/size")
252 remo=$(cat "${nvme}/removable")
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700253 if [ ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700254 nvme_base="${nvme##*/}"
255 # Store in all_nvme names of nvme devices, without namespace.
256 # In case of nvme device with several namespaces, we will have
257 # redundancy.
258 all_nvme="${all_nvme} ${nvme_base%n*}"
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700259 fi
260 done
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700261 echo "${all_nvme}" | tr '[:space:]' '\n' | sort -u
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700262}
263
Gwendal Grignou732af512014-04-07 20:07:29 +0000264# Find the drive to install based on the build write_cgpt.sh
265# script. If not found, return ""
266get_fixed_dst_drive() {
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700267 local dev rootdev
268
269 if [ -n "${DEFAULT_ROOTDEV}" ]; then
Gwendal Grignou732af512014-04-07 20:07:29 +0000270 # No " here, the variable may contain wildcards.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700271 for rootdev in ${DEFAULT_ROOTDEV}; do
272 dev="/dev/$(basename "${rootdev}")"
273 if [ -b "${dev}" ]; then
274 break
275 else
276 dev=""
277 fi
278 done
Congbin Guofcaade82018-01-05 15:47:56 -0800279 else
280 dev=""
Gwendal Grignou732af512014-04-07 20:07:29 +0000281 fi
282 echo "${dev}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700283}
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700284
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700285edit_mbr() {
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700286 locate_gpt
Ian Coolidge83e74322017-04-14 18:35:45 +0000287 # TODO(icoolidge): Get this from disk_layout somehow.
288 local PARTITION_NUM_EFI_SYSTEM=12
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400289 local start_esp=$(partoffset "$1" ${PARTITION_NUM_EFI_SYSTEM})
290 local num_esp_sectors=$(partsize "$1" ${PARTITION_NUM_EFI_SYSTEM})
Victor Dodonf3888602016-04-21 10:36:15 -0700291 sfdisk -X dos "${1}" <<EOF
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700292unit: sectors
293
294disk1 : start= $start_esp, size= $num_esp_sectors, Id= c, bootable
295disk2 : start= 1, size= 1, Id= ee
296EOF
297}
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700298
299install_hybrid_mbr() {
300 # Creates a hybrid MBR which points the MBR partition 1 to GPT
301 # partition 12 (ESP). This is useful on ARM boards that boot
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700302 # from MBR formatted disks only.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700303 #
304 # Currently, this code path is used principally to install to
305 # SD cards using chromeos-install run from inside the chroot.
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700306 # In that environment, `sfdisk` can be racing with udev, leading
307 # to EBUSY when it calls BLKRRPART for the target disk. We avoid
308 # the conflict by using `udevadm settle`, so that udev goes first.
309 # cf. crbug.com/343681.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700310
311 echo "Creating hybrid MBR"
312 if ! edit_mbr "${1}"; then
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700313 udevadm settle
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700314 blockdev --rereadpt "${1}"
315 fi
316}
Gwendal Grignouacb06352017-02-08 20:30:47 -0800317
318ext4_dir_encryption_supported() {
319 # Can be set in the ebuild.
320 local direncryption_enabled=false
321
322 # Return true if kernel support ext4 directory encryption.
323 ${direncryption_enabled} && \
324 ! LC_LANG=C e4crypt get_policy / | grep -qF \
325 -e "Operation not supported" \
326 -e "Inappropriate ioctl for device"
327}