blob: a27bca2b746a70dfa3a280ea403909d2a8d10a2a [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
Allen Webb034c5d92019-05-31 15:52:16 -070049 local bytes
50 bytes="$(stat -c%s "${path}")"
Sam Hurstc8e17172018-06-29 14:18:07 -070051 local rem=$(( bytes % 512 ))
52 block_size=512
53 sectors=$(( bytes / 512 ))
54 if [ "${rem}" -ne 0 ]; then
55 sectors=$(( sectors + 1 ))
Bill Richardsoneff5b062010-03-30 14:17:34 -070056 fi
Jie Sun1f9d4122010-04-12 17:04:36 -070057 fi
Sam Hurstc8e17172018-06-29 14:18:07 -070058
59 echo $(( sectors * 512 / block_size ))
Bill Richardsoneff5b062010-03-30 14:17:34 -070060}
61
Sam Hurst545e5512018-06-07 11:08:46 -070062# This returns the block size of a file or device in byte
63# Invoke as: subshell
64# Args: FILENAME
65# Return: block size in bytes
66blocksize() {
67 local path="$1"
68 if [ -b "${path}" ]; then
69 local dev="${path##*/}"
70 local sys="/sys/block/${dev}/queue/logical_block_size"
71 if [ -e "${sys}" ]; then
72 cat "${sys}"
73 else
74 local part="${path##*/}"
Allen Webb034c5d92019-05-31 15:52:16 -070075 local block
76 block="$(get_block_dev_from_partition_dev "${path}")"
77 block="${block##*/}"
Sam Hurst545e5512018-06-07 11:08:46 -070078 cat "/sys/block/${block}/${part}/queue/logical_block_size"
79 fi
80 else
81 echo 512
82 fi
83}
84
Bill Richardson7c358a92010-06-11 09:16:03 -070085# Locate the cgpt tool. It should already be installed in the build chroot,
robotboya7684292010-04-21 14:46:00 -070086# but some of these functions may be invoked outside the chroot (by
Bill Richardsoneff5b062010-03-30 14:17:34 -070087# image_to_usb or similar), so we need to find it.
robotboya7684292010-04-21 14:46:00 -070088GPT=""
Yusuke Satod55cea92010-04-21 10:46:59 +090089
robotboya7684292010-04-21 14:46:00 -070090locate_gpt() {
Allen Webb034c5d92019-05-31 15:52:16 -070091 if [ -z "${GPT}" ]; then
Bill Richardsonf67f8442010-12-01 08:27:37 -080092 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
93 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
94 else
Allen Webb034c5d92019-05-31 15:52:16 -070095 GPT="$(command -v cgpt 2>/dev/null)" || /bin/true
96 if [ -z "${GPT}" ]; then
Bill Richardson7c358a92010-06-11 09:16:03 -070097 echo "can't find cgpt tool" 1>&2
robotboya7684292010-04-21 14:46:00 -070098 exit 1
99 fi
100 fi
101 fi
102}
Bill Richardsoneff5b062010-03-30 14:17:34 -0700103
Bill Richardsoneff5b062010-03-30 14:17:34 -0700104# Read GPT table to find the starting location of a specific partition.
105# Invoke as: subshell
106# Args: DEVICE PARTNUM
107# Returns: offset (in sectors) of partition PARTNUM
108partoffset() {
Allen Webb034c5d92019-05-31 15:52:16 -0700109 maybe_sudo "${GPT}" show -b -i "$2" "$1"
Bill Richardsoneff5b062010-03-30 14:17:34 -0700110}
111
112# Read GPT table to find the size of a specific partition.
113# Invoke as: subshell
114# Args: DEVICE PARTNUM
115# Returns: size (in sectors) of partition PARTNUM
116partsize() {
Allen Webb034c5d92019-05-31 15:52:16 -0700117 maybe_sudo "${GPT}" show -s -i "$2" "$1"
Bill Richardsoneff5b062010-03-30 14:17:34 -0700118}
119
Jie Sun1f9d4122010-04-12 17:04:36 -0700120# Extract the whole disk block device from the partition device.
121# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
122# (-> /dev/mmcblk0).
123get_block_dev_from_partition_dev() {
Allen Webb034c5d92019-05-31 15:52:16 -0700124 local partition="$1"
125 if ! (expr match "${partition}" ".*[0-9]$" >/dev/null) ; then
126 echo "Invalid partition name: ${partition}" >&2
Jie Sun1f9d4122010-04-12 17:04:36 -0700127 exit 1
128 fi
Will Drewry056e9c82010-08-06 16:10:59 -0500129 # Removes any trailing digits.
Allen Webb034c5d92019-05-31 15:52:16 -0700130 local block
131 block="$(echo "${partition}" | sed -e 's/[0-9]*$//')"
Jie Sun1f9d4122010-04-12 17:04:36 -0700132 # If needed, strip the trailing 'p'.
Allen Webb034c5d92019-05-31 15:52:16 -0700133 if (expr match "${block}" ".*[0-9]p$" >/dev/null); then
Jie Sun1f9d4122010-04-12 17:04:36 -0700134 echo "${block%p}"
135 else
Allen Webb034c5d92019-05-31 15:52:16 -0700136 echo "${block}"
Jie Sun1f9d4122010-04-12 17:04:36 -0700137 fi
138}
139
140# Extract the partition number from the partition device.
141# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
142get_partition_number() {
Allen Webb034c5d92019-05-31 15:52:16 -0700143 local partition="$1"
144 if ! (expr match "${partition}" ".*[0-9]$" >/dev/null) ; then
145 echo "Invalid partition name: ${partition}" >&2
Jie Sun1f9d4122010-04-12 17:04:36 -0700146 exit 1
147 fi
148 # Extract the last digit.
Allen Webb034c5d92019-05-31 15:52:16 -0700149 echo "${partition}" | sed -e 's/^.*\([0-9]\)$/\1/'
Jie Sun1f9d4122010-04-12 17:04:36 -0700150}
151
152# Construct a partition device name from a whole disk block device and a
153# partition number.
154# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
155# (-> /dev/mmcblk0p2).
156make_partition_dev() {
Allen Webb034c5d92019-05-31 15:52:16 -0700157 local block="$1"
158 local num="$2"
Jie Sun1f9d4122010-04-12 17:04:36 -0700159 # If the disk block device ends with a number, we add a 'p' before the
160 # partition number.
Allen Webb034c5d92019-05-31 15:52:16 -0700161 if (expr match "${block}" ".*[0-9]$" >/dev/null) ; then
Jie Sun1f9d4122010-04-12 17:04:36 -0700162 echo "${block}p${num}"
163 else
164 echo "${block}${num}"
165 fi
166}
167
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700168# Return the type of device.
169#
170# The type can be:
171# MMC, SD for device managed by the MMC stack
172# ATA for ATA disk
Deepti Patildf2d2692016-03-04 15:24:58 +0530173# NVME for NVMe device
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700174# OTHER for other devices.
175get_device_type() {
Allen Webb034c5d92019-05-31 15:52:16 -0700176 local dev
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700177 local vdr
178 local type_file
Deepti Patildf2d2692016-03-04 15:24:58 +0530179 # True device path of a NVMe device is just a simple PCI device.
180 # (there are no other buses),
181 # Use the device name to identify the type precisely.
Allen Webb034c5d92019-05-31 15:52:16 -0700182 dev="$(basename "$1")"
Deepti Patildf2d2692016-03-04 15:24:58 +0530183 case "${dev}" in
184 nvme*)
185 echo "NVME"
186 return
187 ;;
188 esac
189
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700190 type_file="/sys/block/${dev}/device/type"
191 # To detect device managed by the MMC stack
192 case $(readlink -f "${type_file}") in
193 *mmc*)
194 cat "${type_file}"
195 ;;
196 *usb*)
197 # Now if it contains 'usb', it is managed through
198 # a USB controller.
199 echo "USB"
200 ;;
Alexis Saverydec5e0f2018-08-15 17:11:51 -0700201 *ufs*)
202 # Check if it is a UFS device.
203 echo "UFS"
204 ;;
Gwendal Grignou20f0ca72014-03-13 16:14:43 -0700205 *target*)
206 # Other SCSI devices.
207 # Check if it is an ATA device.
208 vdr="$(cat "/sys/block/${dev}/device/vendor")"
209 if [ "${vdr%% *}" = "ATA" ]; then
210 echo "ATA"
211 else
212 echo "OTHER"
213 fi
214 ;;
215 *)
216 echo "OTHER"
217 esac
218}
219
Gwendal Grignou732af512014-04-07 20:07:29 +0000220# ATA disk have ATA as vendor.
221# They may not contain ata in their device path if behind a SAS
222# controller.
223# Exclude disks with size 0, it means they did not spin up properly.
224list_fixed_ata_disks() {
225 local sd
226 local remo
227 local vdr
228 local size
229
230 for sd in /sys/block/sd*; do
231 if [ ! -r "${sd}/size" ]; then
232 continue
Paul Stewart04f3ef12010-05-27 15:56:42 -0700233 fi
Allen Webb034c5d92019-05-31 15:52:16 -0700234 size="$(cat "${sd}/size")"
235 remo="$(cat "${sd}/removable")"
236 vdr="$(cat "${sd}/device/vendor")"
237 if [ "${vdr%% *}" = "ATA" ] && [ "${remo:-0}" -eq 0 ] && \
238 [ "${size:-0}" -gt 0 ];
239 then
Gwendal Grignou732af512014-04-07 20:07:29 +0000240 echo "${sd##*/}"
241 fi
Paul Stewart04f3ef12010-05-27 15:56:42 -0700242 done
Gwendal Grignou732af512014-04-07 20:07:29 +0000243}
244
245# We assume we only have eMMC devices, not removable MMC devices.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700246# also, do not consider special hardware partitions on the eMMC, like boot.
Gwendal Grignou732af512014-04-07 20:07:29 +0000247# These devices are built on top of the eMMC sysfs path:
248# /sys/block/mmcblk0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0
249# /sys/block/mmcblk0boot0 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot0
250# /sys/block/mmcblk0boot1 -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0boot1
251# /sys/block/mmcblk0rpmb -> .../mmc_host/.../mmc0:0001/.../mmcblk0/mmcblk0rpmb
252#
253# Their device link points back to mmcblk0, not to the hardware
254# device (mmc0:0001). Therefore there is no type in their device link.
255# (it should be /device/device/type)
256list_fixed_mmc_disks() {
257 local mmc
258 local type_file
259 for mmc in /sys/block/mmcblk*; do
260 type_file="${mmc}/device/type"
261 if [ -r "${type_file}" ]; then
262 if [ "$(cat "${type_file}")" = "MMC" ]; then
263 echo "${mmc##*/}"
264 fi
265 fi
266 done
267}
268
aysusayine3eb9872019-08-07 12:31:49 +0200269# NVMe block devices
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700270# Exclude disks with size 0, it means they did not spin up properly.
aysusayine3eb9872019-08-07 12:31:49 +0200271list_fixed_nvme_nss() {
272 local nvme remo size
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700273
274 for nvme in /sys/block/nvme*; do
Gwendal Grignou040ab8c2017-04-27 18:24:35 -0700275 if [ ! -r "${nvme}/size" ]; then
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700276 continue
277 fi
Allen Webb034c5d92019-05-31 15:52:16 -0700278 size="$(cat "${nvme}/size")"
279 remo="$(cat "${nvme}/removable")"
280 if [ "${remo:-0}" -eq 0 ] && [ "${size:-0}" -gt 0 ]; then
aysusayine3eb9872019-08-07 12:31:49 +0200281 echo "${nvme##*/}"
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700282 fi
283 done
aysusayine3eb9872019-08-07 12:31:49 +0200284}
285
286# NVMe character devices
287# Exclude disks with size 0, it means they did not spin up properly.
288list_fixed_nvme_disks() {
289 local nvme_dev
290
291 for nvme_dev in $(list_fixed_nvme_nss); do
292 echo "${nvme_dev%n*}"
293 done | sort -u
Gwendal Grignou66cc8352016-10-14 08:48:57 -0700294}
295
Alexis Saverydec5e0f2018-08-15 17:11:51 -0700296# UFS device
297# Exclude disks with size 0, it means they did not spin up properly.
298list_fixed_ufs_disks() {
299 local sd
300 local remo
301 local size
302 local type
303
304 for sd in /sys/block/sd*; do
305 if [ ! -r "${sd}/size" ]; then
306 continue
307 fi
Allen Webb034c5d92019-05-31 15:52:16 -0700308 type="$(get_device_type "${sd}")"
309 size="$(cat "${sd}/size")"
310 remo="$(cat "${sd}/removable")"
311 if [ "${type}" = "UFS" ] && [ "${remo:-0}" -eq 0 ] && \
312 [ "${size:-0}" -gt 0 ]; then
Alexis Saverydec5e0f2018-08-15 17:11:51 -0700313 echo "${sd##*/}"
314 fi
315 done
316}
317
Gwendal Grignou732af512014-04-07 20:07:29 +0000318# Find the drive to install based on the build write_cgpt.sh
319# script. If not found, return ""
320get_fixed_dst_drive() {
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700321 local dev rootdev
322
323 if [ -n "${DEFAULT_ROOTDEV}" ]; then
Gwendal Grignou732af512014-04-07 20:07:29 +0000324 # No " here, the variable may contain wildcards.
Gwendal Grignou6562fe72017-06-06 09:11:01 -0700325 for rootdev in ${DEFAULT_ROOTDEV}; do
326 dev="/dev/$(basename "${rootdev}")"
327 if [ -b "${dev}" ]; then
328 break
329 else
330 dev=""
331 fi
332 done
Congbin Guofcaade82018-01-05 15:47:56 -0800333 else
334 dev=""
Gwendal Grignou732af512014-04-07 20:07:29 +0000335 fi
336 echo "${dev}"
Paul Stewart04f3ef12010-05-27 15:56:42 -0700337}
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700338
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700339edit_mbr() {
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700340 locate_gpt
Ian Coolidge83e74322017-04-14 18:35:45 +0000341 # TODO(icoolidge): Get this from disk_layout somehow.
342 local PARTITION_NUM_EFI_SYSTEM=12
Allen Webb034c5d92019-05-31 15:52:16 -0700343 local start_esp
344 local num_esp_sectors
345
346 start_esp="$(partoffset "$1" "${PARTITION_NUM_EFI_SYSTEM}")"
347 num_esp_sectors="$(partsize "$1" "${PARTITION_NUM_EFI_SYSTEM}")"
Gwendal Grignou0788acb2018-06-18 08:54:23 -0700348 maybe_sudo sfdisk -w never -X dos "${1}" <<EOF
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700349unit: sectors
350
Allen Webb034c5d92019-05-31 15:52:16 -0700351disk1 : start= ${start_esp}, size= ${num_esp_sectors}, Id= c, bootable
Liam McLoughlin2dd21d62012-07-09 17:45:06 -0700352disk2 : start= 1, size= 1, Id= ee
353EOF
354}
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700355
356install_hybrid_mbr() {
357 # Creates a hybrid MBR which points the MBR partition 1 to GPT
358 # partition 12 (ESP). This is useful on ARM boards that boot
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700359 # from MBR formatted disks only.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700360 #
361 # Currently, this code path is used principally to install to
362 # SD cards using chromeos-install run from inside the chroot.
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700363 # In that environment, `sfdisk` can be racing with udev, leading
364 # to EBUSY when it calls BLKRRPART for the target disk. We avoid
365 # the conflict by using `udevadm settle`, so that udev goes first.
366 # cf. crbug.com/343681.
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700367
368 echo "Creating hybrid MBR"
369 if ! edit_mbr "${1}"; then
J. Richard Barnette2db77d42015-03-19 17:19:15 -0700370 udevadm settle
Gwendal Grignou0788acb2018-06-18 08:54:23 -0700371 maybe_sudo blockdev --rereadpt "${1}"
J. Richard Barnette40ce8a02015-03-18 14:59:26 -0700372 fi
373}
Gwendal Grignouacb06352017-02-08 20:30:47 -0800374
375ext4_dir_encryption_supported() {
376 # Can be set in the ebuild.
377 local direncryption_enabled=false
378
379 # Return true if kernel support ext4 directory encryption.
Allen Webb034c5d92019-05-31 15:52:16 -0700380 "${direncryption_enabled}" && \
Gwendal Grignouacb06352017-02-08 20:30:47 -0800381 ! LC_LANG=C e4crypt get_policy / | grep -qF \
382 -e "Operation not supported" \
383 -e "Inappropriate ioctl for device"
384}