blob: 219fa706664a17273c12984e6820e1900f0bb3fb [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
Micah Mortone615bc32018-06-06 09:30:13 -070015# Call sudo when not root already. Otherwise, add usual path before calling a
16# command, as sudo does.
17# This way we avoid using sudo when running on a device in verified mode.
18maybe_sudo() {
19 if [ "${UID:-$(id -u)}" = "0" ]; then
20 PATH="${PATH}:/sbin:/usr/sbin" "$@"
21 else
22 sudo "$@"
23 fi
24}
25
Sam Hurstc8e17172018-06-29 14:18:07 -070026# This returns the size of a file or device in physical sectors, rounded up if
Bill Richardsoneff5b062010-03-30 14:17:34 -070027# needed.
28# Invoke as: subshell
29# Args: FILENAME
30# Return: whole number of sectors needed to fully contain FILENAME
31numsectors() {
Sam Hurstc8e17172018-06-29 14:18:07 -070032 local block_size
33 local sectors
34 local path="$1"
35
36 if [ -b "${path}" ]; then
37 local dev="${path##*/}"
38 block_size="$(blocksize "${path}")"
39
40 if [ -e "/sys/block/${dev}/size" ]; then
41 sectors="$(cat "/sys/block/${dev}/size")"
Jie Sun1f9d4122010-04-12 17:04:36 -070042 else
Sam Hurstc8e17172018-06-29 14:18:07 -070043 part="${path##*/}"
44 block="$(get_block_dev_from_partition_dev "${path}")"
45 block="${block##*/}"
46 sectors="$(cat "/sys/block/${block}/${part}/size")"
Jie Sun1f9d4122010-04-12 17:04:36 -070047 fi
48 else
Sam Hurstc8e17172018-06-29 14:18:07 -070049 local bytes="$(stat -c%s "${path}")"
50 local rem=$(( bytes % 512 ))
51 block_size=512
52 sectors=$(( bytes / 512 ))
53 if [ "${rem}" -ne 0 ]; then
54 sectors=$(( sectors + 1 ))
Bill Richardsoneff5b062010-03-30 14:17:34 -070055 fi
Jie Sun1f9d4122010-04-12 17:04:36 -070056 fi
Sam Hurstc8e17172018-06-29 14:18:07 -070057
58 echo $(( sectors * 512 / block_size ))
Bill Richardsoneff5b062010-03-30 14:17:34 -070059}
60
Sam Hurst545e5512018-06-07 11:08:46 -070061# This returns the block size of a file or device in byte
62# Invoke as: subshell
63# Args: FILENAME
64# Return: block size in bytes
65blocksize() {
66 local path="$1"
67 if [ -b "${path}" ]; then
68 local dev="${path##*/}"
69 local sys="/sys/block/${dev}/queue/logical_block_size"
70 if [ -e "${sys}" ]; then
71 cat "${sys}"
72 else
73 local part="${path##*/}"
74 local block="$(get_block_dev_from_partition_dev "${path}")"
75 local block="${block##*/}"
76 cat "/sys/block/${block}/${part}/queue/logical_block_size"
77 fi
78 else
79 echo 512
80 fi
81}
82
Bill Richardson7c358a92010-06-11 09:16:03 -070083# Locate the cgpt tool. It should already be installed in the build chroot,
robotboya7684292010-04-21 14:46:00 -070084# but some of these functions may be invoked outside the chroot (by
Bill Richardsoneff5b062010-03-30 14:17:34 -070085# image_to_usb or similar), so we need to find it.
robotboya7684292010-04-21 14:46:00 -070086GPT=""
Yusuke Satod55cea92010-04-21 10:46:59 +090087
robotboya7684292010-04-21 14:46:00 -070088locate_gpt() {
89 if [ -z "$GPT" ]; then
Bill Richardsonf67f8442010-12-01 08:27:37 -080090 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
91 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
92 else
93 GPT=$(which cgpt 2>/dev/null) || /bin/true
94 if [ -z "$GPT" ]; then
Bill Richardson7c358a92010-06-11 09:16:03 -070095 echo "can't find cgpt tool" 1>&2
robotboya7684292010-04-21 14:46:00 -070096 exit 1
97 fi
98 fi
99 fi
100}
Bill Richardsoneff5b062010-03-30 14:17:34 -0700101
Bill Richardsoneff5b062010-03-30 14:17:34 -0700102# Read GPT table to find the starting location of a specific partition.
103# Invoke as: subshell
104# Args: DEVICE PARTNUM
105# Returns: offset (in sectors) of partition PARTNUM
106partoffset() {
Micah Mortone615bc32018-06-06 09:30:13 -0700107 maybe_sudo $GPT show -b -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -0700108}
109
110# Read GPT table to find the size of a specific partition.
111# Invoke as: subshell
112# Args: DEVICE PARTNUM
113# Returns: size (in sectors) of partition PARTNUM
114partsize() {
Micah Mortone615bc32018-06-06 09:30:13 -0700115 maybe_sudo $GPT show -s -i $2 $1
Bill Richardsoneff5b062010-03-30 14:17:34 -0700116}
117
Jie Sun1f9d4122010-04-12 17:04:36 -0700118# Extract the whole disk block device from the partition device.
119# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
120# (-> /dev/mmcblk0).
121get_block_dev_from_partition_dev() {
122 local partition=$1
123 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
124 echo "Invalid partition name: $partition" >&2
125 exit 1
126 fi
Will Drewry056e9c82010-08-06 16:10:59 -0500127 # Removes any trailing digits.
128 local block=$(echo "$partition" | sed -e 's/[0-9]*$//')
Jie Sun1f9d4122010-04-12 17:04:36 -0700129 # If needed, strip the trailing 'p'.
130 if (expr match "$block" ".*[0-9]p$" >/dev/null); then
131 echo "${block%p}"
132 else
133 echo "$block"
134 fi
135}
136
137# Extract the partition number from the partition device.
138# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
139get_partition_number() {
140 local partition=$1
141 if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
142 echo "Invalid partition name: $partition" >&2
143 exit 1
144 fi
145 # Extract the last digit.
146 echo "$partition" | sed -e 's/^.*\([0-9]\)$/\1/'
147}
148
149# Construct a partition device name from a whole disk block device and a
150# partition number.
151# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
152# (-> /dev/mmcblk0p2).
153make_partition_dev() {
154 local block=$1
155 local num=$2
156 # If the disk block device ends with a number, we add a 'p' before the
157 # partition number.
158 if (expr match "$block" ".*[0-9]$" >/dev/null) ; then
159 echo "${block}p${num}"
160 else
161 echo "${block}${num}"
162 fi
163}
164
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700165# Return the type of device.
166#
167# The type can be:
168# MMC, SD for device managed by the MMC stack
169# ATA for ATA disk
Deepti Patildf2d2692016-03-04 15:24:58 +0530170# NVME for NVMe device
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700171# OTHER for other devices.
172get_device_type() {
173 local dev="$(basename "$1")"
174 local vdr
175 local type_file
176 local vendor_file
Deepti Patildf2d2692016-03-04 15:24:58 +0530177 # True device path of a NVMe device is just a simple PCI device.
178 # (there are no other buses),
179 # Use the device name to identify the type precisely.
180 case "${dev}" in
181 nvme*)
182 echo "NVME"
183 return
184 ;;
185 esac
186
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700187 type_file="/sys/block/${dev}/device/type"
188 # To detect device managed by the MMC stack
189 case $(readlink -f "${type_file}") in
190 *mmc*)
191 cat "${type_file}"
192 ;;
193 *usb*)
194 # Now if it contains 'usb', it is managed through
195 # a USB controller.
196 echo "USB"
197 ;;
Alexis Saverydec5e0f2018-08-15 17:11:51 -0700198 *ufs*)
199 # Check if it is a UFS device.
200 echo "UFS"
201 ;;
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700202 *target*)
203 # Other SCSI devices.
204 # Check if it is an ATA device.
205 vdr="$(cat "/sys/block/${dev}/device/vendor")"
206 if [ "${vdr%% *}" = "ATA" ]; then
207 echo "ATA"
208 else
209 echo "OTHER"
210 fi
211 ;;
212 *)
213 echo "OTHER"
214 esac
215}
216
Gwendal Grignou732af512014-04-07 20:07:29 +0000217# ATA disk have ATA as vendor.
218# They may not contain ata in their device path if behind a SAS
219# controller.
220# Exclude disks with size 0, it means they did not spin up properly.
221list_fixed_ata_disks() {
222 local sd
223 local remo
224 local vdr
225 local size
226
227 for sd in /sys/block/sd*; do
228 if [ ! -r "${sd}/size" ]; then
229 continue
Paul Stewart04f3ef12010-05-27 15:56:42 -0700230 fi
Gwendal Grignou732af512014-04-07 20:07:29 +0000231 size=$(cat "${sd}/size")
232 remo=$(cat "${sd}/removable")
233 vdr=$(cat "${sd}/device/vendor")
234 if [ "${vdr%% *}" = "ATA" -a ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
235 echo "${sd##*/}"
236 fi
Paul Stewart04f3ef12010-05-27 15:56:42 -0700237 done
Gwendal Grignou732af512014-04-07 20:07:29 +0000238}
239
240# We assume we only have eMMC devices, not removable MMC devices.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700241# also, do not consider special hardware partitions on the eMMC, like boot.
Gwendal Grignou732af512014-04-07 20:07:29 +0000242# These devices are built on top of the eMMC sysfs path:
243# /sys/block/mmcblk0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0
244# /sys/block/mmcblk0boot0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot0
245# /sys/block/mmcblk0boot1 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot1
246# /sys/block/mmcblk0rpmb -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0rpmb
247#
248# Their device link points back to mmcblk0, not to the hardware
249# device (mmc0:0001). Therefore there is no type in their device link.
250# (it should be /device/device/type)
251list_fixed_mmc_disks() {
252 local mmc
253 local type_file
254 for mmc in /sys/block/mmcblk*; do
255 type_file="${mmc}/device/type"
256 if [ -r "${type_file}" ]; then
257 if [ "$(cat "${type_file}")" = "MMC" ]; then
258 echo "${mmc##*/}"
259 fi
260 fi
261 done
262}
263
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700264# NVMe device
265# Exclude disks with size 0, it means they did not spin up properly.
266list_fixed_nvme_disks() {
Gwendal Grignoudc0a2072017-07-11 09:57:57 -0700267 local nvme remo size nvme_base
268 local all_nvme=''
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700269
270 for nvme in /sys/block/nvme*; do
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700271 if [ ! -r "${nvme}/size" ]; then
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700272 continue
273 fi
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700274 size=$(cat "${nvme}/size")
275 remo=$(cat "${nvme}/removable")
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700276 if [ ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700277 nvme_base="${nvme##*/}"
278 # Store in all_nvme names of nvme devices, without namespace.
279 # In case of nvme device with several namespaces, we will have
280 # redundancy.
281 all_nvme="${all_nvme} ${nvme_base%n*}"
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700282 fi
283 done
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700284 echo "${all_nvme}" | tr '[:space:]' '\n' | sort -u
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700285}
286
Alexis Saverydec5e0f2018-08-15 17:11:51 -0700287# UFS device
288# Exclude disks with size 0, it means they did not spin up properly.
289list_fixed_ufs_disks() {
290 local sd
291 local remo
292 local size
293 local type
294
295 for sd in /sys/block/sd*; do
296 if [ ! -r "${sd}/size" ]; then
297 continue
298 fi
299 type=$(get_device_type "${sd}")
300 size=$(cat "${sd}/size")
301 remo=$(cat "${sd}/removable")
302 if [ "${type}" = "UFS" -a ${remo:-0} -eq 0 -a ${size:-0} -gt 0 ]; then
303 echo "${sd##*/}"
304 fi
305 done
306}
307
Gwendal Grignou732af512014-04-07 20:07:29 +0000308# Find the drive to install based on the build write_cgpt.sh
309# script. If not found, return ""
310get_fixed_dst_drive() {
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700311 local dev rootdev
312
313 if [ -n "${DEFAULT_ROOTDEV}" ]; then
Gwendal Grignou732af512014-04-07 20:07:29 +0000314 # No " here, the variable may contain wildcards.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700315 for rootdev in ${DEFAULT_ROOTDEV}; do
316 dev="/dev/$(basename "${rootdev}")"
317 if [ -b "${dev}" ]; then
318 break
319 else
320 dev=""
321 fi
322 done
Congbin Guofcaade82018-01-05 15:47:56 -0800323 else
324 dev=""
Gwendal Grignou732af512014-04-07 20:07:29 +0000325 fi
326 echo "${dev}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700327}
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700328
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700329edit_mbr() {
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700330 locate_gpt
Ian Coolidge83e74322017-04-14 18:35:45 +0000331 # TODO(icoolidge): Get this from disk_layout somehow.
332 local PARTITION_NUM_EFI_SYSTEM=12
Steven 'Steve' Kendallbde39b12015-09-30 12:59:02 -0400333 local start_esp=$(partoffset "$1" ${PARTITION_NUM_EFI_SYSTEM})
334 local num_esp_sectors=$(partsize "$1" ${PARTITION_NUM_EFI_SYSTEM})
Gwendal Grignou0788acb2018-06-18 08:54:23 -0700335 maybe_sudo sfdisk -w never -X dos "${1}" <<EOF
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700336unit: sectors
337
338disk1 : start= $start_esp, size= $num_esp_sectors, Id= c, bootable
339disk2 : start= 1, size= 1, Id= ee
340EOF
341}
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700342
343install_hybrid_mbr() {
344 # Creates a hybrid MBR which points the MBR partition 1 to GPT
345 # partition 12 (ESP). This is useful on ARM boards that boot
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700346 # from MBR formatted disks only.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700347 #
348 # Currently, this code path is used principally to install to
349 # SD cards using chromeos-install run from inside the chroot.
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700350 # In that environment, `sfdisk` can be racing with udev, leading
351 # to EBUSY when it calls BLKRRPART for the target disk. We avoid
352 # the conflict by using `udevadm settle`, so that udev goes first.
353 # cf. crbug.com/343681.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700354
355 echo "Creating hybrid MBR"
356 if ! edit_mbr "${1}"; then
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700357 udevadm settle
Gwendal Grignou0788acb2018-06-18 08:54:23 -0700358 maybe_sudo blockdev --rereadpt "${1}"
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700359 fi
360}
Gwendal Grignouacb06352017-02-08 20:30:47 -0800361
362ext4_dir_encryption_supported() {
363 # Can be set in the ebuild.
364 local direncryption_enabled=false
365
366 # Return true if kernel support ext4 directory encryption.
367 ${direncryption_enabled} && \
368 ! LC_LANG=C e4crypt get_policy / | grep -qF \
369 -e "Operation not supported" \
370 -e "Inappropriate ioctl for device"
371}